Staff Cut B across three sessions and prepare Cut C for the pre-1.0 corpus (#456) - #489
Conversation
…pins, and claims (#456) Cut B is staffed as three parallel sessions coordinating through the inventory CSV. Before they start, the contract they claim slots against has to exist: where a corpus-built synthetic lives (never samples/), what makes it a case (base/ and head/ that differ, CASE.md beside them, no engine output inside), how real history enters (a sweep, then a miner label, so the slot stays holdout-eligible), and the pin form for closed-unmerged and reverted PRs, which the merge-commit convention cannot express. The guard gains a constructed_design basis, a by-name engine_tests detector for constructions, and reads n8n as the top-level section it is rather than a tool-source type it is not. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ner (#456) The safety-qualification corpus needs a rejected_or_reverted vein that merged history cannot supply. `mine --state closed` enumerates PRs closed without merging, pinned at the fork point and the PR head; `--state reverted` finds merged PRs a later Revert PR undid, pinned like any merged PR with the revert recorded in notes; `--pr N` mines one named PR in whichever state it is in. Merged enumeration is untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…bulary (#456) Restructure benchmark/miner/LABELING.md so the top of the file is a self-contained rater rubric for passed / review_required / insufficient_evidence / blocked, with a first-draft rule for the review_required vs insufficient_evidence line, constructed illustrations that name no corpus case, a mapping to the miner's three labels, and the JSON output contract. The miner process moves below a 'not a rater input' heading and the real-PR anchor that stated a corpus case's label and verifier verdicts is removed. A guard test keeps the guide free of inventory candidate refs (both spellings), slot samples, and SHIP- check IDs, and requires the four decisions as headings above the miner section. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…or Cut C (#456) build_packet.py turns an external (clone + base/head SHAs) or constructed (base/ + head/ trees) case into the three inputs Amendment 1 condition 2 allows: repo/ (the head tree, no .git, verifier output and CASE.md excluded), diff.patch, a byte copy of LABELING.md, plus a role-specific TASK.md and a MANIFEST.json hashing every file. It refuses a source tree that carries the strata inventory. run_rater.py runs one fresh read-only session per family (claude -p with Read/Grep/Glob only and no MCP; codex exec --sandbox read-only), archives the complete transcript content-addressed, and parses the final message into an IndependentHumanLabelV1 with reviewer_id <family>:<model>:<session>. Anything but exactly one valid JSON object with a known decision fails closed. --home-mode isolated runs --bare in an empty HOME (needs ANTHROPIC_API_KEY); shared keeps the caller's HOME under file-level memory checks. --dry-run prints the command and environment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Name the five non-corpus cases for the Amendment 1 calibration round: four merged reserve PRs pinned as merge commit + first parent from a clone (mongodb-js/mongodb-mcp-server#1417, awslabs/mcp#4489, stripe/ai#353, openai/openai-agents-python#3518) and one constructed blocked-shaped LangChain case under calibration/cal-5/, since no reserve PR has that shape. Each entry records why the diff tests the guide and where two raters are expected to diverge; no label or verdict is recorded. The file discloses that the chooser had read the inventory, which is why none of these can ever become a corpus case. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…esses (#456) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…Cut B (#456) sdk_agent_adds_ticket_update_tool adds a scoped Zendesk write with no approval policy; sdk_agent_loads_tools_from_registry replaces the literal tools list with a runtime registry so the bound surface is not enumerable. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…or Cut B (#456) crewai_tools_from_factory builds the crew's tools from a profile factory; langchain_agent_adds_refund_tool adds a Stripe refund tool with neither an approval policy nor idempotency evidence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…456) adk_agent_adds_calendar_toolset adds a domain-scoped calendar write through a resolved McpToolset (the adk-samples#1975 shape); adk_billing_sub_agent_refund puts a Stripe refund on a sub-agent (the adk-samples#1745 shape) with no approval policy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ut B (#456) Five slot cases on one support-orders workflow family: a POST tool with no approval, a Code Tool whose request target is built at run time, a Call Workflow Tool with an expression target, a DELETE tool behind a public webhook, and a disabled send-and-wait approval node. Two reserves: a read-only GET tool and an allowlisted MCP Client Tool write. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d reserve for Cut B (#456) A triage root with an Agents SDK handoff to a billing sub-agent: a write added on the sub-agent, handoffs resolved from an environment route list, and an approvals sub-agent that decides the refund requests the root submits. One reserve adds a scoped read on the sub-agent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ntory (#456) Fifteen synthetic gap slots move to pinned with target_basis constructed_design, exposure none and their CASE.md as evidence; the register gains one row per construction and three reserve rows; the summary tables and the shape prose are recomputed from the CSV. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n for Cut B (#456) 2026-W36-cutb: 912 rows over 21 repositories, the first post-#403 run. Every n8n repository this project had never mined, eight unwalked MCP servers, and closed-unmerged / reverted / named PRs from the new miner states. Labeled from the PR diffs as one session's Cut B cell-targeting labels, not adjudicated. Named off the *-mined glob because it is a selected, capability-dense sample (trigger-skip 0.71), not the unselected history the cross-run noise-bound guard measures; the README says why. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Eighteen slots pinned from 2026-W36-cutb: seventeen of the eighteen gaps Cut B session B owned, plus a third google_adk x insufficient_evidence slot because adk-python#6605 turned out to be engine_tests exposure. Every rejected_or_reverted slot is filled from five repositories; n8n has its first two real-history candidates. The guard gains a `reverted` state (landed history whose rejection came afterwards) mapping to rejected_or_reverted only. langchain_crewai.insufficient_evidence.1 stays a gap with the re-mine's findings as its lead. Summary tables recomputed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Conflicts in the inventory CSV and register resolved by union: each session's rows taken from the session that claimed them, the summary tables recomputed from the merged CSV. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…read the shape after Cut B (#456) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
pengfei-threemoonslab
left a comment
There was a problem hiding this comment.
Changes requested. I found three failures in the new blind-rater boundary. The targeted miner/rater/inventory tests and Ruff checks pass locally, and the full Agents Shipgate verifier routes the protected-surface changes to human review, but these cases are not covered by the current tests.
-
[P1] Verify the packet manifest before launching a rater (
benchmark/safety-qualification/rater/run_rater.py:421-452)._check_packet()only checks that five paths exist and parsesMANIFEST.json; it never callsbuild_packet.verify_manifest()or otherwise re-hashes the packet. Any edit torepo/,diff.patch,LABELING.md, orTASK.mdafter packet construction is therefore accepted, while the emitted label records the hash of the stale manifest. This breaks the claimed content binding and can turn a contaminated packet into admissible evidence. Please verify the manifest immediately before constructing the invocation and fail closed on any mismatch. -
[P1] Do not reuse the caller's real
CODEX_HOMEin isolated mode (benchmark/safety-qualification/rater/run_rater.py:252-258). The default OpenAI path setsHOMEto a temporary directory but then pointsCODEX_HOMEback at the caller's real profile. Codex reads globalAGENTS.md/AGENTS.override.mdfromCODEX_HOME, and user-levelconfig.tomlcan configure MCP servers, plugins, and web search. Official references: https://developers.openai.com/codex/guides/agents-md and https://developers.openai.com/codex/config-reference. Consequently this session is not blind and is not limited to the packet, even though the mode is namedisolated. Use a fresh Codex home containing only the minimum authentication material (or requireOPENAI_API_KEY), explicitly disable inherited MCP/plugins/web search, and use an ephemeral session. -
[P1] Reject or contain symlinks in packet source trees (
benchmark/safety-qualification/rater/build_packet.py:151-156,:374-382).copy_tree_excluding()preserves symlinks verbatim, whilehash_packet_files()deliberately skips them. A repository symlink can therefore point outside the packet, be followed by the rater's read tools, and expose unmanifested host content. This contradicts the "entire world"/exact-input guarantee. Please either reject symlinks, or resolve and copy only targets proven to remain inside the source tree and include their bytes in the manifest.
Once these boundaries are closed, the rest of the reviewed miner/inventory work looks well-covered by the added tests.
Review findings on #489, all in the Cut C rater harness. 1. The packet is re-hashed at launch. _check_packet() proved five paths existed and parsed the manifest; it never compared the packet against it. Any edit landing after the build -- a note under repo/, a rewritten guide, a doctored diff -- reached the rater while the label recorded the hash of a manifest describing a packet that no longer existed. prepare() now calls verify_manifest() and refuses before a session is launched. 2. Isolated mode gives codex its own home. HOME was replaced and then CODEX_HOME pointed back at the caller's real profile, which is where codex reads global AGENTS.md, AGENTS.override.md, and a config.toml that can mount MCP servers and enable web search -- so the mode named isolated was neither blind nor packet-limited. It now builds a fresh Codex home per run holding one written config (no MCP servers, web search off, read-only sandbox, no approvals, no history) and authenticates through OPENAI_API_KEY, symmetric with the Claude path; shared mode keeps the real profile only after proving it is silent. 3. Symlinks cannot carry unmanifested content. The copy preserved links verbatim and the hasher skipped them, so a link out of the tree was content the rater's read tools resolve and the manifest cannot describe -- and the packet still verified. A link that escapes the tree or dangles now refuses the build; one that stays inside is materialised so its bytes are hashed; a link found in a packet is tamper, not a skip. Each fix is covered by tests that fail without it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Thanks — all three are real, and each is fixed in f7873b2 with a test that fails without the fix. I checked that by reverting each fix in turn and confirming the new tests go red. 1. Verify the manifest before launching a rater. 2. Do not reuse the caller's real One caveat I want to keep visible rather than bury: the OpenAI path is still unverified end to end, because the local codex install has an empty vendor binary directory. The config keys come from the reference you linked, and the module docstring now says they must be checked with 3. Reject or contain symlinks in packet source trees. Both halves are closed. A link that escapes the source tree or dangles refuses the build outright, with nothing written. A link that resolves inside the tree is materialised — copied as a regular file — so its bytes are in the manifest, and no link survives into a packet. Full suite and |
Summary
Cut B of #456, staffed as three parallel sessions coordinating through the strata inventory CSV, plus the Cut C preparation that was to run alongside it. The inventory goes from 26 of 59 slots sourced to 59 of 60: 32 sourced qualifying-origin slots (floor 23), 27 synthetic (ceiling 33), every cell still holding a holdout-eligible slot. The one open slot is
langchain_crewai.insufficient_evidence.1, whose lead now records what the re-mine found.strata-inventory.md,test_strata_inventory.py): constructions live atbenchmark/safety-qualification/constructed/<case>/{CASE.md,base,head}and never undersamples/; aconstructed_designbasis with a guard (the trees differ,CASE.mdsits outside both, no engine output inside, no name shared with a sample, a by-nameengine_testsdetector); one pin form per origin, including closed-unmerged (fork point →refs/pull/N/head) and reverted PRs; and the claim protocol. Perturbation-swept: eight violations fail closed, the two valid shapes pass.syntheticgap, across all seven profiles. Each is a plausible PR in the framework's own idiom with the design record beside the trees.2026-W36-cutb.*: 912 rows over 21 repositories, including the four n8n repositories this project had never mined and eight unwalked MCP servers. The miner gains--state closed|revertedand--pr Nenumeration for the rejected vein. 17 of 18 real-history / rejected-or-reverted slots claimed, six of themrejected_or_revertedfrom five repositories. Real history enters as sweep-then-miner-label so the slots stay holdout-eligible; the reason is written down in the register.calibration.md, four reserve PRs plus one construction),LABELING.mdrestructured with a rater-facing four-way rubric on top and the miner process below, the rater packet builder and both session harnesses (benchmark/safety-qualification/rater/), and 39 tests.Type
src/changesVerification
CI is authoritative for
python -m ruff check .,python -m compileall -q src tests, andpython -m pytest.Additional local checks run:
pytest -n auto -m "not perf" --ignore=tests/test_adapter_static_only.pyon the merged branch: exit 0;tests/test_adapter_static_only.py: exit 0;ruff check .: clean.base/andhead/tree: zero hits; no engine output inside any tree.CASE.mdinside a tree, report inside a tree, wrongevidence_ref, underived split,sample_designon a construction, construction named intests/, name shared with a sample): all fail closed.Things a reviewer should know
LABELING.mdis the file Amendment 1 names as the rater input, and this PR changes it. The oldstripe/ai#232worked anchor stated a corpus case's label and verifier verdicts, which condition 2 forbids a rater to see; it is replaced by constructed illustrations, andtests/test_labeling_guide_is_rater_safe.pykeeps every inventory candidate and everySHIP-check ID out of the guide. The draftedreview_requiredvsinsufficient_evidencerule is a first draft for the calibration round to test.claude loginneeded); the OpenAI runner is written againstcodex execflags from memory because the local codex npm install has an empty vendor binary directory. Packets hand raters the head tree plus the diff as "the pinned repository state"; say if the base tree should ship too.google/adk-python#6605isengine_testsexposure (it was reduced into a trigger fixture before this cut read it), sogoogle_adk × insufficient_evidencegained a third slot to keep a holdout-eligible case. The four calibration PRs are struck from the reserve: chosen by someone who has read the inventory, they can never be corpus cases.*-minedglob on purpose. Its selected-PR mix (closed, reverted, named) would drop the cross-run trigger-skip rate below the noise-bound test; the README run note explains. Its labels are one session's cell-targeting labels, not adjudicated, and the README says so.scanpasses a published-but-undeclared write (onlyverify --basecatches it); n8nhuman_review_nodesare collected and never consumed, so disabling the only approval node ismergeable;SHIP-MCP-PERMISSION-EXPANDEDnames the sibling whose binding hash moved rather than the added tool; n8n non-GET nodes are forced toexternal_communicationso a declaredwritelands ininsufficient_evidence; every manifest touch isSHIP-VERIFY-TRUST-ROOT-TOUCHED; n8n node names with spaces alone forcereview_required;initwritesCHANGE_MEand scan exits 2 on every TypeScript MCP server; Go servers on mcp-go / go-sdk read 0 tools; SDK example repositories nowinit_skipwhere the W24 sweep evaluated them.Release-readiness notes
benchmark/, already network-touching by design)docs/checks.md— none changedSTABILITY.md— none🤖 Generated with Claude Code