Skip to content

feat: crowdsourced verification tab with flashcard task mode#116

Merged
AlorSahoo merged 8 commits into
mainfrom
alor/crowdsourcedverification
Jun 19, 2026
Merged

feat: crowdsourced verification tab with flashcard task mode#116
AlorSahoo merged 8 commits into
mainfrom
alor/crowdsourcedverification

Conversation

@AlorSahoo

@AlorSahoo AlorSahoo commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Two modes:

  • Verify tab (default): flashcard flow — one (entity, field, value) at
    a time, prioritised by least-verified + most-connected. Confirm / Flag /
    Skip before seeing the next card. Prevents selection bias toward popular
    entities. Votes write to field_feedback, the same table the map reads for
    vote badges.
  • Browse tab: full-entity review UI — scan all fields, flag corrections
    with error type + corrected value, mark complete with timer.

Also: onboarding popup on first load, fixed field_feedback unique constraint
(dropped vote from key so each user has one authoritative vote per field),
added voter-leading indexes for rate-limit queries, dropped legacy NOT NULL
on reviewer_key_id left over from an older branch schema.

Preview: https://drive.google.com/file/d/19EbU0smwttOQi_Cm8dbsKenKU9-dZyx7/view?usp=sharing

Adds /verify page with two modes:
- Task mode: serves one (entity, field, value) card at a time, prioritised
  by least-verified first, requiring Confirm / Flag / Skip before advancing.
  Votes write to field_feedback (same table the map reads for vote badges).
- Browse mode: existing full-entity review UI preserved behind a tab.

DB: ALTER TABLE verification_correction/review to add voter_id and drop
NOT NULL on legacy reviewer_key_id; fix GIN index ordering in migrate.js.

ESLint: add dev-server.js to Node globals block so process/console.log
are recognised.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Neon preview branch ready

branch: preview/pr-116
host:   

The full connection string is available to workflow steps on this PR
via the db_url output of the Neon create-branch action. It is NOT
printed here because the output includes the password, and posting it
as a PR comment would leak that credential in email notifications.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 13, 2026

Copy link
Copy Markdown

Deploying mapping-ai with  Cloudflare Pages  Cloudflare Pages

Latest commit: 66fa12f
Status: ✅  Deploy successful!
Preview URL: https://809d139b.mapping-ai.pages.dev
Branch Preview URL: https://alor-crowdsourcedverificatio.mapping-ai.pages.dev

View logs

AlorSahoo and others added 3 commits June 12, 2026 18:50
- Add welcome popup on first /verify visit (sessionStorage-gated)
- Fix field_feedback unique constraint: drop vote from key so each
  user has one vote per field; upsert instead of silently ignoring
- Add voter_id-leading indexes for rate-limit and already_voted queries
- Remove dead field_notes query from entity API
- Extract submitReview helper, fix optimistic delete rollback,
  surface queue 1load errors with retry
- Expand map welcome popup tips inline (remove collapsible)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@AlorSahoo AlorSahoo changed the title [IN PROGRESS] feat: crowdsourced verification tab with flashcard task mode feat: crowdsourced verification tab with flashcard task mode Jun 13, 2026
@AlorSahoo AlorSahoo marked this pull request as ready for review June 13, 2026 02:29
…polish

- field-feedback.ts: ON CONFLICT now targets (entity_id, field_name,
  voter_id) and updates the vote in place, matching the migration that
  dropped `vote` from the unique key. Without this the map's field-vote
  arrows 500 once a voter changes or repeats a vote.
- dev-server task_vote: same DO UPDATE semantics so local mirrors prod.
- verify: gate the onboarding popup behind a localStorage flag (first
  load only), and sanitize entity.notes_html with DOMPurify before
  dangerouslySetInnerHTML, matching every other render site.
@anushreechaudhuri

Copy link
Copy Markdown
Collaborator

Reviewed and tested this end to end: local quality gates plus the Cloudflare preview driven with a browser. Really nice feature, the flashcard flow is smooth and the Browse review UI is polished. I pushed a few fixes directly to the branch (commit d30dc33), details below.

