Compare commits

..

1 Commits

Author SHA1 Message Date
Jesse Vincent
61f669ebc9 fix(sdd): preflight emits its pairwise checks as a ledger table and rules on what it surfaces
The pre-Task-1 conflict scan currently permits 'the scan is clean' with
no evidence the scan happened — mined sessions show controllers skipping
straight to dispatch and plan conflicts surfacing mid-execution as
blocking questions. Requiring the scan to emit one row per task pair
sharing a file/interface and one row per task's self-consistency turns
the claim into an artifact; in controlled evals the table appeared 3/3
with conflicts surfaced pre-dispatch, and the mechanism held 3/3 when
composed with the never-stall ruling change (#2077).

Claude-Session: https://claude.ai/code/session_0185AJr98gHx5EmwqNeft4Sy
2026-08-03 09:03:05 -07:00
2 changed files with 14 additions and 68 deletions

View File

@@ -142,17 +142,24 @@ a ledger file, not only in todos.
Read the plan once, note its context and Global Constraints, and create a
todo per task.
Before dispatching Task 1, scan the plan once for conflicts:
Before dispatching Task 1, scan the plan once for conflicts, writing down
what you checked as you check it:
- tasks that contradict each other or the plan's Global Constraints
- anything the plan explicitly mandates that the review rubric treats as a
defect (a test that asserts nothing, verbatim duplication of a logic block)
Present everything you find to your human partner as one batched question —
each finding beside the plan text that mandates it, asking which governs —
before execution begins, not one interrupt per discovery mid-plan. If the
scan is clean, proceed without comment. The review loop remains the net for
conflicts that only emerge from implementation.
The scan's output is a table, not a verdict. One row for every pair of tasks
that share a file or an interface: the two tasks, what one produces against
what the other consumes, and what you found. One row for every task: whether
its own text agrees with itself — the tests it specifies against the code it
specifies, the files it creates against the files it later touches. "The scan
is clean" without those rows is not a scan you ran.
Write the table to the ledger. Rule on each conflict it surfaces — the spec
is the binding authority, the plan is its argument — record the ruling beside
its row, and dispatch Task 1. The review loop remains the net for conflicts
that only emerge from implementation.
## Model Selection
@@ -197,17 +204,6 @@ Everything you paste into a dispatch prompt — and everything a subagent
prints back — stays resident in your context for the rest of the session
and is re-read on every later turn. Hand artifacts over as files.
**Waiting on dispatched subagents:** never poll a wait interface with
short timeouts, and never sit in one silent, open-ended wait either.
While you have local work — ledger updates, packaging the next review,
reading reports — keep working; child results arrive on their own.
When you are genuinely idle, wait in bounded stretches (five to ten
minutes, where your platform allows), and between stretches post one
line of status and reconcile your live children: list them, and chase
any that finished without reporting. A bounded stretch keeps nearly
all of a long wait's efficiency while guaranteeing a stuck or lost
child is noticed within minutes, not at the end of the session.
### 1. Dispatch the implementer
Record BASE (`git rev-parse HEAD`) before dispatching — the review package

View File

@@ -7,57 +7,7 @@ Add to your Codex config (`~/.codex/config.toml`):
multi_agent = true
```
This enables the multi-agent tools that skills like
`dispatching-parallel-agents` and `subagent-driven-development` use.
Which tools you get depends on the multi-agent version your model
preset selects (current presets run V2; older ones run V1). Trust your
actual tool list over any table — including this one — when they
disagree.
- **Spawning:** give children a clean context with
`spawn_agent {fork_turns: "none"}`; the default `"all"` copies your
entire transcript into the child. On Codex 0.145+, role files under
`~/.codex/agents/` attach to isolated forks via `agent_type`.
Full-history forks accept `model` and `reasoning_effort` overrides
(only `agent_type` is refused there) — isolated forks are the SDD
default for context hygiene, not because overrides require them.
- **Fix rounds:** resume the implementer with `followup_task` — it
delivers your message, triggers a turn, and transparently reloads a
child the harness evicted. Never dispatch a fresh implementer on the
theory that a spawned agent cannot be messaged again; on V2 it
always can.
- **Lifecycle:** V2 has no `close_agent`. Finished children are
evicted automatically when slots are needed; leaving them unclosed
costs nothing. Only V1 sessions have `close_agent` — there, close
reviewers when their review returns, and close each implementer
after its task's review passes.
- **Model names:** never copy a model name from a skill, table, or old
session into `spawn_agent` without checking it against your current
spawn allowlist — V2 accepts only V2-capable presets and hard-errors
on the rest.
## Waiting on children
`wait_agent` is an event subscription, not a poll: a long wait wakes
the moment a child produces mailbox activity, with the same latency as
a short one. Short-timeout polling buys nothing and costs a tool call —
and a context rebill — per poll. In measured sessions, roughly
two-thirds of all wait calls were short polls that timed out.
- While you still have local work, do not wait at all. A completed
child's final answer is pushed into your mailbox and arrives with
your next turn.
- When you are genuinely idle with children outstanding, wait in
bounded stretches: `wait_agent` with `timeout_ms` 300000-600000
(5-10 minutes). After each stretch — wake or timeout — post one
status line, run `list_agents`, and chase any child that finished
without reporting. Never stack polls shorter than five minutes; the
event subscription wakes a bounded stretch just as fast as a short
one.
- Completion mail cannot wake an idle controller (it is delivered
without triggering a turn); covering that idle window is
`wait_agent`'s only job. A stretch that times out with no activity
is your cue to reconcile, not to shorten the next stretch.
This enables `spawn_agent`, `wait_agent`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`. When using subagent-driven-development, close reviewer subagents when their review returns. Keep each implementer subagent open until its task's review passes — the fix loop resumes the implementer — then close it. If your harness cannot send another message to a spawned agent, dispatch each fix round as a fresh implementer carrying the brief, the report file, and the findings.
## Environment Detection