Skill Tracer
Skills › Compound Engineering › ce-retune › halt-taxonomy.md

halt-taxonomy.md

123 lines · skills/ce-retune/references/halt-taxonomy.md at 3449230

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Halt Taxonomy
2

Halt Taxonomy

Raw lines 1 to 2
3## The mechanism
4
5A workflow "phase" is often invoked by loading its instructions into the **same conversation** (a skill load, an include, a prose route to "the review phase") rather than by spawning a separate process. When that happens, the model on both sides of that seam is one model in one turn. In an unattended run there is no second party and no next user message, and a reply that contains no tool call ends the session. So an instruction to return, hand back, or report to a caller has exactly one expressible form at that seam: stop. The prose is not wrong about its protocol. The protocol has no runtime.
6
7**The diagnostic that settles which seams are real.** In the run archive, find one session id whose trace contains *both* phase-invocation calls (skill loads, reads of another unit's `SKILL.md`) and real subagent dispatches. The phase invocations carry the same session id as the orchestrator. That is one conversation and a fictional boundary. The subagent dispatches carry a distinct child id. That is a real boundary that can carry a hand-off. One line of log settles it for the whole corpus. Run this before classifying anything. Class 9 and survival screen 3 both depend on the answer.
8
9If the archive carries no session or child ids (`references/baseline-mining.md` extracts them where it can), substitute the weaker structural test: a seam is real only where the trace shows a **dispatch tool call whose result returns into the parent trace**. A skill load, an include, or a file read is not one. Do not treat an unlabeled trace as evidence of a real boundary. That reading keeps every halt.
11Each class below gives what to grep, why the match halts, and the replacement. Grep terms are starting points for a corpus that never used exactly these words. Read the matches; do not batch-edit them. Case-insensitive, whole corpus including reference files, one class at a time:
13```
14grep -rniE 'return control|hand back|hand off to|the caller (owns|applies)' <corpus-dir>
15```

The mechanism

A workflow "phase" is often invoked by loading its instructions into the same conversation (a skill load, an include, a prose route to "the review phase") rather than by spawning a separate process. When that happens, the model on both sides of that seam is one model in one turn. In an unattended run there is no second party and no next user message, and a reply that contains no tool call ends the session. So an instruction to return, hand back, or report to a caller has exactly one expressible form at that seam: stop. The prose is not wrong about its protocol. The protocol has no runtime.

The diagnostic that settles which seams are real. In the run archive, find one session id whose trace contains both phase-invocation calls (skill loads, reads of another unit's SKILL.md) and real subagent dispatches. The phase invocations carry the same session id as the orchestrator. That is one conversation and a fictional boundary. The subagent dispatches carry a distinct child id. That is a real boundary that can carry a hand-off. One line of log settles it for the whole corpus. Run this before classifying anything. Class 9 and survival screen 3 both depend on the answer.

If the archive carries no session or child ids (references/baseline-mining.md extracts them where it can), substitute the weaker structural test: a seam is real only where the trace shows a dispatch tool call whose result returns into the parent trace. A skill load, an include, or a file read is not one. Do not treat an unlabeled trace as evidence of a real boundary. That reading keeps every halt.

Each class below gives what to grep, why the match halts, and the replacement. Grep terms are starting points for a corpus that never used exactly these words. Read the matches; do not batch-edit them. Case-insensitive, whole corpus including reference files, one class at a time:

grep -rniE 'return control|hand back|hand off to|the caller (owns|applies)' <corpus-dir>
Raw lines 3 to 16
Starts an agent spawning :5
Starts an agent subagent :7
Starts an agent dispatches :7
Starts an agent dispatch :9
17## 1. Waits on helpers the runtime already terminated
19**Grep:** `wait for all`, `in parallel`, `concurrently`, `background`, `up to <n> minutes`, `poll until`, `dispatch all <n>`
21**Why it halts:** a mandated fan-out plus a wait ceiling. If the helpers were never spawned concurrently, or the runtime reaped them at turn end, the wait resolves to nothing. And "wait" has no tool call to express it, so the turn ends inside the ceiling.
23**Falsifiable check before touching it:** from the archive, measure the maximum number of helpers dispatched *concurrently* per run (see `references/baseline-mining.md` for the extraction). In the engagement, 331 of 332 runs never exceeded one at a time, which falsified the wall-clock justification the corpus had written for its own fan-out machinery.
25**Replacement:** dispatch serially, or state parallelism as an allowance rather than a mandate, and delete the wait ceiling with the wall-clock rationale that justified it.

1. Waits on helpers the runtime already terminated

Grep: wait for all, in parallel, concurrently, background, up to <n> minutes, poll until, dispatch all <n>

Why it halts: a mandated fan-out plus a wait ceiling. If the helpers were never spawned concurrently, or the runtime reaped them at turn end, the wait resolves to nothing. And "wait" has no tool call to express it, so the turn ends inside the ceiling.

Falsifiable check before touching it: from the archive, measure the maximum number of helpers dispatched concurrently per run (see references/baseline-mining.md for the extraction). In the engagement, 331 of 332 runs never exceeded one at a time, which falsified the wall-clock justification the corpus had written for its own fan-out machinery.

Replacement: dispatch serially, or state parallelism as an allowance rather than a mandate, and delete the wait ceiling with the wall-clock rationale that justified it.

Raw lines 17 to 26
Starts an agent dispatch :19
Starts an agent spawned :21
Starts an agent dispatched :23
27## 2. Hand-off across a same-model seam
29**Grep:** `return control`, `hand back`, `hand off to`, `the caller owns`, `the caller applies`, `report to the orchestrator`, `your caller will`
31**Why it halts:** it names a recipient that does not exist on this side of the diagnostic above.
33**Replacement:** record the structured result and continue. "Write the result to `<path>`, then continue to `<next step>`." Keep every field name in the result untouched. The fields are data; the hand-off verb is the defect.

2. Hand-off across a same-model seam

Grep: return control, hand back, hand off to, the caller owns, the caller applies, report to the orchestrator, your caller will

Why it halts: it names a recipient that does not exist on this side of the diagnostic above.

Replacement: record the structured result and continue. "Write the result to <path>, then continue to <next step>." Keep every field name in the result untouched. The fields are data; the hand-off verb is the defect.

Raw lines 27 to 34
35## 3. A step ending with no instruction to advance
37**Diagnostic (count, not grep):** at each boundary between consecutive steps, classify the last sentence of the step as terminal (`stop`, `done`, `await`, `report`, `wait for confirmation`, `end of step`) or forward (`then`, `next`, `continue to`, `proceed to`). A corpus with more terminal than forward endings has a structural halt, not a wording problem.
39**Why it halts:** a step that closes on a terminal word and says nothing about advancing leaves ending the turn as the only complete reading.
41**Replacement:** an explicit continue-to-next at **each** transition, placed at the transition and not once in a preamble, plus one statement that a checkpoint means verify and continue rather than pause.

3. A step ending with no instruction to advance

Diagnostic (count, not grep): at each boundary between consecutive steps, classify the last sentence of the step as terminal (stop, done, await, report, wait for confirmation, end of step) or forward (then, next, continue to, proceed to). A corpus with more terminal than forward endings has a structural halt, not a wording problem.

Why it halts: a step that closes on a terminal word and says nothing about advancing leaves ending the turn as the only complete reading.

Replacement: an explicit continue-to-next at each transition, placed at the transition and not once in a preamble, plus one statement that a checkpoint means verify and continue rather than pause.

Raw lines 35 to 42
Involves a person wait for confirmation :37
43## 4. Completion defined without a successor
45**Grep:** `is done once`, `is complete when`, `you are finished when`, `definition of done`, `success criteria`
47**Why it halts:** "X is done once ..." with nothing after it reads as the end of the turn, not the end of a step.
49**Replacement:** say what follows being done. "X is done once <criteria>; then <next step>."

4. Completion defined without a successor

Grep: is done once, is complete when, you are finished when, definition of done, success criteria

Why it halts: "X is done once ..." with nothing after it reads as the end of the turn, not the end of a step.

Replacement: say what follows being done. "X is done once <criteria>; then <next step>."

Raw lines 43 to 50
51## 5. A structured output labeled as a return
53**Grep:** `Return the following`, `Return:`, `your return value`, `respond with the following object`
55**Why it halts:** the verb, and only the verb. A return is a control transfer; there is nowhere to transfer to.
57**Replacement:** verb swap. `Return the following:` becomes `Write the following to <path>:`. The field list is untouched. This is the cheapest class and the easiest to over-cut. An agent told to fix "return" language will happily also delete the schema under it.

5. A structured output labeled as a return

Grep: Return the following, Return:, your return value, respond with the following object

Why it halts: the verb, and only the verb. A return is a control transfer; there is nowhere to transfer to.

Replacement: verb swap. Return the following: becomes Write the following to <path>:. The field list is untouched. This is the cheapest class and the easiest to over-cut. An agent told to fix "return" language will happily also delete the schema under it.

Raw lines 51 to 58
59## 6. An output-format rule doubling as a turn boundary
61**Grep:** `output nothing else`, `no other text`, `respond with only`, `a single bare`, `do not add commentary`, `the entire response must be`
63**Why it halts:** a rule forbidding anything after the payload forbids the next tool call. It is a strictness constraint that has quietly become a stop instruction.
65**Replacement:** write the machine-readable payload to a file at a stated path and let the reply continue. The strictness moves rather than being lost. A file at a fixed path is a *more* deterministic parse target for a programmatic consumer than the end of a transcript, so say that in the replacement text or someone will restore the old rule.

6. An output-format rule doubling as a turn boundary

Grep: output nothing else, no other text, respond with only, a single bare, do not add commentary, the entire response must be

Why it halts: a rule forbidding anything after the payload forbids the next tool call. It is a strictness constraint that has quietly become a stop instruction.

Replacement: write the machine-readable payload to a file at a stated path and let the reply continue. The strictness moves rather than being lost. A file at a fixed path is a more deterministic parse target for a programmatic consumer than the end of a transcript, so say that in the replacement text or someone will restore the old rule.

Raw lines 59 to 66
67## 7. A missing optional capability treated as fatal
69**Grep:** `not installed`, `must be available`, `required tool`, `abort if`, `did not start`, `if <x> is unavailable, stop`
71**Why it halts:** a step that cannot execute takes the whole run with it, when the correct outcome is a partial result.
73**Replacement:** record the step as skipped with the reason and what it would have covered, report partial, continue. Keep the stop only where the missing capability makes every later step meaningless. That is a real precondition, not this class.

7. A missing optional capability treated as fatal

Grep: not installed, must be available, required tool, abort if, did not start, if <x> is unavailable, stop

Why it halts: a step that cannot execute takes the whole run with it, when the correct outcome is a partial result.

Replacement: record the step as skipped with the reason and what it would have covered, report partial, continue. Keep the stop only where the missing capability makes every later step meaningless. That is a real precondition, not this class.

Raw lines 67 to 74
75## 8. An unresolvable precondition with no unattended path
77**Grep:** `resolve ... first`, `ask the user to`, `credentials`, `log in`, `confirm before`, `requires approval`
79**Why it halts:** "resolve credentials first" is satisfiable only by a human, and no human is present.
81**Replacement:** report the unmet precondition and continue without the step. Where the step is mutating and unsafe to perform unattended, skip the mutation and record the exact command a human would run. Do not resolve a halt by widening what the run is allowed to change.

8. An unresolvable precondition with no unattended path

Grep: resolve ... first, ask the user to, credentials, log in, confirm before, requires approval

Why it halts: "resolve credentials first" is satisfiable only by a human, and no human is present.

Replacement: report the unmet precondition and continue without the step. Where the step is mutating and unsafe to perform unattended, skip the mutation and record the exact command a human would run. Do not resolve a halt by widening what the run is allowed to change.

Raw lines 75 to 82
Involves a person ask the user :77
83## 9. The subagent-prompt trap
85**Grep:** the vocabulary of classes 2 and 6, restricted to the corpus's own prompt assets: its persona or agent-prompt directories and prompt templates. Also `report and stop`, `return only a gist`, `the orchestrator owns that decision`, `do not act on this yourself`.
87**Why a naive sweep misses it entirely:** while the asset is sent to a real subagent, every one of those lines is correct and required. They become a live session terminator the moment a documented no-subagent fallback routes the asset **inline** into the orchestrator's own conversation. Same words, different consumer. A sweep that reads only the asset sees a correct file. A sweep that reads only the orchestrator sees no offending prose.
89**Resolution:** classify each prompt asset by who actually consumes it. Grep every unit that dispatches the asset for an inlining fallback: `if you cannot dispatch`, `if subagents are unavailable`, `run this yourself`, `inline`. Then:
91| Consumer | Action |
92|---|---|
93| Always a real subagent | Leave as is. The boundary is real. |
94| Any documented inline fallback | Rewrite so the text is safe in both paths, or remove the fallback. |
95| Asset shared by several units | Resolve once, for the union of consumers (see the shared-asset rule in `references/cut-passes.md`). |
97Do not blanket-rewrite prompt assets. That deletes the one boundary in the corpus that was not fiction.

9. The subagent-prompt trap

Grep: the vocabulary of classes 2 and 6, restricted to the corpus's own prompt assets: its persona or agent-prompt directories and prompt templates. Also report and stop, return only a gist, the orchestrator owns that decision, do not act on this yourself.

Why a naive sweep misses it entirely: while the asset is sent to a real subagent, every one of those lines is correct and required. They become a live session terminator the moment a documented no-subagent fallback routes the asset inline into the orchestrator's own conversation. Same words, different consumer. A sweep that reads only the asset sees a correct file. A sweep that reads only the orchestrator sees no offending prose.

Resolution: classify each prompt asset by who actually consumes it. Grep every unit that dispatches the asset for an inlining fallback: if you cannot dispatch, if subagents are unavailable, run this yourself, inline. Then:

ConsumerAction
Always a real subagentLeave as is. The boundary is real.
Any documented inline fallbackRewrite so the text is safe in both paths, or remove the fallback.
Asset shared by several unitsResolve once, for the union of consumers (see the shared-asset rule in references/cut-passes.md).

Do not blanket-rewrite prompt assets. That deletes the one boundary in the corpus that was not fiction.

Raw lines 83 to 98
Starts an agent subagent :83
Starts an agent dispatches :89
Starts an agent dispatch :89
Starts an agent subagents :89
99## 10. Over-correction: removing the mandate that made phases required
101This class belongs here because the cure for 1 through 9 causes it.
103A dispatch mandate carries two payloads: the fictional seam, and the requirement that the phase run at all. Remove the first without preserving the second and nothing in the corpus says the workflow's own phases are required.
105**Observed:** after a dispatch-mandate removal, a run did the task inline and reported success with no artifacts. The transcript looked clean. That defect is invisible to a did-it-finish metric and shows up only if process adherence and task completion are tracked as separate numbers (`references/baseline-mining.md`).
107**Replacement:** keep the requirement, drop the seam. "Phase N is required. Do it in this session; do not skip it." Then verify the phase by artifact existence, never by the final message.

10. Over-correction: removing the mandate that made phases required

This class belongs here because the cure for 1 through 9 causes it.

A dispatch mandate carries two payloads: the fictional seam, and the requirement that the phase run at all. Remove the first without preserving the second and nothing in the corpus says the workflow's own phases are required.

Observed: after a dispatch-mandate removal, a run did the task inline and reported success with no artifacts. The transcript looked clean. That defect is invisible to a did-it-finish metric and shows up only if process adherence and task completion are tracked as separate numbers (references/baseline-mining.md).

Replacement: keep the requirement, drop the seam. "Phase N is required. Do it in this session; do not skip it." Then verify the phase by artifact existence, never by the final message.

Raw lines 99 to 108
Starts an agent dispatch :103
109## Screens for a stop that must survive
111Treating every stop as the enemy is the failure mode of applying this file. Run these before editing any match above. **Any one** is sufficient to keep the stop as written.
1131. **The user is genuinely the subject.** The instruction concerns a human's decision, consent, or preference, not a fabricated caller.
1142. **It is a terminal no-op.** Nothing is left for anyone: "no findings, stop." A continuation here invents work.
1153. **The roles split across a real runtime boundary.** The opening diagnostic shows two distinct sessions or processes. Then "return to the caller" is accurate and the halt is somebody else's turn ending, correctly.
1164. **The site already has an unattended default.** "If no reply within X, choose Y", "in non-interactive mode, do Z." The path exists; the stop is the interactive branch.
1175. **The word bounds an activity, not the turn.** "Stop expanding the search once you have three candidates", "halt the retry loop after two failures." A grep for `stop` catches these. They are scope quantifiers, and removing them removes a threshold.
119**Sixth case, stated separately because it is the one that gets deleted anyway:** a workflow whose product **is** stopping to ask. An interview that must take one question at a time. A teaching check-in that pauses for the learner's answer. An approval step that exists in order to make the user decide. Deleting the pause deletes the unit. These get an unattended degradation path (a stated default, a skip-with-reason, or an explicit refusal to run unattended), never a deletion. If such a unit fails the benchmark, the benchmark's task is wrong for it. Exclude the unit and report the exclusion rather than editing the unit to pass.

Screens for a stop that must survive

Treating every stop as the enemy is the failure mode of applying this file. Run these before editing any match above. Any one is sufficient to keep the stop as written.

  1. The user is genuinely the subject. The instruction concerns a human's decision, consent, or preference, not a fabricated caller.
  2. It is a terminal no-op. Nothing is left for anyone: "no findings, stop." A continuation here invents work.
  3. The roles split across a real runtime boundary. The opening diagnostic shows two distinct sessions or processes. Then "return to the caller" is accurate and the halt is somebody else's turn ending, correctly.
  4. The site already has an unattended default. "If no reply within X, choose Y", "in non-interactive mode, do Z." The path exists; the stop is the interactive branch.
  5. The word bounds an activity, not the turn. "Stop expanding the search once you have three candidates", "halt the retry loop after two failures." A grep for stop catches these. They are scope quantifiers, and removing them removes a threshold.

Sixth case, stated separately because it is the one that gets deleted anyway: a workflow whose product is stopping to ask. An interview that must take one question at a time. A teaching check-in that pauses for the learner's answer. An approval step that exists in order to make the user decide. Deleting the pause deletes the unit. These get an unattended degradation path (a stated default, a skip-with-reason, or an explicit refusal to run unattended), never a deletion. If such a unit fails the benchmark, the benchmark's task is wrong for it. Exclude the unit and report the exclusion rather than editing the unit to pass.

Raw lines 109 to 120
121## Why the fix is never more capability
123Every class above reduces to prose written as if a second party were waiting. The fix is never to add capability. It is to remove the fictional seam and keep the requirement.

Why the fix is never more capability

Every class above reduces to prose written as if a second party were waiting. The fix is never to add capability. It is to remove the fictional seam and keep the requirement.

Raw lines 121 to 123