Repository navigation
Enforce a pre-spawn model budget for planning invocations (#163) - #196
Merged
Merged
Conversation
createClaudeCommand now refuses a planning request whose prompt and schema together exceed 64 KiB of UTF-8 (a byte count standing in for tokens, as Claude's tokenizer is not available offline), and passes --max-turns 50 so the run itself is bounded by turns, not only by time and output bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…163) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e count (#163) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… turn-limit detection (#163) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…163) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y phase (#163) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…163) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Both planning recordings require authenticated re-recording because the new command invalidates their fingerprints and breaks replay checks.
1 open issue
What changed in this PR
Adds pre-spawn planning budgets for #163 within the Claude invocation pipeline.
Changes:
- Caps combined prompt/schema input at 64 KiB and planning runs at 50 turns.
- Preserves provider error details and adds turn-limit guidance.
- Documents budget assumptions and adds boundary tests.
| File | Description |
|---|---|
| test/planning-provider.test.ts | Tests turn-limit error guidance. |
| test/planning-author.test.ts | Checks prepared-input budget compatibility. |
| test/agent-policy.test.ts | Tests exact byte boundaries and planning argv. |
| test/agent-adapter.test.ts | Tests early refusal and error decoding. |
| runner/planning-provider.ts | Adds turn-limit retry guidance. |
| prompts/plan-author.md | Updates builder-only budget instructions. |
| docs/implementation/plan-library-alignment.md | Records model-budget implementation. |
| docs/implementation/agent-isolation.md | Documents limits, assumptions, and evidence. |
| agents/policy.ts | Enforces input and turn budgets. |
| agents/adapters/claude.ts | Preserves error text when results are empty. |
Review effort: Balanced
Recorded by the maintainer with scripts/record-planning.ts through the planning container (Claude Code 2.1.281). Both answers validate and replay through E2/E3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mchwang
marked this pull request as ready for review
October 21, 2026 05:25
mchwang
added a commit
that referenced
this pull request
Oct 21, 2026
This was referenced Oct 21, 2026
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.

Closes #163.
What changes
createClaudeCommand(agents/policy.ts) now checks a planning model budget when it builds the command.startClaudeInvocationbuilds the command before it allocates a container or network, so this is before the agent process starts.MAX_PLANNING_INPUT_BYTES). A larger request is refused. The error gives the size, split into prompt and schema, and says what to narrow. Bytes stand in for tokens because Claude's tokenizer is not available offline (labelled as assumed). This equals the 32 KiB + 32 KiB limits thatprepareDraft/prepareSuggestionsalready apply, so it is a backstop for callers that skip them.--max-turns 50(PLANNING_MAX_TURNS). Other phases do not.parseClaudeOutput(agents/adapters/claude.ts) uses the envelope'serrorsstrings as the text when a failed result'sresultis missing or empty. This applies in every Claude phase.planningOutput(runner/planning-provider.ts) names the turn limit when that text includes "Reached maximum number of turns". Every other failure keeps the sign-in advice.docs/implementation/agent-isolation.md. The section records why turns and bytes were chosen, and not tokens or dollars. Also updated: the alignment row inplan-library-alignment.mdand the builder note inprompts/plan-author.md, which is stripped before sending.Evidence for the CLI behaviour
--max-turnsin--printmode even though its help hides it. Checked in the Linux arm64 binary's bundled source.--print --output-format json --json-schema … --max-turns 1. It exited 1 withsubtype: "error_max_turns",is_error: true, noresultkey,errors: ["Reached maximum number of turns (1)"]andnum_turns: 2.parseClaudeOutputon that file returned{ text: 'Reached maximum number of turns (1)', providerFailed: true }. The test fixtures use that envelope verbatim, minus members the parser does not read.Re-recorded planning fixtures
test/planning-recorded.test.tshashes the exact planning argv, so adding--max-turns 50made the old recordings stale. The maintainer re-recordedtest/fixtures/planning/recorded/claude-{draft,suggest}.jsonwithscripts/record-planning.ts, running Claude Code 2.1.281 in the planning container with the new argv. The result is commit 69eb218. OnlycommandSha256,requestId,recordedAtandoutputchanged. The prompt, schema and files hashes are unchanged, and neither file contains any credential text. The hashes were not edited by hand.Validation (head 69eb218)
planning-recorded,agent-policy,agent-adapter,planning-author,planning-providerplanning-recordedfailures. The rest are timing failures inpre-merge/runner-publishing, which this change does not touch; on an isolated rerun a different pair failed. Not a clean gate: CI is authoritative.test,real-docker)planning-recorded(83/84 and 90/91 files passed); at 69eb218 both passed (test, real-docker)Review record
Base
aced300(origin/main) for every round. Each independent round was a fresh general-purpose subagent, reviewing the full diff.errorsfallback (e2a11c6)result:""hiderrors--max-turns 1; docs and comments cite it (f3998cb..98a6d1f)MAX_PROMPT_BYTES. Nit: wraperrorstext reaches every phase (undocumented). L:startsWithfragile. Nit: wrapincludes(0f16acc)Round 13 (
aced300...58df0ce) authorized the first Copilot request. Round 14 (aced300...69eb218) authorizes the re-request.Review-lesson audit
docs/implementation/planning-acceptance.md: a changed Claude argv makes a recording stale, so it must be recorded again, not have its hashes edited.AGENTS.md/CLAUDE.mdchange needed.Follow-ups
--max-turnsinside the Linux container.🤖 Generated with Claude Code