Skip to content

Add reusable campaign admission contract - #457

Draft
lluisinthedesert wants to merge 8 commits into
mainfrom
yolo/campaign-admission-contract
Draft

Add reusable campaign admission contract#457
lluisinthedesert wants to merge 8 commits into
mainfrom
yolo/campaign-admission-contract

Conversation

@lluisinthedesert

@lluisinthedesert lluisinthedesert commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

What changed

  • add a versioned, runtime-enforced campaign-admission schema and reusable fail-closed validator
  • require campaign_id, reject unknown properties, and test schema/runtime lockstep
  • attest pyproject.toml, uv.lock, live uv lock --check, exact locked uv run --project ... --locked argv, uv/Python identity, complete resolved package inventory, git revisions, MCP/tool-schema hashes, and immutable container digest
  • generate the synthetic exactly-one-task smoke with Verifiers 0.2.1, then reproduce and compare its trace, execution receipt, and before/after state artifacts byte-for-byte
  • bind distinct seed/candidate hashes to generator inputs and verify a specific real state delta rather than trusting hand-authored mutation fields
  • derive redacted per-tool-step transport fingerprints from response and executed trace: call-id hash, normalized tool-name hash/class, raw argument SHA, semantic object SHA, result hashes, pair hashes, equality flags, and mutation evidence
  • fail on duplicate/missing tool IDs, non-string wire arguments, invalid/non-object JSON, name or semantic mismatch, and unmatched trace calls/results
  • preserve fixed benchmark prompts, consume candidate policy tags from the outer system transcript exactly once, and enforce exact upstream messages/tools/sampling payload parity
  • fail context overflow instead of silently lowering max_tokens
  • quarantine unchanged candidates and split admission-only evidence from compile authorization so a paid canary remains inspectable before GEPA reflection
  • separate immutable optimizer, endpoint, and training caps/charges; account for prior spend and require prior plus new charges to remain within the campaign total
  • expose only the public schema, validators, CLI, and synthetic fixture; no customer data or secrets

Why

Campaigns need one reusable admission boundary before optimizer, endpoint, or training spend begins. This turns previously separate run conventions into an inspectable receipt and prevents compilation from hiding a malformed or non-mutating paid canary.

Safety and privacy

The implementation performs local validation only. It does not deploy, call providers, execute customer workloads, merge changes, or include private prompts, traces, credentials, or answer keys.

Validation

  • focused campaign-admission suite: 8/8 passed
  • full npm run check: 1,191 tests across 162 suites passed; typecheck, build, skill validation, and package dry-run passed
  • exact locked fixture generator replay passed
  • git diff --check passed

Cedar compatibility note

The fixture locks canonical Verifiers 0.2.1 at commit ab65b6e8d34b03d162408d4bcb854430a86809e6 with mcp==1.29.0. Historical Cedar artifacts that lack the generated execution receipt, exact environment inventory, per-step response-to-trace transport pairing, assertion fraction, or verified state delta will fail admission. They require private re-execution or a private adapter that produces equivalent hash-bound evidence; this public contract intentionally does not weaken admission for legacy rows.

@lluisinthedesert

Copy link
Copy Markdown
Contributor Author

@codex review

Fresh independent review requested for head 3f2d2da. Please re-evaluate all previously reported P1s plus the cross-workload admission additions:

  • actual pinned-Verifiers ToolEnv mutation and independent state-delta assertion
  • interpreter path/hash and installed distribution inventory captured inside exact locked uv run
  • exact raw and semantic request-to-executed tool argument equality
  • prior spend plus effective lane allocation reservation
  • executed oversized-request failure before sampling/tool execution
  • separate optimizer input and executable endpoint bundle attestations
  • candidate parent/prompt/model/checkpoint lineage and source/reflection context gates
  • generic exact workload Verifiers/MCP version and commit matching, while Cedar remains pinned to Verifiers 0.2.1

No providers, deployment, private data, or merge were used. Full repository checks pass locally.

