Stop an empty preflight plan from granting merge and completion (#610) - #925
Open
pengfei-threemoonslab wants to merge 1 commit into
Open
pengfei-threemoonslab wants to merge 1 commit into
pengfei-threemoonslab wants to merge 1 commit into
Conversation
A preflight plan that named nothing to route returned the shared `complete` state, whose permission vector grants `merge` and `report_complete`, with no verifier run or current-control identity behind it. The published 0.5 schema also refused that payload, because it pinned `update_pr` to false. Preflight 0.6 gives `control` its own union: the new `planning_complete`, `agent_action_required` and `human_review_required`. `planning_complete` owes no action and authorizes nothing. `complete` and `review_publishable` cannot appear, and every permission is false on every route, in the model and the generated schema alike. The shared AgentControl union is unchanged, so minimum_control_contract_version stays 21. - Both base-preflight readers now parse through one version ladder (`parse_preflight_result`). A stored 0.5 answer still reads as 0.5. - The hook script accepts preflight 0.5 and 0.6. - The adoption scorer reads `planning_complete` as itself. - The CLI text says the result authorizes nothing. - Contract 41 -> 42. Preflight 0.5 is frozen and pinned by digest. Docs, STABILITY migration note and CHANGELOG are updated. The Route H dry run was re-run on contract 42. - AGENTS.md edits were approved by the owner in conversation on 2026-10-01. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Why
A coding agent that asked preflight about a plan naming nothing —
{"changed_files": []}, no flags at all, orshipgate.preflightwith no arguments — got back the sharedcompletestate, and that state's permission vector grantsmergeandreport_complete, with no verifier run and no current-control identity behind it. Leaving files out of a plan therefore read as merge authority. The published0.5schema also rejected that very payload, because it pinnedupdate_prtofalse.Reproduced on this branch's base (
0e98f41d, contract 41):A README-only plan already returned
agent_action_requiredwith an exactverifyroute and every permission false; the defect was only the empty-plan route.What changes
The owner chose planning-only completion with no publication or merge authority (#610 comment,
docs/research/application-days1-5/README.md). This PR implements that across the model, schema, projections and consumers:0.6(PreflightResultV6,docs/preflight-schema.v0.6.json) givescontrolits own union:planning_complete(new),agent_action_required,human_review_required.completeandreview_publishablecannot appear.planning_completemeans only that planning finished: nonext_action, no commands,completion_allowed/must_stop/verify_requiredfalse, and a required, all-falsepermissions. Its reason says it is not a verification and authorizes nothing.falseon every preflight route, enforced by a model validator and anallOfrule in the generated schema (which also requires the vector to be present). The schema mirrors each route's legacy projection, so the runtime payload and the published grammar agree for empty, verify-required and human-review plans.AgentControlunion is untouched (it is embedded by six durable schemas).minimum_control_contract_versionstays21: a reader that does not knowplanning_completecannot mistake it forcomplete, and the vector beside it denies everything.--base-preflightreader kept its own copy of the version dispatch, which would have refused a saved0.6answer. Both readers now go throughparse_preflight_result. A stored0.5answer still reads as0.5(completeincluded); relabelled0.6, it is refused.install-hooksscript accepts preflight0.5and0.6. A hook written before this change accepts only0.5, so its instruction-structure check fails closed untilinstall-hooks --writeis re-run. This is documented in the migration note.planning_completeas itself, rather than as an unexecutableagent_action_requiredobligation.Authorizes: nothing (only verify can authorize merge or completion).0.5is frozen and pinned by digest inFROZEN_CONTROL_SCHEMAS. Docs updated: STABILITY migration note, CHANGELOG,agent-contract-current.md,.well-known, INDEX,llms.txt/llms-full.txt, MCP/protocol docs and the per-agent guides.AGENTS.mdgains oneplanning_completesentence in the preflight paragraph, and its schema-table row moves to0.6. Owner approved both edits in conversation on 2026-10-01, as preflight routesAGENTS.mdto human review.main(contract 41). Cells are identical apart from the contract number; preflight is not one of that route's cells.Acceptance (from #610)
planning_completewith every permission false; the docs-only plan still owesverify.completeshape, a missing vector, a planning result that owes verify, a publishing verify route, a human route granting merge, andreview_publishable.planning_completestate, beside an all-false vector.0.5completeanswer used as a base cannot clear a protected-surface, docs-only or empty plan.Validation
tests/test_preflight_planning_only.py(new, 30 tests) and a harness scorer test (tests/harness/test_detectors.py). The scorer test fails without the scorer change, which was checked.ruff check .,git diff --checkandscripts/generate_schemas.py --checkall pass.-n auto -m "not perf" --ignore=tests/test_adapter_static_only.py): everything passes except twotest_check_unmodelled_host_config_keys.py[local_settings_enabled_plugins-*]cases. Those fail only on this machine, whose global gitignore hides.claude/settings.local.jsonfrom the fixture's commit, and they pass withXDG_CONFIG_HOME=<empty dir>. The separately run CI files (test_adapter_static_only, both P0 canary files,test_agent_boundary) pass. The self-review fixes after the full run are a refusal of a non-object base and a wording change; the affected files were re-run.Closes #610
🤖 Generated with Claude Code