Fixed on the branch

  1. Map field-voting broke after the migration (the one real blocker). The migration drops vote from the field_feedback unique key, but functions/api/field-feedback.ts (the map's vote endpoint, untouched in this PR) still used ON CONFLICT (entity_id, field_name, voter_id, vote). On the preview that returned HTTP 500 the moment a voter changed or repeated a vote on a field, and on a fully migrated production DB even the first vote would 500. I switched it to ON CONFLICT (entity_id, field_name, voter_id) DO UPDATE SET vote = EXCLUDED.vote and made the remove branch delete by (entity, field, voter). Re-tested on the rebuilt preview: confirm, change-vote, repeat, and remove all return 200.

  2. dev/prod vote divergence. dev-server.js task_vote used ON CONFLICT DO NOTHING while prod uses DO UPDATE, so changing a vote behaved differently locally. Aligned it to match prod.

  3. Unsanitized HTML render. EntityReview injected entity.notes_html via dangerouslySetInnerHTML with no sanitization, while every other render site (map engine, sidebar, note modal) runs it through DOMPurify first. Added DOMPurify here too. It is gated by admin approval today, but worth closing the gap.

  4. Onboarding popup. It showed on every load rather than first load. Gated it behind a verifyWelcomeSeen localStorage flag.

All four are verified on the rebuilt preview.

Worth considering before merge (non-blocking)

  • Ballot-stuffing surface. Vote identity is a client-controlled random UUID (X-Voter-Id) plus IP, so clearing localStorage or rotating the header yields a fresh identity and sidesteps both the one-vote-per-field constraint and the per-voter rate limits. This matches the existing field-feedback design, but it matters more for a vote-driven verification feature. An IP-leading secondary cap would harden it.
  • Duplicate corrections. Flagging the same field repeatedly stacks duplicate rows in verification_correction (bounded only by the 500/hr limit). A dedup or upsert per (entity, field, voter) would keep that table clean.
  • Lint scope. pnpm run lint covers src/, api/, scripts/ only, so verify.ts and the other Pages Functions are never linted. Might be worth extending.
  • Nav vs robots. /verify is now in the main nav while verify.html is noindex,nofollow. Intentional to expose it already?

Everything else checks out: typecheck, lint, format, 120 tests, and the production build are all green, and the flashcard and Browse flows work against the preview DB.

Brings the branch up to date with main: WelcomeOverlay NPR Marketplace
link and the claude-sonnet-4-6 enrichment-script migration.
The flashcard VerifyTask only handled free-text and single-select for
the corrected value, so multi-select fields (threat models, funding
model, evidence sources) fell through to a free-text box. Browse mode's
CorrectionForm shows the allowed options for these. Add the same
multi-select control to the flashcard so both surfaces match.
@anushreechaudhuri

Copy link
Copy Markdown
Collaborator

Two follow-ups pushed:

  • Merged current main into the branch (it was 2 commits behind, branched from Fix methodology page hash scroll #115). This pulls in the updated WelcomeOverlay (the NPR Marketplace link) and the claude-sonnet-4-6 enrichment-script migration. The merge was clean with no conflicts. The branch preview was showing the older welcome banner because of this.
  • Flashcard correction parity. The flashcard (VerifyTask) only handled free-text and single-select for the corrected value, so multi-select fields (threat models, funding model, evidence sources) fell through to a plain text box, while Browse mode's CorrectionForm shows the real options. Added the same multi-select control to the flashcard so both surfaces match. Verified on the preview: flagging a Funding Model card now lists Grants / Contracts / VC / etc.

Both are green on typecheck, lint, format, and build, and verified on the rebuilt preview.

@AlorSahoo

Copy link
Copy Markdown
Collaborator Author

(anushree confirmed its ready for merge, so merging in!)

@AlorSahoo AlorSahoo merged commit 34fc442 into main Jun 19, 2026
3 checks passed
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.

2 participants