@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: 3f2d2da5c7

ℹ️ 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".

Comment thread src/commands/campaigns.ts Outdated
Comment on lines +45 to +46
const generator = resolve(options.smokeGenerator);
if (generator !== join(project, "generate_smoke.py")) throw new Error("smoke generator must be generate_smoke.py inside the locked project");

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 Bind the smoke generator before trusting its rerun

When campaigns admit is run against a caller-supplied project, this verifies only that the script has the expected filename; neither the manifest nor another trusted artifact binds the script's contents. A modified generate_smoke.py can therefore skip ToolEnv execution, emit self-consistent trace/state/receipt files, and pass the subsequent byte comparison because the CLI reruns that same untrusted script. Hash or otherwise attest the generator before treating its output as proof of an actual pinned-Verifiers mutation.

Useful? React with 👍 / 👎.

Comment thread src/campaign-admission/index.ts Outdated
Comment on lines +362 to +364
if (!pins.some((pin) => pin.name === "verifiers" && pin.version === "0.2.1" && typeof pin.git_revision === "string" && GIT_REVISION.test(pin.git_revision))) {
errors.push("environment.resolved_packages must pin verifiers 0.2.1 to a full git revision");
}

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 Scope the Cedar Verifiers pin instead of applying it globally

For any non-Cedar workload whose lock, workload contract, receipt, and trace consistently attest a different exact Verifiers version, this unconditional environment check still rejects admission. That defeats the new generic version/commit matching at lines 291–295 and makes the reusable cross-workload contract effectively hard-coded to 0.2.1; apply this constraint only when the workload is identified as Cedar.

Useful? React with 👍 / 👎.

Comment on lines +321 to +322
const expectedCandidate = sha256Bytes(Buffer.from(canonicalize({ parent_candidate_sha256: lineage.parent_candidate_sha256, prompt_sha256: lineage.prompt_sha256, model_attestation_sha256: lineage.model_attestation_sha256, checkpoint_sha256: lineage.checkpoint_sha256, executable_bundle_sha256: endpoint.executable_bundle_sha256 })));
if (lineage.candidate_sha256 !== expectedCandidate) errors.push("candidate mutation is not bound to parent, prompt, model, checkpoint, and executable bundle");

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 Bind candidate lineage to the admitted workload prompt

If candidate_lineage.prompt_sha256 is changed to an unrelated hash and candidate_sha256 is recomputed from the fields here, admission still succeeds because the lineage prompt is never compared with workload_contract.benchmark_prompt_sha256. This permits a candidate generated for one prompt to be admitted against another workload while presenting internally consistent lineage, so the prompt lineage needs a cross-attestation to the admitted prompt.

Useful? React with 👍 / 👎.

Comment thread src/campaign-admission/index.ts Outdated
Comment on lines +234 to +238
const installed = Array.isArray(receipt.installed_distributions) ? receipt.installed_distributions.map(object) : [];
const declared = Array.isArray(object(manifest.environment).resolved_packages) ? (object(manifest.environment).resolved_packages as unknown[]).map(object) : [];
const installedPairs = installed.map((pin) => `${pin.name}==${pin.version}`).sort();
const declaredPairs = new Set(declared.map((pin) => `${pin.name}==${pin.version}`));
if (installedPairs.some((pin) => !declaredPairs.has(pin))) errors.push("inside-project installed distributions contain a package outside the exact lock inventory");

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 Require the captured distribution inventory to be complete

For direct callers of the exported validator, this one-way subset check accepts an inventory with arbitrary locked packages omitted: removing mcp (or even verifiers) from installed_distributions and updating the two inventory/receipt hashes leaves every remaining pair in declaredPairs, so admission can still succeed. Consequently the receipt does not attest the claimed exact installed environment; validate the complete expected environment inventory, including required workload distributions, rather than only rejecting extras.

Useful? React with 👍 / 👎.

Comment on lines +245 to +246
const delta = object(receipt.verified_state_delta);
if (delta.path !== "/records/alpha/status" || delta.before !== "pending" || delta.after !== "ready") errors.push("execution receipt does not verify the required state delta");

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 Enforce the independent state-delta assertion

When validating a receipt outside the fixed CLI fixture, verified_state_delta.independently_asserted can be false or absent and the receipt and manifest hashes can be updated without producing any admission error. The validator checks only the path and values, so evidence that explicitly says the delta was not independently asserted is still admitted; require this receipt field to be exactly true.

Useful? React with 👍 / 👎.

@lluisinthedesert

Copy link
Copy Markdown
Contributor Author

@codex review

Fresh independent review requested for head 923d210. Please re-check the four P1s from the review of 3f2d2da:

  • optimizer input, executable bundle, health, model, checkpoint, lineage, source, and reflection hashes are derived from supplied immutable artifacts sharing campaign/workload/request/execution identity; request, trace, execution receipt, overflow receipt, and evidence all enforce that identity
  • installed distributions equal a platform-applicable inventory generated from the exact locked uv export; root/non-installable and marker exclusions are explicit; installed Verifiers must match the exact locked version and VCS commit
  • no production validator/schema constant remains for Verifiers 0.2.1; Cedar remains git-pinned to 0.2.1 and a second fully replayed git-pinned fixture proves Verifiers 0.2.2.dev77 admission
  • assertion_fraction is emitted by an actual verifiers.Rubric.score_rollout assertion over the executed ToolEnv trajectory/state and is receipt-bound; overflow is bound to the executable endpoint artifact

Adversarial tests cover campaign/workload substitution, arbitrary artifact hashes, omitted packages after rehash, missing Verifiers, runtime mismatch, and fabricated metrics. Both locked generators replay byte-for-byte and the full repository check passes locally. No providers, private data, deployment, merge, or holdout activity.

@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: 923d2101dc

ℹ️ 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".

Comment thread src/commands/campaigns.ts
if (declaredPins !== lockedPins) throw new Error("resolved package pins do not exactly match uv.lock");
const generator = resolve(options.smokeGenerator);
if (generator !== join(project, "generate_smoke.py")) throw new Error("smoke generator must be generate_smoke.py inside the locked project");
const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState], ["overflow-receipt.json", options.overflowReceipt], ["campaign-evidence.json", options.campaignEvidence], ["applicable-lock.json", options.applicableLock]] as const;

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 Bind the generator contents before replay

When --project is caller-controlled, the fresh head adds campaign evidence and applicable-lock output to the byte comparisons, but both are still produced by the same unattested generate_smoke.py; the preceding check verifies only its path. Replacing that script can synthesize a fully self-consistent trace, receipts, inventory, and evidence bundle which then reproduces byte-for-byte, so bind the generator contents to a trusted digest outside the supplied project before treating this replay as execution proof.

Useful? React with 👍 / 👎.

Comment on lines +242 to +243
if (canonicalize(installed) !== canonicalize(applicable)) errors.push("installed distributions do not equal the exact applicable locked project inventory");
if (canonicalize(applicable) !== canonicalize(applicableArtifact)) errors.push("applicable locked distributions do not match the supplied uv-export artifact");

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 Check applicable versions against locked pins

For direct callers of validateCampaignAdmission, equality between installed, applicable, and the supplied artifact does not prove that their versions came from environment.resolved_packages. For example, changing mcp or aiofiles to 9.9.9 in both arrays and rehashing the artifact, receipt, and environment still passes because only Verifiers is cross-checked against declared; compare every applicable name/version with the exact lock pins or derive this inventory in trusted code.

Useful? React with 👍 / 👎.

Comment on lines +353 to +355
const executableEvidence = object(evidence.executable_bundle);
const healthEvidence = object(evidence.health_receipt);
if (executableEvidence.environment_sha256 !== endpoint.environment_sha256 || executableEvidence.model_attestation_sha256 !== endpoint.model_attestation_sha256 || executableEvidence.checkpoint_sha256 !== lineage.checkpoint_sha256 || executableEvidence.frozen !== true) errors.push("executable artifact does not match endpoint environment/model/checkpoint attestation");

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 Bind the executable policy to the admitted candidate

