Skip to content

review: the live producer (live A/B phase 2)#234

Draft
jwbron wants to merge 8 commits into
jwbron/live-eval-corpusfrom
jwbron/live-eval-producer-staging
Draft

review: the live producer (live A/B phase 2)#234
jwbron wants to merge 8 commits into
jwbron/live-eval-corpusfrom
jwbron/live-eval-producer-staging

Conversation

@jwbron

@jwbron jwbron commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Phase 2 of the live A/B eval plan (#232), complete, stacked on the Phase 1 corpus format (#233): everything needed to run the real model sub-agents over a live-enabled corpus case.

2a: eval/agent-extract.ts

Parses review.md's ## agent: sections into {name, description, model, prompt}. String in, no filesystem access, because the baseline arm of an A/B extracts the merge-base review.md via git show. Parsing is strict: missing/unterminated frontmatter, a name mismatch, a missing model, or an empty body throws with every problem listed, since a silently dropped agent would skew an eval arm without failing it. An integration test extracts the real review.md (21 agents) and pins the default roster's reference to the production staging root so a rename fails a test instead of silently staging nothing.

2b: eval/live-stage.ts

Materializes the production /tmp/gh-aw/review/ layout for one case, per review.md Step 1's staging contract: pr-context.json (synthetic identity fields), full.diff/pr.diff/full-stripped.diff, files.json + review-files.json with the hasPatch cross-check, provenance.json, routing.json from the deterministic router, out/, and the post-change checkout from the case's tree. rewriteAgentPrompt swaps the production staging root across a prompt.

2c: eval/live-producer.ts + eval/live-runner.ts

produceLive dispatches the live roster (default finders plus the router's lensesToSpawn; no pattern-triage or thread-reconciler in eval) behind an injected LiveAgentRunner seam, the same pattern as judge.ts's injected model, so all its logic is stub-tested with zero model calls. It maps the three sub-agent output contracts into exactly the shapes the deterministic runner consumes (RecordedFinding[] for produceFindings, CaseVerification[] for the validation replay): label-shape findings get the code-assigned lens (correctness, or conventions for the skill-auditor so labelForFinding reproduces the best-practice label variants) and the production 0.7 confidence default; lens findings validate against the schema as-is; the claim-validator's {claims: [...]} output becomes verifications. It stages claims.json, resolves {{#runtime-import}} directives from the case tree (a case opts into a skills index by carrying the file), retries once on malformed output with the rejection fed back, keeps partial results when an agent fails twice, prefixes colliding finding ids, and accounts per-agent cost/turns/wall-clock.

live-runner.ts is the only module touching a real model runtime: one Agent SDK query() per dispatch, Read/Grep/Glob only, cwd pinned to the staged checkout, the agent's pinned model, hard turn and wall-clock caps, plus the CLI smoke entry: pnpm dlx tsx workflows/review/eval/live-runner.ts --case <id> (requires ANTHROPIC_API_KEY). Adds @anthropic-ai/claude-agent-sdk as a dev dependency.

Documented deviations from production (module doc): no pattern-triage pass, runtime imports resolve from the case tree or a fixed note, and the investigation-cap CLI is not staged (its own denied-budget fallback applies).

Test plan:

  • pnpm run test --run: 680 tests green (21 new across the three test files: extraction fixtures + real-review.md integration, staging via memfs, producer via a scripted stub runner covering happy path, retry, double-failure, empty-findings skip, id collisions, missing-agent error, and runtime-import resolution).
  • pnpm run typecheck and eslint clean.
  • The CLI smoke run against a live case needs ANTHROPIC_API_KEY, which this environment does not have; it is the first thing to run when testing this PR (any of the 13 live case ids, e.g. --case incident-money-rounding). Expected cost: roughly $0.50 to $2 per case with the default roster.

Next steps (human)

  1. Key-bearing validation DONE, superseded by the phase 4 acceptance runs, which exercised this producer end to end with a real key over 7 live cases x 2 arms x 2 PRs (runs 29052332224 and 29052334404); measured ~$0.55-0.72 per case per arm, inside the plan's expected envelope. The CLI smoke remains available for local iteration.
  2. Sanity-check the SDK runner's settings (live-runner.ts): permissionMode: "bypassPermissions" with tools restricted to Read/Grep/Glob and cwd pinned to the staged checkout. Confirm you are comfortable with that posture for CI.
  3. Review the documented deviations from production in live-producer.ts's module doc (no pattern-triage, runtime-import resolution, investigation-cap absence); each is a measurement caveat for the A/B.
  4. New dev dependency: @anthropic-ai/claude-agent-sdk. Confirm it clears whatever dependency review applies to this repo.

…action and case staging

Phases 2a/2b of the live A/B eval plan (#232), stacked on the Phase 1
corpus format (#233).

agent-extract.ts turns review.md's '## agent:' sections into data
(name, description, pinned model, prompt body). It takes the markdown
as a string with no fs access, because the baseline arm of an A/B
reads the merge-base review.md via git show. Parsing is strict; a
malformed or model-less section throws listing every problem, since a
silently dropped agent would skew an eval arm without failing it. An
integration test extracts the real review.md (21 agents) and pins the
staging-root reference so a future rename fails a test instead of
silently staging nothing.

live-stage.ts materializes the production staging layout for one
live-enabled corpus case: pr-context.json (review.md Step 1's shape,
synthetic identity fields), full.diff / pr.diff / full-stripped.diff
(all the case diff; corpus diffs carry no generated files and no
pattern-triage pass runs), files.json + review-files.json with the
hasPatch cross-check derived from the diff parse, provenance.json,
routing.json from the deterministic router, an out/ directory, and
the post-change checkout copied from the case tree.
rewriteAgentPrompt swaps the production staging root for the staged
context dir. Everything sits behind an injected-fs seam and is
memfs-tested.

Model dispatch (phase 2c) is deliberately absent; it needs the Agent
SDK dependency decision and arrives separately.
@jwbron jwbron self-assigned this Jul 9, 2026
@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 25133b4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
review Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

… runner (phase 2c)

live-producer.ts runs the live roster over one staged case behind an
injected LiveAgentRunner seam (the judge.ts pattern), so its logic is
stub-tested with zero model calls. Roster: the default finders
(correctness-reviewer, skill-auditor) plus the router's lensesToSpawn;
no pattern-triage or thread-reconciler in eval. It maps all three
sub-agent output contracts into the shapes the deterministic runner
consumes: label-shape findings (correctness lens, or conventions for
the skill-auditor so labelForFinding reproduces the best-practice
variants; confidence defaulted to 0.7 per the production claims rule),
structured-schema lens findings validated as-is, and the validator's
{claims: [...]} verdicts into CaseVerification[]. It stages
claims.json for the validator, resolves {{#runtime-import}} directives
against the case tree (a case opts into a skills index by carrying the
file), retries once on malformed output with the rejection fed back,
keeps partial results when an agent fails twice, prefixes colliding
finding ids, and reports per-agent cost/turns/wall-clock.

live-runner.ts is the one module that touches a real model runtime:
an Agent SDK query() per dispatch with Read/Grep/Glob only, cwd pinned
to the staged checkout, the agent's pinned model, and hard turn and
wall-clock caps; plus the CLI smoke entry
(tsx live-runner.ts --case <id>, requires ANTHROPIC_API_KEY). The
investigation-cap CLI the prompts reference is not staged; its own
denied-budget fallback applies. Adds @anthropic-ai/claude-agent-sdk
as a dev dependency.
@jwbron jwbron changed the title review: live-producer prompt extraction and case staging review: the live producer (live A/B phase 2) Jul 9, 2026
jwbron added 2 commits July 9, 2026 13:48
…rpus' into jwbron/live-eval-producer-staging
…s with the case id

Live agents choose their own finding ids, so every case's first
correctness finding was live-correctness-reviewer-1; ids were unique
within a case but collided across cases, and judge.ts's score join
requires arm-global uniqueness. Caught by the first real A/B run
(both arms completed, then judge aggregation threw). Ids are now
<caseId>:<id> from the moment of parsing, so claims.json, the
validator round-trip, the matcher, and the judge all see the same
namespaced id.
jwbron added 3 commits July 9, 2026 15:20
…rpus' into jwbron/live-eval-producer-staging
…gin/jwbron/live-eval-producer-staging' into jwbron/live-eval-producer-staging
…rpus' into jwbron/live-eval-producer-staging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant