Skip to content

feat(identity): separate opt-in for reviewer / juror / expert pools (issue #107)#115

Open
vrkothekar wants to merge 5 commits into
mainfrom
feat/issue-107-separate-role-consents
Open

feat(identity): separate opt-in for reviewer / juror / expert pools (issue #107)#115
vrkothekar wants to merge 5 commits into
mainfrom
feat/issue-107-separate-role-consents

Conversation

@vrkothekar

Copy link
Copy Markdown
Collaborator

Summary

Closes #107. Splits the single reviewer_consent toggle into three independent opt-in fields so identities can choose adjudication roles separately:

  • reviewer_consent — pre-scan reviewer (1 reviewer per flagged content, 48 h async)
  • juror_consent — Stage-2 jury panel (7-seat commit-reveal, time-boxed)
  • expert_consent — Stage-3 expert appeal panel (highest score bar, highest accountability)

Previously, opting into any adjudication role opted you into all three. This caused reviewers to be drafted onto jury panels they hadn't consented to, and experts to be pulled from a pool that included identities who only wanted to be reviewers.

Changes

Protocol / schema

  • UPDATE_PROFILE schema: added juror_consent and expert_consent as sparse-update fields; reviewer_consent retained for back-compat (existing opted-in identities remain eligible via fallback in jury.js and reviewer-selection.js)
  • dag.js / knex-adapter.js: new columns wired through _canonIdentity, saveIdentity, _hydrate
  • jury.js: selectJury now filters on juror_consent (fallback to reviewer_consent for pre-split identities); selectExperts filters on expert_consent (same fallback)
  • genesis.js / protocol-constants.js: updated genesis defaults and constant accessors

Routes / services

  • New convenience endpoints: POST /v1/identity/:tipId/become-juror and POST /v1/identity/:tipId/become-expert
  • Organization identities are hard-gated from all three adjudication roles

Frontend

  • settings.html: three independent toggle switches replacing the single "Become a reviewer" toggle; each signs its own UPDATE_PROFILE tx

Timestamp discipline

  • Fixed Date.now() usage in consensus/index.js fallback timer → nowMs() from shared/time (enforced by timestamp-discipline.test.js)

Dev tooling

  • scripts/inject-prescan-review.js: fixed to backdate prescan_completed_at (trigger anchor) not just registered_at; added --ignore-empty-pool for Pass-3 fallback testing
  • scripts/seed-jurors.js: DEV-ONLY — registers temp-user key files as juror-eligible identities (mocked ZK proof, requires ZK_SKIP_VERIFY=true)
  • scripts/check-nodes.sh: one-shot cluster health check (state-root agreement, halt status, peer connectivity)

Tests

  • update-profile.test.js: juror/expert consent fields accepted and rejected correctly
  • jury-consent.test.js: selectJury / selectExperts filter by new fields; back-compat fallback for pre-split identities
  • profile-service-reviewer.test.js: becomeJuror / becomeExpert convenience methods
  • dispute-stake-economy.test.js, reviewer-payment.test.js: scoring path coverage

Local test plan (verified)

  • Settings page shows three independent toggles; each signs its own tx
  • POST /v1/identity/:tipId/become-reviewer / become-juror / become-expert all accept and reject correctly
  • Org identity blocked from all three roles (400 organization_ineligible)
  • Pre-scan reviewer assigned via Pass-3 cascade (score ≥ 500) after opt-in
  • Reviewer confirmed flag → creator disputed → 7-seat jury summoned from juror_consent=true pool → UPHELD verdict via drive-jury.js
  • timestamp-discipline regression test passes (0 Date.now() outside shared/time)

Adds a banner near the top of the README pointing to the published
Whitepaper at theailab.org/whitepaper, and updates the Links table
with the canonical Whitepaper URL, the PDF download URL, and the
errata channel. Also corrects the Protocol Spec link to v5.0.

The Whitepaper is the canonical public specification of the TIP
Protocol. The Protocol Spec (CTID v5.0) remains the technical
reference for endpoint contracts and message formats.

License: Whitepaper is CC BY 4.0. Implementations remain under
TIPCL-1.0 with conversion to Apache 2.0 on Jan 1, 2031.
…inks table

The TIP Protocol Whitepaper, Version 1.0 is now permanently archived
on Zenodo (operated by CERN) with a citable DOI. This README update
surfaces the DOI as a discoverable badge at the top of the page,
adds the author's ORCID iD alongside the Wikidata QID, and adds
three rows to the Links table for the Version DOI, the Concept
DOI, and the Zenodo record URL.

The full citation in the README banner now uses the canonical
Zenodo title ("Trust Identity Protocol (TIP): An Open Standard for
Verified Human Identity and Content Provenance on the Internet")
and ends with the DOI URL, so anyone clicking the citation can
resolve to the permanent record.

The DOI badge surfaces in the GitHub repository preview and in any
README mirror.
@vrkothekar vrkothekar requested a review from t-bhendarkar June 17, 2026 09:49
…ORUM refund + idle-verdict fallback

Fixes Issue #106. Three scoring bugs + one infrastructure stall:

Bug 1 — REVIEWER_WRONG_DISMISS_CLAWBACK not fired at Stage-2 UPHELD
When a jury upheld a dispute after the prescan reviewer dismissed the content,
the reviewer's +5 correct-dismiss bonus was never reversed. Added clawback
(delta = reviewer_wrong_dismiss_clawback = -5) in jury.js after the
ADJUDICATION_RESULT tx is built, guarded by !escalatedReview to keep it
mutually exclusive from the CONFIRM-bonus path.
Stage-3 overturn (UPHELD→DISMISSED) reverses the clawback (+5 again).
NO_QUORUM→Stage-3 UPHELD fires a distinct clawback with reason suffix _no_quorum.

Bug 2 — reviewer.min_score was 800, should be 600
genesis.js: min_score 800 → 600; protocol-constants.js + python genesis.py updated.
Re-signed genesis (resign-genesis.js) to keep GENESIS_TX_SIGNATURE valid.

Bug 3 — terminal NO_QUORUM gave disputer no stake refund
When canEscalate=false and Stage-3 is unavailable, jury.js now pushes a
SCORE_UPDATE of delta=+DISPUTE.DISPUTER_STAKE for the disputer before
returning the NO_QUORUM terminal verdict.

Infrastructure — verdict trigger stalls on idle clusters
Bullshark guards onOrderedTxs with `if (orderedTxs.length > 0)`, so
checkPending is never called when there's no mempool traffic. Added a 3-second
setInterval fallback in consensus/index.js that calls checkPending(Date.now(),
currentRound()) when verdictTrigger.size() > 0. Safe: existing leader-gate
(round-modulo) and ADJUDICATION_RESULT first-wins idempotency prevent double-
fire. Cleared in stop().

Tests: 57 new tests across dispute-stake-economy.test.js (+137 lines) and
reviewer-payment.test.js (+342 lines) covering all 5 verdict paths. 197/209
scoring tests pass (12 pre-existing skips, no regressions).
Live-tested on 5-node Docker cluster: reviewer 951→956→951 (net 0). ✓
…issue #107)

Splits the single `reviewer_consent` field into three independent
consent fields — `reviewer_consent` (pre-scan review), `juror_consent`
(Stage-2 jury), and `expert_consent` (Stage-3 expert panel) — so users
can opt into any combination of adjudication roles.

Back-compat: new columns are DEFAULT NULL. Read paths in
`_parseIdentityRow` (SQLite) and `_hydrate` (knex-adapter) fall back to
`reviewer_consent` for pre-migration rows, preserving existing opt-ins
without a re-save. Jury.js gates use the same `?? reviewer_consent`
pattern. `_canonIdentity` applies identical fallback so all 5 nodes
produce the same Merkle root.

Also fixes a `Date.now()` call in `consensus/index.js` (introduced in
the #106 idle-verdict-fallback timer) that violated the
timestamp-discipline rule; replaced with `nowMs()` from shared/time.

Changes:
- schemas/update-profile.js: add juror_consent + expert_consent to
  KNOWN_FIELDS; extend org gate to cover all three consent fields
- dag.js: _canonIdentity, SQLite schema, saveIdentity, _parseIdentityRow
- knex-adapter.js: createTable, saveIdentity, _hydrate back-compat
- jury.js: selectJury → juror_consent gate; selectExperts → expert_consent
- profile-service.js: becomeJuror/stopJuror/becomeExpert/stopExpert helpers
- routes/identity.js: /become-juror, /stop-juror, /become-expert, /stop-expert
- Tests: jury-consent.test.js (5 new cases), profile-service-reviewer.test.js
  (6 new cases), update-profile.test.js (4 new integration cases)
- consensus/index.js: Date.now() → nowMs() fix
…ripts

- inject-prescan-review.js: backdate prescan_completed_at (not just
  registered_at) — trigger uses prescan_completed_at as its 48 h anchor;
  add --ignore-empty-pool flag since selectReviewer has Pass-2/3 fallbacks
- seed-jurors.js: DEV-ONLY script to register temp-user key files as
  juror-eligible personal identities (mocked ZK proof, ZK_SKIP_VERIFY=true
  required on nodes); enables juror_consent + SQL-bumps scores to 750
- check-nodes.sh: quick one-shot health check — state-root agreement,
  anti-entropy counters, byzantine-fork halt status, peer connectivity
@vrkothekar vrkothekar force-pushed the feat/issue-107-separate-role-consents branch from 01aaeef to 0b424f2 Compare June 17, 2026 09:51
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.

Separate opt-in for reviewer / juror / expert pools (backend + UI)

2 participants