The new executable-artifact check binds its environment, model, checkpoint, and frozen flag, but never binds executableEvidence.policy to workload_contract.candidate_tag_sha256 or the mutation receipt's candidate hash. A caller can replace the executable policy, recompute the executable/health/lineage/overflow hashes, and still admit evidence whose request and trace evaluated a different candidate from the endpoint bundle that would be used afterward.

Useful? React with 👍 / 👎.

const healthEvidence = object(evidence.health_receipt);
if (executableEvidence.environment_sha256 !== endpoint.environment_sha256 || executableEvidence.model_attestation_sha256 !== endpoint.model_attestation_sha256 || executableEvidence.checkpoint_sha256 !== lineage.checkpoint_sha256 || executableEvidence.frozen !== true) errors.push("executable artifact does not match endpoint environment/model/checkpoint attestation");
if (healthEvidence.status !== "healthy" || healthEvidence.executable_bundle_sha256 !== endpoint.executable_bundle_sha256 || healthEvidence.environment_sha256 !== endpoint.environment_sha256 || healthEvidence.model_attestation_sha256 !== endpoint.model_attestation_sha256) errors.push("health artifact does not attest the admitted executable endpoint");
if (object(evidence.lineage).parent_candidate_sha256 !== lineage.parent_candidate_sha256 || object(evidence.lineage).prompt_sha256 !== lineage.prompt_sha256 || object(evidence.lineage).model_attestation_sha256 !== lineage.model_attestation_sha256 || object(evidence.lineage).checkpoint_sha256 !== lineage.checkpoint_sha256 || object(evidence.lineage).executable_bundle_sha256 !== endpoint.executable_bundle_sha256 || object(evidence.lineage).health_receipt_sha256 !== endpoint.health_receipt_sha256) errors.push("candidate lineage claims do not match supplied lineage artifact");

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 Bind lineage prompt to the admitted prompt

Fresh evidence in this head only verifies that the supplied lineage artifact repeats candidate_lineage.prompt_sha256; neither value is compared with the request messages hash or workload_contract.benchmark_prompt_sha256. Changing both lineage prompt fields and recomputing the lineage and candidate hashes therefore still admits a candidate attributed to an unrelated prompt, so cross-attest this field to the manifest's defined admitted-prompt hash.

Useful? React with 👍 / 👎.

@lluisinthedesert

Copy link
Copy Markdown
Contributor Author

@codex review

Fresh independent review requested at d348fe7 for the remaining P1 from 923d210.

The workload-local generate_smoke.py files are removed and are no longer executable trust roots. Campaign admission now uses an audited generator shipped by agent-tools, verifies its independently bound SHA/version, executes it inside the supplied exact uv run --project <project> --locked environment, and byte-compares all critical generated evidence before validation. The npm package smoke now requires that trusted runtime asset.

Added a coherent-fabrication regression that rewrites the trace, manifest, execution receipt, metric, hashes, and transport fingerprints consistently; admission still fails because independent agent-tools derivation disagrees. Exact Cedar Verifiers 0.2.1 and second 0.2.2.dev77 locked fixtures remain covered.

Validation: npm run check passed (1,203 tests, 0 failures; 40 public skills; npm package dry-run green). No provider calls, holdout work, deploy, or merge.

@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: d348fe7031

ℹ️ 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".

