Skip to content

Reduce re-review friction for GitHub-verified developer profiles, add Publisher URL verification - #169

Merged
admdly merged 6 commits into
mainfrom
feat/developer-github-verification-enhancements
Jul 30, 2026
Merged

Reduce re-review friction for GitHub-verified developer profiles, add Publisher URL verification#169
admdly merged 6 commits into
mainfrom
feat/developer-github-verification-enhancements

Conversation

@admdly

@admdly admdly commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • upsertOwn no longer clears a developer profile's approved flag 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.
  • New github_url_verified signal: 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.
  • New github_url_verified column (migration 0016), threaded through interfaces.ts (moderator/owner-only, excluded from PublicDeveloperSchema same as the other GitHub verification fields).

… 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
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 30, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

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

@admdly admdly self-assigned this Jul 30, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 10 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/services/extensions/v2/developers-database.ts Outdated
Comment thread src/services/extensions/v2/developers-database.ts Outdated
Comment thread src/services/extensions/v2/db/schema.ts Outdated
Comment thread src/services/extensions/v2/interfaces.ts Outdated
Comment thread src/services/extensions/v2/index.ts
Comment thread src/services/extensions/v2/github-verification.ts
Comment thread src/services/extensions/v2/github-verification.ts Outdated
Comment thread src/services/extensions/v2/github-verification.ts Outdated
Comment thread src/services/extensions/v2/developers-database.ts Outdated
Comment thread src/services/extensions/v2/developers-database.ts Outdated
…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
@admdly

admdly commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

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
@admdly

admdly commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Two more updates in 2d7fa41:

  1. The transient-GitHub-lookup-failure finding was already fixed in d80a6ed — the thread wasn't auto-marked because the fix lives in the caller (reverifyOwn in developers-database.ts), not the exact line cubic flagged (github-verification.ts:28). Verified via the passing test "preserves an existing Publisher URL verification when the GitHub lookup fails".

  2. Rate limiting is now implemented for the one deferred finding: POST /developers/me/reverify?check_url=true returns 429/RATE_LIMITED if the same caller hits it again within 60 seconds, using the existing CACHE_KV binding as a per-user cooldown (no new infrastructure). The opportunistic per-login reverify is unaffected — it never sets check_url, so it never touches this path. Added 4 tests: blocks a rapid second call with zero extra GitHub API calls, doesn't rate-limit the no-check_url path, and scopes the cooldown per-caller (not global).

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/services/extensions/v2/developers-database.ts
Comment thread src/services/extensions/v2/index.ts Outdated
Comment thread src/services/extensions/v2/developers-database.ts Outdated
…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
@admdly

admdly commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

All 3 new findings addressed in 120453c — all were valid:

  1. Stale URL on concurrent edit (developers-database.ts) — reverifyOwn's final write now re-asserts the Publisher URL hasn't changed since it was checked (same WHERE-clause-guard pattern already used for the ownership race just above it). A concurrent Publisher URL edit now surfaces as 409 CONFLICT instead of silently persisting a URL verification computed against the old URL. Covered by a test using the same SQL-hook race-simulation technique as the existing ownership-race test.

  2. Non-atomic rate limit (index.ts) — you were right that a KV get-then-put isn't atomic. Replaced it entirely: the cooldown is now a conditional UPDATE ... WHERE url_check_cooldown_until IS NULL OR < CURRENT_TIMESTAMP directly on the developer's own row (new column, migration 0017), reusing the row already being touched in this function instead of standing up new infrastructure. This is a single atomic SQL statement, so two concurrent requests can't both win. Verified with a real concurrency test (Promise.all of two simultaneous requests) — passes.

  3. Type-mismatch only cleared the URL signal, not identity (developers-database.ts) — when a manual re-check discovers GitHub's current entity type no longer matches the profile's type, github_org_verified now gets downgraded too, not just github_url_verified. matchesClaimant() never queries GitHub's actual current type on its own, so this was the only place post-creation that could catch the discrepancy at all.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/services/extensions/v2/db/schema.ts
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
@admdly

admdly commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in a30f515 — valid. url_check_cooldown_until lives on the developers row, so it's implicitly keyed by whoever currently owns it; without a reset, a new owner would inherit whatever was left of the previous owner's cooldown window.

There are actually two ownership-transfer write paths, not one — acceptTransfer (raw SQL via the direct transfer-link flow) and approveClaim (the claims-queue flow). Reset it in both:

  • acceptTransfer is the one that's actually reachable today (a real previous owner with a real prior cooldown).
  • approveClaim only ever targets never-owned profiles, so there's no prior owner's cooldown to inherit in practice — reset there too anyway, for the same reason, as defense-in-depth rather than something with a reachable test case.

…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
@admdly

admdly commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

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.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@admdly
admdly merged commit 90aa70d into main Jul 30, 2026
9 checks passed
@admdly
admdly deleted the feat/developer-github-verification-enhancements branch July 30, 2026 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant