Skip to content

feat: add fail-closed prospective maintainer study runner - #12

Merged
VrtxOmega merged 1 commit into
mainfrom
feat/prospective-study-runner
Jul 14, 2026
Merged

feat: add fail-closed prospective maintainer study runner#12
VrtxOmega merged 1 commit into
mainfrom
feat/prospective-study-runner

Conversation

@VrtxOmega

Copy link
Copy Markdown
Owner

Summary

  • add a local pcf study workflow for the frozen 48-case independent-maintainer protocol
  • separate consent identity, observations, canonical snapshots, sealed PCF outputs, blinded rating packets, and aggregate receipts
  • fail closed on permission drift, symlinks, path traversal, unapproved production activation, assignment conflicts, self-rating, hash drift, duplicate ratings, withdrawal violations, and post-lock mutation
  • preserve deterministic aggregate analysis through the offline corpus validator merged in feat: add offline maintainer corpus validation #11

Why this is narrow

This is one new study-runner core, one focused test file, one operator guide, and the minimum CLI/package wiring. It adds no dependency, network call, GitHub write capability, evaluator threshold change, benchmark expectation change, or live participant data.

Validation

  • node --test test/prospective-study.test.mjs test/corpus-validation.test.mjs — 11/11 passed
  • npm run ci:gates — 268/268 tests, 77/77 benchmark cases, 29/29 adversarial cases, maintainer demo PASS
  • npm run mcp:smoke — PASS; no public-write tools
  • durable synthetic status — 0 participants, 0 observations, 0 cases, 0 ratings, aggregate unlocked, outreach unauthorized, decision INCONCLUSIVE
  • signed commit 0d2755b72343dbe93efbbc9cffe24f301adeb7bc — good signature; tree and five file hashes match the prior sealed implementation
  • rebased VERITAS — 10/10 PASS, claim 3035da7826bbe2cf76643b831cbae0ca904e7a8d01cdb11b72e21464851adc08

Boundaries

This PR does not activate a study, contact maintainers, register research, promise compensation, collect participant data, establish institutional compliance, or claim product validity. All analysis remains INCONCLUSIVE until a genuinely consented, independently governed prospective corpus exists.

@VrtxOmega
VrtxOmega merged commit 75419de into main Jul 14, 2026
1 check passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0d2755b723

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

caseId: item.caseId,
stratum: item.stratum,
pcfLane: seal.pcf.lane,
consensusLane: strictMajority(ratings.map((rating) => rating.lane)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Exclude no-majority cases before aggregation

When the three raters split across all three lanes, strictMajority(...) returns null, but this case still remains in completed and counts toward targetCases for --lock. The later false/missed review-now counts and per-stratum confusion matrix then treat that null consensus as data while the corpus validator excludes it as ambiguous, so an ambiguous case can be locked as complete and corrupt the reported rates.

Useful? React with 👍 / 👎.

Comment on lines +857 to +859
if (write || lock) {
await writePrivateFile(join(loaded.paths.corpus, "consented.jsonl"), corpusText);
await writePrivateJson(join(loaded.paths.output, "analysis.json"), result);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not write aggregate artifacts before lock

If an operator runs pcf study analyze --write without --lock while withdrawal is still allowed, these files are written even though aggregateLockedAt remains unset. A later withdrawStudyParticipant only deletes the participant's rating files and marks cases excluded; it never removes or rewrites restricted/corpus/consented.jsonl or output/analysis.json, so withdrawn ratings can remain in durable aggregate artifacts.

Useful? React with 👍 / 👎.

Comment on lines +1150 to +1151
for (const position of expected) {
if (!positions.has(position)) throw new ProspectiveStudyError(`Sampling slot '${slotId}' references unknown position '${position}'.`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate slot host positions at initialization

This validation checks only the context/external rater positions, but never verifies that slot.hostPosition itself exists in hostPositions or that its per-host ordinal is usable. A sampling frame with a typo in slot.hostPosition initializes successfully, yet consent/observation can never be recorded for that slot because consent rejects unknown host positions, making the target case count impossible to reach after the study has already been initialized.

Useful? React with 👍 / 👎.

@VrtxOmega
VrtxOmega deleted the feat/prospective-study-runner branch July 14, 2026 00:11
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