Reduce re-review friction for GitHub-verified developer profiles, add Publisher URL verification - #169
Conversation
… Publisher URL verification - upsertOwn no longer clears a profile's approval on every edit when it's currently GitHub org/user-verified, since that's an independently-computed identity signal strong enough to skip re-queuing for manual review. - New github_url_verified signal: cross-checks Publisher URL against GitHub's own on-file website for the org/user, computed at creation and re-checked via the owner's manual "Re-verify" action (POST /developers/me/reverify ?check_url=true) — never by the opportunistic per-login check, which stays GitHub-API-free by design. Claude-Session: https://claude.ai/code/session_014dzTSwUW78Qipx7sYH2dgD
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
api | b068e92 | Commit Preview URL Branch Preview URL |
Jul 30 2026, 04:35 PM |
There was a problem hiding this comment.
All reported issues were addressed across 10 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
…everify edge cases - upsertOwn now invalidates GitHub verification (and approval) when a profile's type changes, and clears github_url_verified when the Publisher URL changes — previously both were left stale after such edits. - reverifyOwn's manual URL re-check now validates the returned GitHub entity's type against the profile's own type, preserves an existing github_url_verified on a transient lookup failure instead of clearing it, and clears github_url_verified whenever identity no longer matches even without ?check_url (cheap — no extra API call). - ReverifyQuerySchema no longer uses z.coerce.boolean() for check_url, which coerced the string "false" to true. - The github_url_verified CHECK constraint now enforces "= 1" (only ever 1 or NULL) rather than "IN (0, 1)", matching its documented contract. - urlMatchesGithubBlog() now preserves port in the host comparison and only lowercases the host, not the path (URL paths are case-sensitive). Claude-Session: https://claude.ai/code/session_014dzTSwUW78Qipx7sYH2dgD
|
Went through all 10 findings from cubic — 9 were valid and fixed in d80a6ed. |
…budget POST /developers/me/reverify?check_url=true now returns 429/RATE_LIMITED if called again within 60 seconds by the same caller, using CACHE_KV as a per-user cooldown. The opportunistic per-login reverify (no check_url) is unaffected since it never makes a GitHub API call. Claude-Session: https://claude.ai/code/session_014dzTSwUW78Qipx7sYH2dgD
|
Two more updates in 2d7fa41:
|
There was a problem hiding this comment.
All reported issues were addressed across 9 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…ype-mismatch guards - Rate limiting moved from a KV get-then-put (racy — two concurrent ?check_url=true requests could both pass) to an atomic conditional UPDATE on the developer's own row, gated by a new url_check_cooldown_until column. Reuses the row already being read/written in this function instead of adding a new store. - reverifyOwn's final write now also re-asserts the Publisher URL hasn't changed since it was checked, same pattern as the existing ownership re-assertion — otherwise a concurrent edit could let a stale URL comparison get persisted as if it described the new URL. - When a manual URL re-check finds GitHub's current entity type no longer matches the profile's own type, it now downgrades github_org_verified too, not just github_url_verified — matchesClaimant() alone never queries GitHub's actual current type, so this discrepancy is the only place that catches it post-creation. Claude-Session: https://claude.ai/code/session_014dzTSwUW78Qipx7sYH2dgD
|
All 3 new findings addressed in 120453c — all were valid:
|
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
acceptTransfer and approveClaim now both clear it — left unchanged, a new owner would inherit whatever was left of the previous owner's check_url cooldown window, since the column is keyed by whoever currently owns the row. Claude-Session: https://claude.ai/code/session_014dzTSwUW78Qipx7sYH2dgD
|
Fixed in a30f515 — valid. There are actually two ownership-transfer write paths, not one —
|
…identity, not the new owner's acceptTransfer now resets github_org_verified/github_url_verified/ github_verification_note/github_verified_at to null, same as it already resets approval. Unlike approveClaim (which carries over a claim-time verification computed against the specific claimant), a transfer has no equivalent verification step to carry over — it's a bare ownership handoff, so this can only fall back to unverified until the new owner re-verifies. Claude-Session: https://claude.ai/code/session_014dzTSwUW78Qipx7sYH2dgD
|
Done in b068e92. `acceptTransfer` now also clears `github_org_verified`/`github_url_verified`/`github_verification_note`/`github_verified_at` on transfer, same as it already clears approval — a bare ownership handoff has no verification step of its own to carry over (unlike `approveClaim`, which carries over the claim's own verification, run specifically against the claimant), so this falls back to unverified until the new owner re-verifies. |
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Requires human review: Includes two database migrations (schema changes) and modifies approval behavior for GitHub-verified profiles, requiring operational judgment on trust and migration risk.
Re-trigger cubic
Summary
upsertOwnno longer clears a developer profile'sapprovedflag on every edit when the profile is currently GitHub org/user-verified — that identity check is an independently-computed signal strong enough to skip re-queuing for manual moderator review on every subsequent edit.github_url_verifiedsignal: cross-checks the profile's Publisher URL against GitHub's own on-file website for that org/user (same API call as the existing entity-type check, no extra request). Computed at profile creation, and re-checked via the owner's manual "Re-verify" action (POST /developers/me/reverify?check_url=true) — deliberately never by the opportunistic per-login re-check, which stays GitHub-API-free by design.github_url_verifiedcolumn (migration0016), threaded throughinterfaces.ts(moderator/owner-only, excluded fromPublicDeveloperSchemasame as the other GitHub verification fields).