/claim #18
Summary
Adds a distinct challenge-prequalification-fairness-guard/ slice for Scientific Bounty System issue #18. The guard evaluates sponsor-side prequalification rounds before solver teams are accepted or rejected.
It checks well-formed top-level prequalification packets, challenge identity, generated-at audit timestamps, published screening criteria, criteria-list evidence, criterion identifiers after trimming, valid weights and totals, valid thresholds and reviewer quorum, sponsor accept/reject decisions, applicant identities, applicant-list evidence, review-list evidence, reviewer identities, duplicate reviewer score evidence, valid finite 0-100 score values, anonymous-screening requirements, reviewer conflicts, rejection reasons, appeal windows, and deterministic audit evidence.
Conflicted reviewer scores are excluded from threshold scoring while the conflict remains auditable. Repeated reviewer identities are deduplicated before quorum or threshold scoring. Malformed top-level packets, missing challenge identities, invalid generated-at timestamps, missing applicant lists, malformed applicant rows, missing or duplicate applicant identities, missing criteria lists, malformed criteria entries, missing review lists, malformed review entries, missing reviewer identities, invalid sponsor decisions, and invalid score values are held before solver access can change.
Latest Hardening
17e260d: invalid or missing generatedAt round timestamps now produce a high-priority generated-at-invalid fairness hold instead of allowing an otherwise accepted applicant through without auditable round timing evidence.
- Added
reports/invalid-generated-at-packet.json and refreshed the generated Markdown evidence so reviewers can inspect the new hold.
- The red regression first failed with
accept-prequalified instead of hold-for-fairness-review for a high-scoring accepted applicant whose round had generatedAt: "not-a-date".
Prior hardening also covers malformed top-level prequalification packets, missing/blank challenge identities, malformed criteria entries, missing criteria lists, malformed review entries, missing review lists, malformed applicant entries, missing applicant lists, missing or duplicate applicant identities, missing or blank reviewer identities, duplicate reviewer score evidence, incomplete reviewer scores, invalid score values, invalid quorum/threshold/sponsor decisions, appeal-window errors, hidden criteria, reviewer conflicts, and malformed rejection-reason evidence.
Non-overlap
This is scoped to prequalification fairness before solver acceptance or rejection. It does not duplicate broad bounty-system modules, intake compliance, workspace privacy, clarification freeze, arbitration/scoring, payout eligibility, sponsor data-room access, benchmark leakage, evaluator calibration, reviewer workload SLA, award transparency, appeals, escrow settlement, sponsor reliability, submission quarantine/security, deadline fairness, COI recusal, withdrawal reimbursement, localization, communication parity, onboarding clocks, regulatory attestation, or payout-routing slices.
Timestamp Hardening Update
6465bfa: strict UTC timestamp validation now rejects calendar-impossible generatedAt and appeal-window values before sponsor prequalification decisions can take effect.
generatedAt: "2026-02-30T08:00:00Z" now emits generated-at-invalid instead of allowing a high-scoring applicant through after JavaScript date normalization.
appealDueAt: "2026-06-31T08:00:00Z" now emits invalid-appeal-window instead of publishing a rejection packet with a normalized open appeal deadline.
- Added
reports/impossible-generated-at-packet.json and reports/impossible-appeal-window-packet.json plus refreshed Markdown/MP4 evidence.
- Verification: red regression first reproduced
reject-with-audit for the impossible appeal deadline; npm test passed (35 tests); npm run check, npm run demo, and npm run video passed; 20 JSON packets parsed; ffprobe verified H.264 1280x720 30fps 4.0s / 120 frames / 46,164 bytes; diff checks, allowlist staging, and focused restricted-string scan passed.
Validation
- Red regression first reproduced
accept-prequalified instead of hold-for-fairness-review when a prequalification round had an invalid generated-at timestamp.
npm test from challenge-prequalification-fairness-guard -> 33 challenge prequalification fairness tests passed.
node --check passed for index.js, test.js, and demo.js.
npm run demo regenerated 18 JSON packets plus Markdown and SVG evidence.
npm run video regenerated reports/demo.mp4.
npm run check passed the package test, demo, and video sequence.
- All 18 generated JSON packets parsed successfully, including
reports/invalid-generated-at-packet.json.
ffprobe verified reports/demo.mp4 as H.264, 1280x720, 30 fps, 4.0s, 120 frames, 46,164 bytes.
git diff --check and git diff --cached --check passed; only Windows line-ending normalization warnings appeared.
- Staged allowlist check confirmed all staged paths are under
challenge-prequalification-fairness-guard/.
- Focused payout/credential scan returned no matches.
Demo Artifacts
challenge-prequalification-fairness-guard/reports/prequalification-fairness-packet.json
challenge-prequalification-fairness-guard/reports/missing-criterion-id-packet.json
challenge-prequalification-fairness-guard/reports/normalized-criterion-id-packet.json
challenge-prequalification-fairness-guard/reports/invalid-reviewer-score-packet.json
challenge-prequalification-fairness-guard/reports/invalid-reviewer-quorum-packet.json
challenge-prequalification-fairness-guard/reports/invalid-sponsor-decision-packet.json
challenge-prequalification-fairness-guard/reports/missing-applicant-identity-packet.json
challenge-prequalification-fairness-guard/reports/duplicate-applicant-identity-packet.json
challenge-prequalification-fairness-guard/reports/missing-review-list-packet.json
challenge-prequalification-fairness-guard/reports/malformed-review-entry-packet.json
challenge-prequalification-fairness-guard/reports/missing-criteria-list-packet.json
challenge-prequalification-fairness-guard/reports/malformed-criterion-entry-packet.json
challenge-prequalification-fairness-guard/reports/missing-applicant-list-packet.json
challenge-prequalification-fairness-guard/reports/malformed-prequalification-round-packet.json
challenge-prequalification-fairness-guard/reports/missing-challenge-identity-packet.json
challenge-prequalification-fairness-guard/reports/invalid-generated-at-packet.json
challenge-prequalification-fairness-guard/reports/malformed-applicant-entry-packet.json
challenge-prequalification-fairness-guard/reports/blank-rejection-reason-packet.json
challenge-prequalification-fairness-guard/reports/prequalification-fairness-report.md
challenge-prequalification-fairness-guard/reports/summary.svg
challenge-prequalification-fairness-guard/reports/demo.mp4
Synthetic data only. No credentials, payment processors, identity providers, private workspaces, sponsor systems, solver accounts, payout systems, or external APIs are used.
AI-assisted with OpenAI Codex; I reviewed and locally verified the diff before submitting.