@try-works/dsh-recursive-mode 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -179,7 +179,7 @@ control plane on disk is the only state it trusts across restarts.
179
179
  | `recursive_audit_team` | Fan a phase out across roles (audit) |
180
180
  | `recursive_review` | **Independent review** of the phase artifact, with a repair path |
181
181
  | `recursive_delegate` | **Delegate the work of a phase** to a durable child; it produces, you judge |
182
- | `recursive_ask` | Ask the workspace a question, with the control plane as context |
182
+ | `recursive_ask` | Ask a **human** gate as a structured decision: `tdd-mode`, `qa-signoff`, `gate-block`, or `run-start` — the phase-0 approval that decides whether the run goal exists |
183
183
  | `recursive_preview` | Preview what a tool would do, without doing it |
184
184
 
185
185
  ### 4.2 The command surface
@@ -405,9 +405,20 @@ prove. Three facts shape the picture:
405
405
  the audit contract: `01-as-is`, `01.5-root-cause`, `02-to-be-plan`, `03-implementation-summary`,
406
406
  `03.5-code-review`, `04-test-summary`, `06-decisions-update`, `07-state-update`, `08-memory-impact`.
407
407
  `00-requirements`, `00-worktree` and `05-manual-qa` are not in it.
408
- 3. **`recursive_ask` is not a subagent tool.** It carries the workflow's three **human** gates —
409
- `ASK_GATE_IDS = ['tdd-mode', 'qa-signoff', 'gate-block']` — as structured decisions rather than prose, so the
410
- answer is validated and citeable.
408
+ 3. **`recursive_ask` is not a subagent tool.** It carries the workflow's **four human gates** —
409
+ `tdd-mode`, `qa-signoff` and `gate-block` (the list in `ASK_GATE_IDS`), plus **`run-start`**, the
410
+ phase-0 approval that decides whether a run's goal exists at all — as structured decisions rather
411
+ than prose, so the answer is validated and citeable.
412
+
413
+ `run-start` is unlike the other three: it is the only gate that asks the harness's **blocking
414
+ human channel**, and the only one that **arms a goal**. Creating a spec therefore creates no goal;
415
+ nothing runs unattended until a person approves it. When the mounted channel cannot deliver the
416
+ question, the refusal **names the channel's own cause** (`RM5503`) instead of asserting one — and a
417
+ composition that cannot render a card at all can still record the decision explicitly by passing
418
+ `answer` with `relay: true`, which is reported as relayed rather than as a person's selection. A
419
+ person's own answer always wins, and a question that was cancelled, aborted or timed out is **never**
420
+ relayable. A channel that *did* reach a person whose answer was not one of the offered labels is
421
+ `RM5504`, which is a different event from `RM5503`.
411
422
 
412
423
  ```mermaid
413
424
  flowchart TB
package/lib/errors.d.ts CHANGED
@@ -61,12 +61,30 @@ export declare const TOOL_ERRORS: {
61
61
  readonly problem: "this gate has no default artifact, so one must be named";
62
62
  readonly next: "pass artifact: <file> so the answer has somewhere durable to land";
63
63
  };
64
+ readonly RELAY_ONLY_FOR_RUN_START: {
65
+ readonly code: "RM1150";
66
+ readonly klass: "input";
67
+ readonly problem: "relay applies only to the run-start gate, which is the only gate that asks the user-questions channel";
68
+ readonly next: "drop relay for this gate and answer it with one of its own labels, or call recursive_ask with gate: run-start when the decision is whether to start the run";
69
+ };
64
70
  readonly MISSING_RUN_ID: {
65
71
  readonly code: "RM1101";
66
72
  readonly klass: "input";
67
73
  readonly problem: "runId is required";
68
74
  readonly next: "call recursive_status with no runId to see the latest run id in this workspace";
69
75
  };
76
+ /**
77
+ * A run id is the NAME of the run directory and is joined onto the run layer
78
+ * as one path segment, so a path-shaped id is refused before any directory is
79
+ * created. See `run-id.ts` for the rule and for why it is not the runtime that
80
+ * learns to accept a path.
81
+ */
82
+ readonly BAD_RUN_ID: {
83
+ readonly code: "RM1107";
84
+ readonly klass: "input";
85
+ readonly problem: "runId is not a single directory name";
86
+ readonly next: "pass the run directory name such as 03-something, then call recursive_init again";
87
+ };
70
88
  readonly MISSING_ARTIFACT: {
71
89
  readonly code: "RM1102";
72
90
  readonly klass: "input";
@@ -139,12 +157,27 @@ export declare const TOOL_ERRORS: {
139
157
  readonly problem: "the run-start gate needs an answer, and this composition mounts no user-questions channel to ask one directly";
140
158
  readonly next: string;
141
159
  };
160
+ /**
161
+ * ⚠ RM5503 USED TO LIE. Its text asserted "so no person was asked" for EVERY cause, because the caller
162
+ * that produced it had already thrown the cause away — and a live session showed the cost: the gate
163
+ * failed 22.9 s into the call with a reason nobody could see, and its `Next:` clause prescribed the very
164
+ * call that had just failed, so no route to start a run remained. The problem statement now claims only
165
+ * what the gate knows (no decision came back), and the cause travels in the `detail` the caller
166
+ * supplies. `RUN_START_ANSWER_UNUSABLE` carries the one case this entry must NOT cover: a person was
167
+ * reached and their answer was not an approval.
168
+ */
142
169
  readonly RUN_START_UNANSWERED: {
143
170
  readonly code: "RM5503";
144
171
  readonly klass: "runtime";
145
- readonly problem: "the user-questions channel mounted in this composition refused the run-start question, so no person was asked";
172
+ readonly problem: "the run-start question reached no decision: the mounted user-questions channel failed before a person answered it";
146
173
  readonly next: string;
147
174
  };
175
+ readonly RUN_START_ANSWER_UNUSABLE: {
176
+ readonly code: "RM5504";
177
+ readonly klass: "runtime";
178
+ readonly problem: "a person was asked to start this run and their answer was not one of the labels the run-start gate offered";
179
+ readonly next: "call recursive_ask again and have the person choose exactly \"Start run\" or \"Hold\"; a skipped or custom answer is not an approval, and no relayed answer can replace a decision the person made";
180
+ };
148
181
  readonly RUNTIME_REFUSED: {
149
182
  readonly code: "RM5501";
150
183
  readonly klass: "runtime";