Comment thread src/campaign-admission/index.ts Outdated
const smoke = object(manifest.mutation_smoke);
if (smoke.execution_receipt_sha256 !== sha256Bytes(artifacts.executionReceipt)) errors.push("mutation_smoke.execution_receipt_sha256 does not match supplied receipt");
if (receipt.schema_version !== "understudy.synthetic_verifiers_execution.v1") errors.push("synthetic execution receipt schema is invalid");
if (receipt.trusted_generator_version !== "understudy.agent_tools.campaign_admission_generator.v1" || receipt.trusted_generator_sha256 !== sha256Bytes(artifacts.trustedGenerator) || receipt.trusted_generator_sha256 !== object(manifest.environment).trusted_generator_sha256) errors.push("execution evidence is not derived by the trusted agent-tools generator");

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 Bind the exported validator to the packaged generator

Fresh evidence at this head shows that direct callers of the newly exported validateCampaignAdmission still choose artifacts.trustedGenerator; this check merely compares that caller-controlled buffer with hashes in the caller-controlled manifest and receipt. A caller can substitute arbitrary generator bytes, update those two hashes, and retain an admitted result, so coherent fabricated evidence remains possible whenever admission uses the public validator rather than the CLI. Load or hash the packaged runtime asset inside the validator instead of accepting the trust root as a transport artifact.

Useful? React with 👍 / 👎.

Comment on lines +34 to +37
CAMPAIGN_ID = "public-synthetic-campaign"
WORKLOAD_ID = "cedar-public-synthetic"
REQUEST_ID = "request-public-1"
EXECUTION_ID = "execution-public-1"

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 Derive generator identity from the admission input

When campaigns admit is used for any campaign other than the public fixture, the trusted generator always emits these fixed campaign, workload, request, and execution IDs. The CLI byte-compares that generated campaign evidence and trace with the supplied files, while validateIdentity requires those files to match the manifest and request, so no real campaign with different IDs can ever be admitted. Pass the admitted identity into the audited generator, or keep campaign-specific evidence outside the fixed synthetic replay.

Useful? React with 👍 / 👎.

@lluisinthedesert

Copy link
Copy Markdown
Contributor Author

@codex review

Fresh independent review requested at f9bc9fe for the public-API P1 found at d348fe7.

validateCampaignAdmission now resolves and hashes the packaged Agent Tools trust-root asset internally. TransportArtifacts no longer accepts trusted-generator bytes, and readTransportArtifacts no longer accepts or reads a trusted-generator path. Extra JavaScript properties cannot override the internally resolved asset.

New direct-library adversarial coverage proves that substituted generator bytes, a substituted generator path, and a coherently rewritten metric + trace + manifest + execution receipt are rejected. CLI exact locked replay, npm package inclusion, Cedar Verifiers 0.2.1, and the independent 0.2.2.dev77 fixture remain green.

Validation: npm run check passed (1,205 tests, 0 failures; 40 public skills; npm package dry-run green). No provider calls, holdout, merge, or deployment.

@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: f9bc9fe237

ℹ️ 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".

});
if (workload.candidate_source !== "outer_system_transcript" || workload.policy_injection_count !== 1) errors.push("candidate policy must come from the outer system transcript and be injected exactly once");
if (workload.benchmark_prompt_sha256 !== sha256Bytes(Buffer.from(canonicalize(fixedMessages)))) errors.push("fixed benchmark prompt slot is not hash-bound independently of the candidate policy");
if (workload.tool_schema_sha256 !== toolsHash) errors.push("workload tool schema hash does not match tools artifact");

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 Validate executed calls against the admitted tool schema

For direct callers of validateCampaignAdmission, a response and trace can coherently rename set-record to an undeclared tool such as delete-all, update the tool-step, trace, execution-receipt, and manifest hashes, and still be admitted while the supplied tools artifact continues to declare only set-record. This line binds the catalog's hash but no code checks executed tool names or arguments against that catalog, so admission can attest a mutation performed through an interface the workload never authorized.

Useful? React with 👍 / 👎.

const errors: string[] = publishedSchemaErrors(manifest);
if (value.schema_version !== CAMPAIGN_ADMISSION_SCHEMA_VERSION) errors.push(`schema_version must equal ${CAMPAIGN_ADMISSION_SCHEMA_VERSION}`);
validateEnvironment(value, errors);
const fingerprints = fingerprintTransport(artifacts);

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 Return a rejection for malformed transport JSON

