Adaptive planning¶
The fixed AutoPlanner sequence sends every build request through the same stages, whatever its size:
recognize → requirements → plan → review → revise → final review → your approval
A one-line change pays for six model calls before you see a plan. A plan the Plan Reviewer has no objection to is still revised and reviewed again. A hard plan gets exactly one revision, and whatever the Reviewer still objects to comes back to you as questions.
Adaptive planning lets the evidence decide how much planning a request gets
instead. It is on by default for new runs that use joint planning on the
default planning flow (since 2026-10-02, after the two live comparisons below
found fewer model calls and questions with the same plan quality).
--no-adaptive-planning keeps the fixed sequence for a new run, and
--adaptive-planning insists on adaptive planning, refusing a run that cannot
use it. A saved run keeps the planning flow it was started with. It does not
predict the job's size up front. Each decision is made by the first stage that
has the evidence for it:
| Decision | Made by | Evidence | Effect |
|---|---|---|---|
| Does the request need requirements gathering? | Job recognizer | The request text: does it say what to build and how to tell it is done, with no product choice left open? | clear build requests go straight to the Planner; vague ones keep the Requirements stage. When unsure the recognizer says vague. |
| Is the plan finished? | Plan Reviewer | Its own concerns, each marked blocking or not | No blocking concern: an ordinary Planner draft goes to you, with the non-blocking concerns as notes. Otherwise the Planner revises. Progressive delegations keep revision and final independent review, which supply their approval authority. |
| How many review rounds? | The runner | The draft's declared milestones and the files they touch (plan_size) |
A large plan (3+ milestones or 10+ files) gets 3 review calls instead of 2, so a revision is reviewed again before the final decision. |
| Does feedback on a plan need requirements gathering? | The runner, then the Planner | The run's status: a complete plan waiting for your approval | The Planner revises the plan you were shown, then the Plan Reviewer reviews it. The Planner can send feedback that changes what is being built back to Requirements. See below. |
For this to work, the Planner's draft includes its initial_task (the first
Builder task). In the fixed sequence only the final review writes one.
What does not change:
- You approve every build plan. Adaptive planning removes model calls, never your approval.
- A build named with
--workflow buildskips recognition, so nobody judges its clarity and the Requirements stage always runs. - The setting applies only to new runs. A saved run keeps the planning flow it
was started with: resuming with
--adaptive-planninga run that lacks it, or with--no-adaptive-planningan adaptive one, is refused. Repeating the run's own choice, or passing no flag, is fine. - Questions work as before. On the fast path the Planner asks them itself.
- The Tester and Completion Reviewer still judge the work, and bug-fix, review, design and discuss workflows are unaffected.
- A plan that the Reviewer does block on takes today's path: revise, then a final review that settles every concern.
Where it lives: tools/autocode_adaptive_planning.py holds the decisions as pure
functions. units/autoplanner.py (schema_for, after_challenge,
after_revise, rerun_requirements), autocode_workflows.apply and
autocode_goals.feedback apply them. State: workflow.clarity,
workflow.requirements_skipped, planning.adaptive (size, signals,
review_limit, challenges, approved_at, final_stage), and revises_plan
on a feedback event. autocode --status --json shows the decisions under
planning_depth (task-run interface): the clarity, whether
Requirements was skipped, the plan's size, the review allowance and whether the
Plan Reviewer approved the draft early.
Feedback on a plan you were shown¶
Without adaptive planning, feedback on a plan (--feedback, or typing a change
in chat) restarts planning from the top, however small the change:
your feedback → requirements → plan → review → revise → final review → your approval
In an adaptive run, feedback sent while a complete plan waits for your approval goes to the Planner, which revises the plan you saw:
your feedback → plan (revises the plan you saw) → review → your approval
The review works as for any adaptive draft: with no blocking concern the plan comes back to you; otherwise it is revised and reviewed again. Feedback at any other point (while questions are open, or queued during a build) still restarts from Requirements.
Requirements is skipped because its job was done for the request you already planned; your feedback changes that plan. Three checks keep the shortcut safe:
- The runner checks the revision delivers your feedback. Your feedback becomes a requirement the Planner must trace, like the ones the Requirements stage writes: covered by an acceptance criterion or required behavior of the new plan, or the draft is rejected. This needs no model call. It stays a traced requirement until a Requirements report takes it in.
- The Planner can send it back. If your feedback changes what is being built
(a different product, user or outcome, not an added or changed behavior), the
Planner says so instead of revising (
requirements_rerun), and the runner discards that draft and runs the Requirements stage. "Make it a web page instead of a command-line tool" is the example in the comparison corpus. - The Plan Reviewer still reviews the revision, and is told to check that your feedback is applied as you said it and that nothing you asked for earlier was lost. The runner's existing guard already refuses a revision that drops or rewords a protected item (a criterion, behavior or exclusion) without citing your feedback.
You still approve the revised plan.
Comparing it with today's pipeline¶
scenarios/run.py plan-compare plans each request in scenarios/planning.toml
twice, once with today's pipeline and once with --adaptive-planning. Each run
starts in a fresh copy of the request's seed and stops when AutoCode shows the
plan for approval. A request with feedback then sends that feedback instead of
approving, and stops at the next plan shown for approval; the feedback round is
reported in its own columns. Nothing is built. The driver answers questions with
AutoCode's proposed default, the same way for both variants.
PY=.venv/bin/python
$PY scenarios/run.py plan-compare --fake # plumbing: every adaptive path, scripted, seconds
$PY scenarios/run.py plan-compare --profile default --jobs 3 --i-authorize-live-model-spend
The evidence directory holds comparison.md (stages, review calls and blocking
concerns, questions, tokens, model time and plan shape per request and variant),
records.json, each run's state.json, and blind/. blind/ has each
request's two final plans side by side as Plan A and Plan B, with the key in
blind/key.json, so plan quality can be judged without knowing which variant
wrote which.
Results: live comparison with feedback, 2026-10-02¶
Each of the 11 requests in planning.toml was planned once per pipeline on the
default routes (Requirements and Planner on GLM 5.3, Plan Reviewer on GPT-6 Sol).
After the first plan, each run got the request's feedback instead of an approval
and went on to the next plan shown for approval. The code under test was the
feedback path above plus the re-review context for answered questions
(feat/rereview-after-answers). Evidence:
.scenario-runs/20261002T091307Z-plan-compare-default-ac6a8qs0 (not committed;
blind/verdicts-before-key.md holds the verdicts written before the key was opened).
| Today | Adaptive | Change | |
|---|---|---|---|
| First plan: plans reached | 11/11 | 11/11 | |
| model calls | 112 | 95 | −15% |
| questions to the user | 26 | 16 | −38% |
| Feedback round: new plans reached | 9/11 | 9/11 | |
| model calls | 85 | 50 | −41% |
| plan-review calls | 26 | 15 | −42% |
| tokens in / out | 5.45M / 1.05M | 4.50M / 0.63M | −17% / −40% |
| model time | 267 min | 157 min | −41% |
The first-plan numbers repeat the 2026-09-30 comparison (−15% calls, −37% questions). Four adaptive feedback rounds took two calls: the Planner revised the plan and the Plan Reviewer approved it at once.
Plan quality after the feedback was the same. Judged blind on whether the feedback was applied as stated and the rest of the plan kept: adaptive better in 3 pairs (deployment-planner, tenant-http-api, transactional-outbox), today's pipeline in 3 (small-json-flag, vague-reading-list, vague-timesheet-useful), 5 ties. Both pipelines sometimes added criteria nobody asked for.
Where the adaptive path fell short:
vague-reading-list("make it a web page instead of a command-line tool"): the Planner produced no output for 300 seconds three times and the run stopped for a person, so the send-back to Requirements was never exercised live. A large change can exceed the idle limit before the Planner writes anything.vague-timesheet-useful: the revision appended a section to the default report although the feedback said to keep that output exactly as it is, and the Plan Reviewer did not object.- Planner slips on the feedback path, each costing a report repair: a
conflict_resolutionsentry for a feedback-versus-plan conflict (2 runs; the Planner rule now says to usecontract_changesinstead), a blank feedbackanswer_idon an assumption (2 runs), and contract changes named by list instead of by item.
Today's pipeline missed a new plan twice: deployment-planner (both pipelines
stopped for a person) and transactional-outbox (an Resolver blocker,
"Planning recovery scope or inputs changed").
Earlier attempts at this comparison, stopped and restarted, found four Planner
slips, each fixed on this branch or an accompanying one: a trace row without its
requirement_id (now named by the runner when only one requirement can be meant;
this branch), example_correction: null refused by the schema
(fix/example-correction-null), a declared change whose item was wrapped in its
list name (fix/contract-change-item-refs), and report fields written inside the
contract (feat/rereview-after-answers).
Results: live comparison, 2026-09-30¶
Each of the 11 requests in planning.toml was planned once with each pipeline
on the default routes: Requirements and Planner on GLM 5.3, Plan Reviewer on
GPT-6 Sol. That is one sample per request, and the same request can swing by
several calls from run to run, so read per-request differences as noisy. The
evidence is under .scenario-runs/20260930T180620Z-plan-compare-default-*
(not committed).
| Today | Adaptive | Change | |
|---|---|---|---|
| Plans reached (no errors) | 11/11 | 11/11 | |
| Model calls | 92 | 78 | −15% |
| Clear requests (8) | 64 calls, 7 questions | 52 calls, 1 question | −19% calls |
| Vague requests (3) | 28 calls, 9 questions | 26 calls, 9 questions | about even |
| Plan-review calls | 27 | 27 | same |
| Questions to the user | 16 | 10 | −37% |
| Model time | 160 min | 128 min | −20% |
| Tokens in / out | 3.58M / 734k | 2.93M / 566k | −18% / −23% |
Plan quality was about the same. Each pair was judged blind (Plan A and Plan B, key opened after every verdict was written) against the request and, where the request came from the catalog, against the hidden oracle tests. Adaptive was better in 3 pairs, today's pipeline in 2, and 6 were ties.
- Adaptive better:
parallel-diamond: today's plan invented "raise ValueError for an unknown node", which a faithful build would fail on two oracle checks.transactional-outbox: only the adaptive plan tested concurrency across separateStoreinstances, which is what the hidden test does.feature-by-project.- Today better:
vague-timesheet-useful: the adaptive plan changed the default report output despite the answer "keep existing behavior intact".tenant-http-api, slightly.
In each lopsided pair, the weaker plan had been through the same full review-revise-final cycle. So these look like model variance, not an effect of the pipeline.
Where the savings came from:
- Skipping Requirements for clear requests. Nearly all of the question savings are here (7 questions → 1 on clear requests).
- Fewer planning restarts: 3 today, 1 adaptive. Most began when a revision renamed a protected contract item; the guard then asks the user, and planning starts over.
The live recognizer judged every request correctly: 8 clear, 3 vague.
What did not pay off as designed:
- Early approval rarely fires. The Reviewer blocked on the first draft in
21 of 22 runs, usually on real test gaps. Adaptive approved early only
twice: once at the first review (
tiny-greeting), once at a re-review (deployment-planner). - The size rule over-fires. "10+ acceptance criteria" made 6 of 11 plans
large, 3 of them single-milestone changes, which gave them a third review
call. Those extra rounds did find real gaps (for example in
extend-record-query), but they are why review calls came out even. Fixed after the run: size now comes from milestones and files only, which would have made onlyparallel-diamondlarge. - More bad citations. Planner revisions cited the Reviewer's own report
under
.autocode/as evidence, and the report was rejected and repaired. This happened 3 times, all on the adaptive side, and 2 of them followed a second review. Since fixed for both pipelines by #192's SOURCE CITATIONS rule (merged after this run), which every planning stage after Requirements receives.
Found in both pipelines:
- The protected-item guard turns test-name renames into user questions and full planning restarts. #192 (merged after this run) now tells the Planner to keep existing test names; its effect is not measured yet.
- Planning restarts after a deferred approval are unbounded
(
docs/bugs/2026-09-30-unbounded-planning-restart.md).