Grade the local boundary stop and make the Stop hook follow control.state (contract v19)#291
Open
pengfei-threemoonslab wants to merge 5 commits into
Open
Grade the local boundary stop and make the Stop hook follow control.state (contract v19)#291pengfei-threemoonslab wants to merge 5 commits into
pengfei-threemoonslab wants to merge 5 commits into
Conversation
…rify The local check previously collapsed every require_review violation into the same human_review_required hard stop as block — a CLAUDE.md comment, an unknown settings key, and a critical grant expansion were operationally identical. The graded mapping routes require_review sets that are entirely low/medium risk to control.state=agent_action_required with the exact verify command; the review obligation is preserved in a new additive pending_review[] field on the agent-boundary result and re-asserted by PR-time verify, whose release-decision semantics are unchanged. Fail-closed exclusions keep the human stop for: block actions and critical risk anywhere in the set; BOUNDARY-INPUT-INCOMPLETE and unparseable parse-failure evidence (unknown content is not reviewable content); CODEX-AGENTS-SHIPGATE-REQUIREMENT-REMOVED (gate weakening); every gate-governing trust-root class (manifest, policy, ci_gate, shipgate_state) so a composite diff bundling a safe append with an unsafe manifest edit still routes to a human; and experimental adapter surfaces. The trust-root table moves to core/trust_roots.py (checks.verify re-exports it) so the boundary evaluator classifies paths from the same data without an import cycle. pending_review lives on AgentBoundaryResultV1 only — the deprecated codex-boundary v2 format stays byte-frozen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Claude Code Stop-hook block forces the agent to keep working, so blocking on any non-passed release decision was backwards twice over: human_review_required (must_stop=true) means the turn must END so a human can take over, and review_required with a pending agent action deserves a route, not a lecture. The hook now mirrors the operational contract: complete ends the turn silently; agent_action_required blocks once and names the one exact remaining command; human_review_required prints a hand-off notice and lets the turn end. Unparseable or unrecognized verifier output warns loudly, is never cached, and is never treated as passing. The cold-start no-manifest case advises verify --preview instead of forcing continuation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Runtime contract 18 -> 19 documents the graded local boundary stop and the control-state-driven Stop hook. minimum_control_contract_version stays 14: the AgentControl union, its fixed must_stop/completion_allowed literals, and the release gating signal are untouched, so every >=14 consumer keeps working. pending_review[] ships additively on the regenerated agent-boundary-result-schema.v1.json; the deprecated codex-boundary v2 schema stays byte-frozen. Version 0.16.0b6 -> 0.16.0b7 swept across pyproject, __init__, plugin manifests, marketplace, .well-known, llms.txt, doc stamps, wheel-guard tests, and the codex boundary goldens; STABILITY gains the 0.16.0b7 migration note and CHANGELOG the three graded-stop bullets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ci-recipes/advisory-pr-comment.yml templates {{ shipgate_version }}, so the
version bump changes its rendered bytes: EXPECTED_CLAUDE_CODE_SKILL_RENDER_SHA256
advances to the b7 render and the outgoing b6 hash joins prior_render_sha256 so
kit updates recognize previously installed copies as managed. Hashes verified
byte-exact against the template for both versions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR #274 expanded fail_on_merge_verdicts to include human_review_required and insufficient_evidence, but no verifier mechanism can clear a human_review_required merge verdict (human_ack is decision-inert, checks.ignore is category-blocked for SHIP-VERIFY-*, and a baseline never changes the review branch) - so every trust-root-touching PR, including routine release pin sweeps that bump the plugin manifests, fails CI permanently. The verdict's own rationale says release is allowed and the human reviewer should weigh in; the PR review is where that human weighs in. Both advisory workflows now fail only on blocked and unknown (fail-closed against parse/contract breakage). Review routing stays fully visible in the uploaded verifier artifact, and the GitHub Action's own defaults are unchanged. Reviewed and approved by Pengfei in-session before commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
shipgate checkpreviously projected everyrequire_reviewviolation onto the samehuman_review_required+must_stop: truestate as ablock— a CLAUDE.md comment, an unknown.claude/settings.jsonkey, and a critical grant expansion were operationally identical, which routinely hard-stopped coding agents on user-requested benign edits (2026-07-26 governed-loop UX review). Arequire_reviewset that is entirely low/medium risk now projectscontrol.state: "agent_action_required"with the exact verify command; the review obligation is carried in the new additivepending_review[]field onshipgate.agent_boundary_result/v1and re-asserted by PR-time verify, whoserelease_decisionbranching is byte-identical.blockaction orcriticalrisk in the set;BOUNDARY-INPUT-INCOMPLETE; parse-failure evidence (allow-list polarity — only the parseableunknown_host_config_keycase is band-eligible, so new evidence kinds default to the stop);CODEX-AGENTS-SHIPGATE-REQUIREMENT-REMOVED(gate weakening); experimental adapter surfaces; and every gate-governing trust-root class (manifest,policy,ci_gate,shipgate_state) — preserving the Allow coding agents to author safe tool-source proposals #282 composite-diff guarantee that a safe manifest append bundled with an unsafe manifest edit still routes to a human (its both-orderings regression test caught an earlier draft of this change).control.state, not the release label. A Claude Code Stop-hookblockforces the agent to KEEP working, so blocking on any non-passeddecision was inverted twice:must_stop: truemeans "end the turn and hand off". The hook now ends the turn silently oncomplete, blocks once with the one exact remaining command onagent_action_required, and prints a hand-off notice and lets the turn end onhuman_review_required. Unparseable/unrecognized verifier output warns loudly, is never cached by the verified-signature short-circuit, and is never treated as passing; the cold-start no-manifest case advisesverify --previewinstead of forcing continuation.core/trust_roots.py(checks.verifyre-exports; fixes thechecks.verify → core.context → core.agent_boundarycycle the boundary evaluator would otherwise create).pending_reviewlives onAgentBoundaryResultV1only, so the deprecatedcodex-boundary-jsonv2 schema stays byte-frozen;agent-boundary-result-schema.v1.jsonregenerates additively under/v1per existing convention (P0: prove actual agent-to-tool bindings #268, P0: Make the agent control contract unambiguous #270–P0: make verification identity and portable execution reproducible #273). Contract 18→19;minimum_control_contract_versionstays14(theAgentControlunion and its fixedmust_stop/completion_allowedliterals are untouched). Version0.16.0b6 → 0.16.0b7swept across pyproject, plugin manifests, marketplace,.well-known,llms.txt, doc stamps, wheel-guard tests, and the codex boundary goldens; STABILITY gains the 0.16.0b7 migration note.tool_use_id) is the sanctioned follow-up.Type
Verification
CI is authoritative for
python -m ruff check .,python -m compileall -q src tests, andpython -m pytest.Additional local checks run:
pytestsuite green (exit 0) after each phase;ruff check .andcompileallclean.agent_action_required+pending_review[](previously hard stops); MCP-server add,shipgate.yamledit, and AGENTS.md verifier-requirement removal → stillhuman_review_required;fixture run ai_generated_refund_pr→ stillblocked.complete | agent_action_required | human_review_required | garbage | unknown-state→ silent / one-shot block with exact command / hand-off systemMessage / uncached warning / uncached warning;stop_hook_activere-entry guard intact (5 new tests intests/test_install_hooks.py).finding_fingerprints/audit_idstability: no rule action/risk values changed, so boundary fingerprints do not churn; only theunknown_permission_keygolden's control block flips, all 8 goldens re-stamped for0.16.0b7.scripts/generate_schemas.pyandscripts/build-llms-full.pyre-run to zero diff; schema-roundtrip and public-surface-contract suites green.Release-readiness notes
docs/checks.md(no check IDs added or removed; local control mapping only)STABILITY.md(additivepending_review[]on agent-boundary v1; migration note 0.16.0b7; report/packet/verifier/handoff versions unchanged)🤖 Generated with Claude Code