When any caller-supplied request, response, tools, or trace buffer contains malformed JSON, fingerprintTransport throws here before the validator's error-collection paths run. Direct-library consumers therefore receive an undocumented synchronous exception instead of the promised AdmissionResult with admitted: false, which can crash a service that treats this exported function as the fail-closed validation boundary; catch transport parsing failures and report them as admission errors.

Useful? React with 👍 / 👎.

@lluisinthedesert

Copy link
Copy Markdown
Contributor Author

@codex review

Fresh independent review requested at a1da982 for the clean-room strict-promotion contract.

Added a versioned, workload-generic understudy.strict_promotion.v1 schema and public validator. Promotion now requires an independently expected trusted-scorer contract hash; exact named taskset/harness/scorer/terminal/export/promotion/model/checkpoint/DSPy preimages; exact model/checkpoint/DSPy kind/id/revision identities; zero scorer exceptions; canonical and physical row preimages; the trusted complete dev task ID set exactly once for candidate and every parent; prompt-hash parity; paired wins/losses/ties; and candidate strict-exact count greater than every parent. Dense-only improvement returns HOLD.

Prompt-bearing evaluation evidence and candidate_persistence_payload must remain private_cas with externalized=false; only schema-constrained redacted, prompt-free row receipts can externalize. No AutomationBench scoring semantics are hard-coded; Cedar admission remains pinned to Verifiers 0.2.1 and the second 0.2.2.dev77 fixture remains green.

Adversarial coverage includes dense-only gain, scorer exception, missing/duplicate task, prompt mismatch, scorer/preimage substitution, row-preimage mismatch, and prompt-leakage classification. npm run check passed: 1,209 tests, 0 failures; 40 public skills; package dry-run green. No providers, holdout, merge, or deploy.

@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: a1da9822a0

ℹ️ 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".

const scorerHash = sha(artifacts.trustedScorerContract);
if (value.trusted_scorer_contract_sha256 !== scorerHash || scorerHash !== artifacts.expectedTrustedScorerContractSha256) errors.push("trusted scorer contract hash does not match independently expected scorer-contract preimage");
const declared = object(value.named_preimages);
for (const [name, bytes] of Object.entries(artifacts.namedPreimages)) if (declared[name] !== sha(bytes) || sha(bytes) !== artifacts.expectedNamedPreimageSha256[name as keyof typeof artifacts.expectedNamedPreimageSha256]) errors.push(`named preimage ${name} hash mismatch`);

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 Validate every required named preimage

When a JavaScript caller omits harness, scorer, terminal, export, or promotion from both artifact maps, this loop never visits those required names, so schema-valid arbitrary hashes in evidence.named_preimages remain unchecked and the result can still be PROMOTE. The TypeScript record type is not a runtime guarantee for this public validator; iterate the fixed nine-name set and reject every missing buffer or expected digest.

Useful? React with 👍 / 👎.

Comment on lines +53 to +55
if (row.candidate_prompt_sha256 !== row.evaluated_prompt_sha256) errors.push(`prompt hash mismatch for ${id}/${task}`);
const rowPreimage = artifacts.rowPreimages[`${id}/${task}`];
if (!rowPreimage || row.canonical_row_sha256 !== sha(rowPreimage.canonical) || row.physical_row_sha256 !== sha(rowPreimage.physical)) errors.push(`canonical/physical row hashes do not match supplied preimages for ${id}/${task}`);

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 Bind scored row fields to their preimages

When a row's strict_exact value is changed while its two declared hashes and supplied preimage buffers are left untouched, this check still passes because it verifies only the buffers' digests and never decodes either preimage to compare the candidate, task, prompt, score, or exception data. An originally losing candidate can therefore flip enough booleans to become a strict-exact winner and receive PROMOTE; derive the scored receipt fields from the canonical/physical row contents or validate their semantic equality.

Useful? React with 👍 / 👎.

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