Skip to content

fix(dogfood): record candidate argv independently of the execution adapter - #2848

Merged
namastex888 merged 1 commit into
devfrom
fix/dogfood-adapter-argv-evidence
Aug 30, 2026
Merged

namastex888 merged 1 commit into
devfrom
fix/dogfood-adapter-argv-evidence

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

Problem

Stable release publish fails on linux-x64-musl only. Run 33291504929, job publish / Codex standalone task/board dogfood / linux-x64-musl:

codex-dogfood-entry: FAIL — generated evidence failed validation:
stages[5].standalone must contain standalone task list --json and board --json observations
stages[6].standalone ... stages[7].standalone ...

glibc / arm64 / darwin all pass.

Root cause

musl is the only leg that runs the candidate through an execution adapter (scripts/run-musl-dogfood.sh, digest-pinned Alpine in Docker). captureCommand in tests/support/codex-dogfood-harness.ts folded the adapter's spawn vector into the recorded evidence argv:

const argv = input.executionAdapter === undefined ? input.args : [input.binary, ...input.args];

So musl recorded ['<genie binary>', 'task', 'list', '--json'] where every other platform recorded ['task', 'list', '--json'], and validateStandaloneObservation in scripts/validate-live-dogfood-evidence.ts requires argv.join(' ') to be exactly task list --json / board --json.

capturePtySetup had the identical fold (argv: commandArgs.slice(1), which under an adapter leaves the binary at index 0).

Fix

Evidence argv is now always the candidate's own arguments, on every platform. When an adapter wraps the run, the real spawned vector is recorded separately as adapterArgv: [candidateBinary, ...argv]; executable stays the adapter path and candidateBinary the genie binary, both unchanged.

  • New shared resolveInvocation() helper splits { command, argv, adapterArgv, spawnArgv }; both captureCommand and capturePtySetup go through it.
  • Anything that reconstructs a command line — the stage() command projection, the requireExit diagnostic, and the validator's summary — uses adapterArgv ?? argv, so the human-readable line remains the true spawned command.
  • Validator: accepts the optional adapterArgv (rejects a non-string-array), keeps the standalone assertion on argv, and extends the retired-MCP rejection to cover both vectors. There is no strict key allowlist for command records, so no allowlist change was needed.

Evidence stays honest (the real docker invocation is still recorded, in its own field) and the validator stays strict.

Tests

  • scripts/validate-live-dogfood-evidence.test.ts — new case reshapes every stage observation into adapter form (adapter as executable, adapterArgv = [binary, ...argv], argv = candidate args) and asserts it validates clean; the pre-fix binary-prefixed shape still fails with the exact production message for stages 5/6/7; a non-string adapterArgv is rejected; an MCP token smuggled into adapterArgv is rejected.
  • tests/support/codex-dogfood-harness.test.ts (new) — unit-covers resolveInvocation, then really spawns through a tiny fake adapter script (exec "$candidate" "$@") and proves argv == candidate args, adapterArgv == [binary, ...args], executable == adapter, candidateBinary == binary, and that the candidate's echoed argv matches.
bun test scripts/validate-live-dogfood-evidence.test.ts scripts/release-docs.test.ts \
  scripts/run-musl-dogfood.test.ts scripts/candidate-dogfood-matrix.test.ts \
  scripts/validate-dogfood-matrix-evidence.test.ts tests/support/codex-dogfood-harness.test.ts
# 70 pass, 0 fail, 967 expect() calls

Gates: bun run typecheck ✅ · bun run lint ✅ (3 pre-existing src/ complexity warnings, untouched) · bun run dead-code ✅ · bun run lint:complexity-budget ✅ (OK: budget intact). Pre-push hooks ran clean.

Rollout note

The release-publish workflow checks out this harness and validator from main (at github.sha), so this fix only takes effect after the next dev → main promotion. Until that promotion lands, every stable release will keep failing at the musl dogfood gate.

🤖 Generated with Claude Code

https://claude.ai/code/session_013gGxGgKskzyzr1HRUB6cV3

…apter

The linux-x64-musl leg is the only dogfood platform that runs the candidate
through an execution adapter (scripts/run-musl-dogfood.sh, Alpine in Docker).
captureCommand folded the adapter's spawn vector into the evidence `argv`, so
that leg recorded ['<genie binary>', 'task', 'list', '--json'] where every
other platform recorded ['task', 'list', '--json'] — and
validate-live-dogfood-evidence's standalone assertion, which requires an exact
'task list --json' / 'board --json', failed stages 5-7 on musl alone. Stable
release publish has been failing at that gate.

Evidence `argv` is now always the candidate's OWN arguments. When an adapter
wraps the run, the real spawned vector is recorded separately as
`adapterArgv: [candidateBinary, ...argv]`; `executable` remains the adapter and
`candidateBinary` the genie binary, as before. The stage command projection and
the requireExit diagnostic use `adapterArgv ?? argv`, so the human-readable
command line stays the true spawned command.

capturePtySetup had the same fold and is fixed through the shared
resolveInvocation helper. The validator accepts the optional `adapterArgv`
(rejecting a non-string-array), keeps the standalone check on `argv`, and
extends the retired-MCP rejection to cover both vectors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gGxGgKskzyzr1HRUB6cV3
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5f046b06-660a-4eff-8c36-fbc011807a41

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-08-30T05:25:22.281434Z 2bf5d14 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@namastex888
namastex888 merged commit b164716 into dev Aug 30, 2026
12 checks 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: 2bf5d1453d

ℹ️ 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 on lines +518 to +522
if (
command.adapterArgv !== undefined &&
(!Array.isArray(command.adapterArgv) || command.adapterArgv.some((arg) => typeof arg !== 'string'))
) {
errors.push(`${label}.adapterArgv must be a string array`);

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 adapterArgv to the candidate invocation

For adapter-backed evidence, this only verifies that adapterArgv is a string array; it never requires it to equal [candidateBinary, ...argv]. Consequently, evidence can claim standalone task list --json and board --json in argv while the recorded spawn vector invokes different arguments or even a different binary, and the release validator still accepts the supposed standalone proof. Enforce the documented relationship before using argv as candidate-execution evidence.

AGENTS.md reference: AGENTS.md:L55-L57

Useful? React with 👍 / 👎.

Comment on lines +562 to +563
const vectors = commands.flatMap((value) => [value.record.argv, value.record.adapterArgv]);
if (vectors.some((args) => Array.isArray(args) && args.some((arg) => String(arg).toLowerCase().includes('mcp')))) {

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 Exclude the candidate path from the retired-MCP scan

On adapter-backed runs, adapterArgv[0] is the absolute candidate-binary path rather than a candidate argument. If TMPDIR or an injected dogfood root contains the substring mcp (for example /tmp/mcp-release), every otherwise valid musl standalone observation is rejected as retired MCP evidence. Scan only the actual candidate arguments, or at least omit the adapter vector's first element.

AGENTS.md reference: AGENTS.md:L55-L57

Useful? React with 👍 / 👎.

@automagik-genie
automagik-genie deleted the fix/dogfood-adapter-argv-evidence branch September 25, 2026 04:50
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