Commit Graph

6 Commits

Author SHA1 Message Date
kingwl b29aeb1847 fix(stdio): /mode is reserved even while a question prompt is active
Review finding at the seam of two surfaces this branch added to the
same stdin: with an ask_user_question (or plan-review) prompt active,
the line handler dispatched every line as the answer first, so
'/mode plan' typed mid-question was recorded as free-text feedback —
model-visible in the tool result — and the mode never changed. Command
handling now runs before answer dispatch: the command executes, the
question stays pending and still owns the next non-command line. A
literal '/mode…' free-text answer is the trade-off deliberately spent —
a swallowed command that becomes review feedback costs far more than
that contrived answer shape.
2026-07-10 19:17:45 +08:00
kingwl 3025fbaeb3 fix(mode): prepend the assemble filter; structured_output joins the plan allowlist
Review finding with a real in-repo instance: the structured runtime's
per-spawn final-assembly wrapper (prepend, post-next) re-injects
structured_output OUTSIDE the mode filter, so a structured child in
plan mode would see a tool the gate then denies — the soft policy and
the hard gate telling different stories. The suggested fix (make the
mode filter outermost) cannot beat that instance: prepend unshifts, so
the per-spawn listener always registers later and wraps outer.

Two-part resolution instead. Semantically, structured_output enters the
shipped plan allowlist — it is a child's pure result channel, the same
ask/report class as ask_user_question and exit_plan_mode, so the
filter, the re-injection, and the gate now agree wherever a structured
child runs in plan mode. Mechanically, the filter registers with
prepend anyway: it now wraps outside every append-registered listener
regardless of load order (regression test pins a pre-registered
post-next mutator being filtered), narrowing the documented cosmetic
residual to prepend-after-load listeners only, where the gate still
covers execution. Severity note: no execution breach existed — the gate
held throughout; this closes the prompt-honesty gap.
2026-07-10 18:35:44 +08:00
kingwl 02e0756b78 feat(mode): ask_user_question joins the plan allowlist; the section steers to the exit tool
Live-session feedback (a real Zed elicitation round-trip): the model
presented its finished plan as a plain reply and asked the USER to
switch modes — the exact reversal the roadmap warns about — because the
shipped section's 'present it with the exit_plan_mode tool' read as a
suggestion. The section now says a finished plan is delivered by
calling exit_plan_mode, preferred over pasting it as a plain reply or
asking the user to switch modes — firmer, without imperatives.

ask_user_question enters the shipped plan allowlist (asking is
read-only-safe), and the section points a blocked decision at it. The
plan-acp-agent example composes the bash family (default mode only —
plan's allowlist keeps excluding it, so the two modes now demo a real
difference) plus tool-ask-user; both recorded scenarios re-recorded:
the pin now shows plan = [ask_user_question, exit_plan_mode, read,
todo_write] and post-exit default = the full eight-tool surface.
2026-07-10 15:05:26 +08:00
kingwl 14f7976e3d fix(mode): an approved exit leaves plan mode at the step boundary, not mid-batch
Review finding: the exit tool's direct mode/set append flipped the
folded mode while the loop could still execute further tool calls from
the SAME assistant response — a same-batch exit_plan_mode + write pair
would sail past tools/pre-execute under 'default' even though the
request was assembled under the plan-shaped header. That broke the
design's own invariant (a step's executions run under the mode its
assembly folded), which the pending-intent flush was built to hold for
user flips.

The tool now records the switch as a pending intent like every other
writer, flushed at this step's end (still in-turn); pending intents
carry a narrate flag so the exit's flush stays silent — the tool result
is its narration — while user flips keep the coalesced boundary notice.
The gate, folding the logged mode only, now provably covers the whole
batch: regression test pins approve-then-write-in-the-same-batch as
denied, and the widened toolset still arrives on the next step.

The recorded scenarios are re-recorded: the fixture now shows mode/set
landing after step/end, before the widened fallback header.
2026-07-10 10:35:43 +08:00
kingwl c5cb7da364 test(mode): record the plan-mode approve and keep-planning scenarios
The with-key recording session the RFC deferred. plan-mode is the 'plan'
header class's pinning scenario and necessarily carries BOTH header
shapes verbatim: the plan-shaped initial snapshot and the widened
fallback snapshot the approved exit produces mid-turn — so the suite
factory's pin guards relax from exactly-one to at-least-one header (the
classmates' uniformity anchor is the pin's FIRST header; transition
headers are legal only in the pin, matching the sandbox stack's
precedent). plan-mode-reject pins the keep-planning branch: the
corrective isError carries the reviewer's free-text feedback verbatim
and the session stays in plan mode, one header, uniform with the pin.

Recording notes, encoded in the prompts: the model is pinned to RELATIVE
paths (a recorded absolute temp path neither replays on another host nor
normalizes — the normalizers scrub the run's own cwd, not the
recording's), and the recorded model never calls a filtered tool, so the
gate's deny path stays pinned at the unit tier — that refusal is the
behavior the soft layer exists to produce. The gen-tool-catalog
meta-test pins exit_plan_mode in the harvested schema list.
2026-07-10 03:39:29 +08:00
kingwl 5a8e3a14ee docs(rfc): plan mode to implemented — amendments folded on the way
The proposal survives contact with the code with three amendments, per
the RFCs-are-proposals rule. (1) A mode transition logs a
request/header-delta only when expressible: adding exit_plan_mode
resorts the canonical tool list, and a pure reordering has no delta
form, so entering plan mode logs the full fallback snapshot — the
attributability claim holds either way. (2) The proposed/ skeleton
converts to the implemented grammar: Proposal → Decision, the roadmap's
staging (now history) drops to the standing Deferred list, and
Acceptance criteria + Risks fold into Consequences (what holds, then the
accepted costs, including the ACP v2 mode-removal migration). (3) The
two recorded scenarios stay pending a with-key session, recorded in
Deferred.

The docs tail completes: the cookbook's plan-mode row upgrades from
sketch to the shipped package, architecture.md gains the ctx.modes
capability row (ceiling 1640 → 1650: a new capability service's table
row does not fit the old budget), and every reference repoints to
implemented/.
2026-07-10 03:10:19 +08:00