@tekyzinc/gsd-t 3.16.12 → 3.18.11

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +13 -3
  3. package/bin/gsd-t-depgraph-validate.cjs +140 -0
  4. package/bin/gsd-t-economics.cjs +287 -0
  5. package/bin/gsd-t-file-disjointness.cjs +227 -0
  6. package/bin/gsd-t-in-session-usage.cjs +213 -0
  7. package/bin/gsd-t-orchestrator-config.cjs +100 -3
  8. package/bin/gsd-t-orchestrator.js +2 -1
  9. package/bin/gsd-t-parallel.cjs +382 -0
  10. package/bin/gsd-t-report-tokens.cjs +549 -0
  11. package/bin/gsd-t-task-graph.cjs +366 -0
  12. package/bin/gsd-t-token-capture.cjs +29 -14
  13. package/bin/gsd-t-token-dashboard.cjs +35 -0
  14. package/bin/gsd-t-tool-attribution.cjs +377 -0
  15. package/bin/gsd-t-tool-cost.cjs +195 -0
  16. package/bin/gsd-t-unattended-platform.cjs +7 -1
  17. package/bin/gsd-t-unattended.cjs +2 -0
  18. package/bin/gsd-t.js +155 -5
  19. package/bin/headless-auto-spawn.cjs +69 -49
  20. package/bin/headless-auto-spawn.js +18 -24
  21. package/bin/runway-estimator.cjs +212 -0
  22. package/bin/spawn-plan-derive.cjs +163 -0
  23. package/bin/spawn-plan-status-updater.cjs +292 -0
  24. package/bin/spawn-plan-writer.cjs +204 -0
  25. package/commands/gsd-t-debug.md +26 -7
  26. package/commands/gsd-t-execute.md +36 -28
  27. package/commands/gsd-t-help.md +11 -0
  28. package/commands/gsd-t-integrate.md +27 -7
  29. package/commands/gsd-t-quick.md +30 -13
  30. package/commands/gsd-t-scan.md +5 -5
  31. package/commands/gsd-t-unattended-watch.md +4 -3
  32. package/commands/gsd-t-unattended.md +9 -3
  33. package/commands/gsd-t-verify.md +5 -5
  34. package/commands/gsd-t-wave.md +21 -8
  35. package/commands/gsd.md +45 -3
  36. package/docs/GSD-T-README.md +43 -5
  37. package/docs/architecture.md +423 -3
  38. package/docs/requirements.md +203 -0
  39. package/package.json +1 -1
  40. package/scripts/gsd-t-calibration-hook.js +256 -0
  41. package/scripts/gsd-t-compact-detector.js +223 -0
  42. package/scripts/gsd-t-compaction-scanner.js +305 -0
  43. package/scripts/gsd-t-dashboard-autostart.cjs +172 -0
  44. package/scripts/gsd-t-dashboard-server.js +179 -0
  45. package/scripts/gsd-t-heartbeat.js +50 -2
  46. package/scripts/gsd-t-post-commit-spawn-plan.sh +86 -0
  47. package/scripts/gsd-t-transcript.html +546 -43
  48. package/scripts/hooks/gsd-t-in-session-usage-hook.js +84 -0
  49. package/scripts/spawn-plan-fmt-tokens.cjs +80 -0
  50. package/templates/CLAUDE-global.md +8 -3
  51. package/templates/CLAUDE-project.md +17 -14
  52. package/templates/hooks/post-commit-spawn-plan.sh +85 -0
@@ -4,16 +4,16 @@ You are debugging an issue in a contract-driven project. Your approach should id
4
4
 
5
5
  ## Argument Parsing
6
6
 
7
- Parse `$ARGUMENTS`. The issue description is `$ISSUE`. Detect `--watch` (sets `WATCH_FLAG=true`; default `false`). Per `.gsd-t/contracts/headless-default-contract.md` §2, `--watch` propagates only to the **primary** inner fix-loop subagent (Step 0.1). Validation spawns (Deep Research Step 1.5, Red Team Step 5.3, doc-ripple Step 6) always go headless regardless of the flag.
7
+ Parse `$ARGUMENTS`. The issue description is `$ISSUE`. M43 D4 removed the `--watch` opt-out; `--in-session`/`--headless` were never shipped. Under `.gsd-t/contracts/headless-default-contract.md` **v2.0.0** the inner fix-loop subagent (Step 0.1) and all validation spawns (Deep Research Step 1.5, Red Team Step 5.3, doc-ripple Step 6) go headless unconditionally. A legacy `--watch` token is accepted but ignored (stderr deprecation line).
8
8
 
9
- ## Spawn Primitive — Default Headless (M38 Domain 1)
9
+ ## Spawn Primitive — Always Headless (M43 D4, v2.0.0)
10
10
 
11
- Per `.gsd-t/contracts/headless-default-contract.md` v1.0.0. Spawn classifications used below:
11
+ Per `.gsd-t/contracts/headless-default-contract.md` v2.0.0. Spawn classifications used below (both always headless):
12
12
 
13
13
  - `spawnType: 'primary'` — Step 0.1 fresh-dispatch subagent running the debug session
14
14
  - `spawnType: 'validation'` — Step 1.5 Deep Research teammates, Step 5.3 Red Team, Step 6 doc-ripple
15
15
 
16
- Default path is `autoSpawnHeadless({command, spawnType, watch: WATCH_FLAG, projectDir, sessionContext})`. Outer orchestrator stays interactive; inner subagent goes headless by default and streams in-context only when `WATCH_FLAG=true`.
16
+ Spawn path is `autoSpawnHeadless({command, spawnType, projectDir, sessionContext})`. The outer `gsd-t-debug` command body is itself the interactive spawn target when invoked by `/gsd` or `gsd-t-wave`; nested spawns always go headless.
17
17
 
18
18
  ## Model Assignment
19
19
 
@@ -96,7 +96,7 @@ Violations are task failures, not warnings.
96
96
 
97
97
  If STACK_RULES is empty (no templates/stacks/ dir or no matches), skip silently.
98
98
 
99
- Spawn a fresh subagent via `captureSpawn` — `spawnType: 'primary'` (respects `--watch`: headless by default, in-context when `WATCH_FLAG=true`):
99
+ Spawn a fresh subagent via `captureSpawn` — `spawnType: 'primary'` (always headless per headless-default-contract v2.0.0):
100
100
 
101
101
  **OBSERVABILITY LOGGING (MANDATORY) — wrap the primary subagent spawn with `captureSpawn`:**
102
102
 
@@ -316,6 +316,25 @@ Before touching any code:
316
316
  node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-id "${GSD_T_PARENT_AGENT_ID:-null}" --command gsd-t-debug --step 3 --step-label "Debug (Solo or Team)" 2>/dev/null || true
317
317
  ```
318
318
 
319
+ ### Optional — Parallel Dispatch (M44, lightweight · conditional-only)
320
+
321
+ **This block is a no-op for single-domain debug sessions.** Most debug sessions touch one domain (within-domain bug, Category A in Step 2); for those, the sequential Solo Mode path below runs unchanged.
322
+
323
+ **Trigger conditions (BOTH must hold)**:
324
+ 1. This is a multi-domain debug session (Category B contract boundary bug OR Category C contract gap that spans more than one domain), AND
325
+ 2. The fix is decomposable into independent tasks across domains that pass D4 depgraph + D5 file-disjointness + D6 economics gates.
326
+
327
+ **If either condition fails** — single-domain debug, or a fix that cannot be decomposed cleanly — skip this block entirely. The sequential Solo Mode / Team Mode flow below remains unchanged.
328
+
329
+ **If BOTH conditions hold** — dispatch the independent fix tasks via `gsd-t parallel` (mode auto-detected from `GSD_T_UNATTENDED=1`; do not hardcode `--mode`):
330
+
331
+ - Fallback is silent — any gate veto drops the affected tasks back to the sequential debug path.
332
+ - D2 owns the spawn observability; the parallel path writes the same `.gsd-t/events/YYYY-MM-DD.jsonl` records and `.gsd-t/token-log.md` rows as the sequential path via `captureSpawn`. D3 adds no new spawn machinery.
333
+ - `[unattended]` — D2 enforces the zero-compaction contract by splitting tasks when D6 estimates > 60% per-worker CW.
334
+ - `[in-session]` — NEVER interrupts the user with a pause/resume prompt. If headroom is tight, D2 reduces the worker count (floor N=1). No opt-out flag exists (consistent with M43 D4: `--in-session` / `--headless` were never shipped).
335
+
336
+ Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0.
337
+
319
338
  ### Deviation Rules
320
339
 
321
340
  When you encounter unexpected situations during the fix:
@@ -460,7 +479,7 @@ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
460
479
  description: 'adversarial validation of debug fix',
461
480
  projectDir: '.',
462
481
  notes: '{VERDICT} — {N} bugs found',
463
- spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus) — always headless, --watch ignored:
482
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus) — always headless per headless-default-contract v2.0.0:
464
483
  'Read \$RT_PROMPT and follow it. Context: post-fix validation for a debug session.
465
484
  Additional categories for this run:
466
485
  (a) Regression Around the Fix — test every code path adjacent to the changed lines; fixes frequently break neighboring functionality.
@@ -500,7 +519,7 @@ After all work is committed but before reporting completion:
500
519
 
501
520
  1. Run threshold check — read `git diff --name-only HEAD~1` and evaluate against doc-ripple-contract.md trigger conditions
502
521
  2. If SKIP: log "Doc-ripple: SKIP — {reason}" and proceed to completion
503
- 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless, `--watch` ignored):
522
+ 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
504
523
 
505
524
  ⚙ [{model}] gsd-t-doc-ripple → blast radius analysis + parallel updates
506
525
 
@@ -4,20 +4,16 @@ You are the lead agent coordinating task execution across domains. Choose solo o
4
4
 
5
5
  ## Argument Parsing
6
6
 
7
- Parse `$ARGUMENTS` before doing any work. Detect these flags:
7
+ Parse `$ARGUMENTS` before doing any work. M43 D4 removed the `--watch` opt-out; `--in-session`/`--headless` were never shipped. Under `.gsd-t/contracts/headless-default-contract.md` **v2.0.0** every command spawns — the dialog channel is reserved for the `/gsd` router's exploratory turns and is upstream of this command. Any legacy `--watch` token in `$ARGUMENTS` is accepted but ignored (printed as a single stderr deprecation line by the spawn primitive).
8
8
 
9
- - `--watch`opt-in to **in-context streaming** for primary work subagents. If present, set `WATCH_FLAG=true`; otherwise `WATCH_FLAG=false` (default).
9
+ ## Spawn Primitive Always Headless (M43 D4, v2.0.0)
10
10
 
11
- Validation spawns (QA, Red Team, Design Verification, doc-ripple) ignore `--watch` per `.gsd-t/contracts/headless-default-contract.md` §2 they always go headless.
12
-
13
- ## Spawn Primitive — Default Headless (M38 Domain 1)
14
-
15
- Per `.gsd-t/contracts/headless-default-contract.md` v1.0.0. Every Task-subagent spawn below is classified as one of:
11
+ Per `.gsd-t/contracts/headless-default-contract.md` v2.0.0. Every Task-subagent spawn below goes headless unconditionally. Classification is kept only for downstream logging:
16
12
 
17
13
  - `spawnType: 'primary'` — domain task-dispatcher (Step 3 fresh-dispatch)
18
14
  - `spawnType: 'validation'` — Step 2 QA, Step 5.25 Design Verification, Step 5.5 Red Team, Step 7 doc-ripple
19
15
 
20
- **Default spawn path** (when `WATCH_FLAG=false`):
16
+ **Spawn path** (unconditional):
21
17
 
22
18
  ```bash
23
19
  SESSION=$(node -e "
@@ -27,7 +23,6 @@ const r = has.autoSpawnHeadless({
27
23
  args: [], // optional per-spawn args
28
24
  projectDir: process.cwd(),
29
25
  spawnType: '{primary|validation}',
30
- watch: false,
31
26
  sessionContext: { step: '{step-id}', domain: '{domain-name}', task: '{task-id}' }
32
27
  });
33
28
  process.stdout.write(JSON.stringify(r));
@@ -37,10 +32,6 @@ echo "⚙ [${MODEL:-sonnet}] gsd-t-execute → ${DESC:-subagent} (headless)"
37
32
 
38
33
  Then `bin/check-headless-sessions.js printBannerIfAny()` surfaces the completion on the next user message.
39
34
 
40
- **`--watch` path** (only when `WATCH_FLAG=true` AND `spawnType: 'primary'`): `autoSpawnHeadless()` returns `{mode: 'in-context'}` sentinel — fall back to the in-context Task subagent pattern documented in each Step below. The OBSERVABILITY LOGGING block runs unchanged.
41
-
42
- **Validation spawns** always run headless regardless of `--watch`.
43
-
44
35
  ## Model Assignment
45
36
 
46
37
  Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0. Selection is deterministic via `bin/model-selector.js` — never runtime-overridden by context pressure.
@@ -116,7 +107,7 @@ node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-
116
107
 
117
108
  In solo mode, QA runs inside each domain subagent (see Step 3). In team mode, the lead spawns QA subagents at each domain checkpoint using the pattern below.
118
109
 
119
- **QA subagent prompt** — `spawnType: 'validation'` (always headless, `--watch` ignored per headless-default-contract §2):
110
+ **QA subagent prompt** — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
120
111
  ```
121
112
  Task subagent (spawnType: validation, general-purpose, model: sonnet):
122
113
  "Run the full test suite for this project and report pass/fail counts.
@@ -134,6 +125,28 @@ If QA found issues, append each to `.gsd-t/qa-issues.md` (create with header `|
134
125
  node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-id "${GSD_T_PARENT_AGENT_ID:-null}" --command gsd-t-execute --step 3 --step-label "Choose Execution Mode" 2>/dev/null || true
135
126
  ```
136
127
 
128
+ ### Optional — Parallel Dispatch (M44)
129
+
130
+ **Conditional check** — if `.gsd-t/domains/` contains more than one pending task that passes the D4 depgraph, D5 file-disjointness, and D6 economics gates, dispatch the ready batch via `gsd-t parallel` instead of the sequential task-dispatcher below. If the conditional fails (single pending task, or any gate vetoes, or disjointness is unprovable), fall through silently to the existing sequential path — there is no user prompt, no pause, no opt-out flag.
131
+
132
+ - **Mode auto-detection** — mode is auto-detected by `bin/gsd-t-parallel.cjs` from `GSD_T_UNATTENDED=1`. Do not hardcode `--mode` in this command file. Explicit `--mode` overrides env; omitted flag falls back to env; missing env defaults to in-session.
133
+ - **Fallback** — every gate veto (D4 `dep_gate_veto`, D5 `disjointness_fallback`, D6 estimated > threshold) removes the affected task(s) from the parallel batch. Tasks fall back to the sequential task-dispatcher silently; the dry-run plan table still lists them with decision `sequential` or `veto-deps` so the operator can see why.
134
+ - **Observability** — D2 owns the spawn observability. The parallel path writes the same `.gsd-t/events/YYYY-MM-DD.jsonl` event stream (`gate_veto`, `parallelism_reduced`, `task_split`) and the same `.gsd-t/token-log.md` rows that sequential spawns produce via `captureSpawn`. D3 adds no new spawn machinery — integration is purely a dispatch decision.
135
+ - **Zero-compaction invariant (unattended)** — for `[unattended]` runs, D2 enforces the zero-compaction contract by splitting tasks when D6 estimates per-worker CW > 60%. Mid-run compaction is not tolerated; the splitter slices before fan-out.
136
+ - **In-session invariant** — the parallel path NEVER interrupts the user with a pause/resume prompt. If the in-session headroom check reduces the worker count below the requested N, D2 emits `parallelism_reduced` and proceeds at the reduced count. The final floor is N=1 (sequential). If all gates fail, D2 falls back to sequential silently — no opt-out flag exists (consistent with M43 D4: `--in-session` / `--headless` were never shipped).
137
+
138
+ **Dispatch call** (example; resolve `--mode` via env):
139
+
140
+ ```bash
141
+ # Dry-run first if you want to see the plan table without spawning:
142
+ gsd-t parallel --milestone {milestone} --dry-run
143
+
144
+ # Live dispatch (mode auto-detected from GSD_T_UNATTENDED):
145
+ gsd-t parallel --milestone {milestone}
146
+ ```
147
+
148
+ `runParallel` produces the validated worker plan; the existing M40 orchestrator machinery owns the actual worker spawn, retry policy, wave barriers, and state-file lifecycle. Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0. When the conditional is not met — or when every candidate task falls back via veto — proceed to the existing Wave Scheduling + Solo/Team Mode flow below.
149
+
137
150
  ### Wave Scheduling (read first)
138
151
 
139
152
  Before choosing solo or team mode, read the `## Wave Execution Groups` section in `.gsd-t/contracts/integration-points.md` (added by the plan phase).
@@ -202,9 +215,7 @@ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
202
215
  Run via Bash:
203
216
  `node -e "const tb = require('./bin/token-budget.cjs'); const s = tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s));" 2>/dev/null`
204
217
 
205
- Apply the single-band result per `context-meter-contract.md` v1.3.0:
206
- - `threshold: 'normal'` (or file missing) → proceed with standard model assignments.
207
- - `threshold: 'threshold'` → the Context Meter's PostToolUse hook has already emitted the `next-spawn-headless:true` marker; subsequent task-dispatcher spawns route through `autoSpawnHeadless()` automatically. No manual halt.
218
+ Capture `pct` as `{CTX_PCT}` for the token-log `Ctx%` column on the next spawn. The reading is observational only — under headless-default-contract v2.0.0 the spawn decision is no longer gated on `threshold`; every task-dispatcher spawn goes through `autoSpawnHeadless()` regardless of band.
208
219
 
209
220
  **Pre-dispatch experience retrieval (before dispatching each domain's tasks):**
210
221
  Run via Bash:
@@ -309,7 +320,7 @@ For each task in `.gsd-t/domains/{domain-name}/tasks.md` (in order, skip complet
309
320
  2. Load graph context (if `.gsd-t/graph/meta.json` exists): query task's files for relevant graph context
310
321
  3. Display: `⚙ [sonnet] gsd-t-execute → domain: {domain-name}, task-{task-id}`
311
322
  4. Run observability Bash (T_START / DT_START)
312
- 5. Spawn task subagent — `spawnType: 'primary'` (respects `--watch`: headless by default, in-context when `WATCH_FLAG=true`):
323
+ 5. Spawn task subagent — `spawnType: 'primary'` (always headless per headless-default-contract v2.0.0):
313
324
 
314
325
  ```
315
326
  Task subagent (spawnType: primary, general-purpose, model: sonnet, mode: bypassPermissions):
@@ -537,7 +548,7 @@ Report back:
537
548
 
538
549
  6. **Per-domain Red Team** — invoke Step 5.5 (Red Team) NOW for this domain. This is the first place Red Team runs in v2.74.12 — there is no global post-execute Red Team anymore. If Red Team returns FAIL, fix bugs and re-run before proceeding to the next domain (max 2 fix-and-verify cycles); if bugs persist, log to `.gsd-t/deferred-items.md` and present to user.
539
550
 
540
- 7. **Context gate re-check** — run `node -e "const tb=require('./bin/token-budget.cjs'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s));"`. If `threshold === 'threshold'`, the Context Meter hook has already emitted the `next-spawn-headless:true` marker — the next domain dispatcher must be routed through `autoSpawnHeadless()` so it runs in a fresh headless context. `threshold === 'normal'` → proceed in-context.
551
+ 7. **Context observation** — run `node -e "const tb=require('./bin/token-budget.cjs'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s));"` and capture `pct` for the NEXT spawn's token-log row. No gating: the next domain dispatcher runs through `autoSpawnHeadless()` either way under headless-default-contract v2.0.0.
541
552
 
542
553
  ### Team Mode (when agent teams are enabled)
543
554
  Spawn teammates for domains within the same wave. Only domains in the same wave can run in parallel — do not spawn teammates for domains in different waves simultaneously. Each teammate uses the **domain task-dispatcher pattern** — one subagent per task within their domain (same as solo mode).
@@ -687,18 +698,15 @@ Cleanup is not optional — orphaned worktrees waste disk space and can confuse
687
698
  node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-id "${GSD_T_PARENT_AGENT_ID:-null}" --command gsd-t-execute --step 3 --step-label ".5: Orchestrator Context Gate (MANDATORY)" 2>/dev/null || true
688
699
  ```
689
700
 
690
- Single-band context gate per `.gsd-t/contracts/context-meter-contract.md` v1.3.0. The orchestrator checks `getSessionStatus()` BEFORE every task subagent spawn. `bin/token-budget.cjs` reads `.gsd-t/.context-meter-state.json` the token estimate produced by the Context Meter PostToolUse hook.
701
+ Context observation the orchestrator captures `getSessionStatus()` BEFORE every spawn for the Ctx% column only. Under headless-default-contract v2.0.0 the band does NOT gate the spawn decision; every task-dispatcher spawn goes through `autoSpawnHeadless()`.
691
702
 
692
- **Before each task spawn — gate check:**
703
+ **Before each task spawn — capture ctx reading:**
693
704
 
694
705
  ```bash
695
706
  node -e "const tb=require('./bin/token-budget.cjs'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s));"
696
707
  ```
697
708
 
698
- The JSON on stdout contains `{pct, threshold}` where `threshold` is `normal` or `threshold`. Capture `pct` as `{CTX_PCT}` for the token-log `Ctx%` column on the NEXT spawn.
699
-
700
- - `threshold: 'normal'` → proceed with the standard in-context spawn path for `primary` spawns (headless for `validation` spawns per headless-default-contract).
701
- - `threshold: 'threshold'` → the Context Meter's PostToolUse hook has already emitted the `next-spawn-headless:true` marker. Route subsequent `primary` task-dispatcher spawns through `autoSpawnHeadless()` as well — the next spawn runs in a fresh headless context, the current orchestrator finishes its bookkeeping and returns cleanly. No manual checkpoint/halt.
709
+ The JSON on stdout contains `{pct, threshold}`. Capture `pct` as `{CTX_PCT}` for the token-log `Ctx%` column on the NEXT spawn. The `threshold` field is observational — no longer used for branching.
702
710
 
703
711
  **Configuring the threshold:**
704
712
 
@@ -774,7 +782,7 @@ DV_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/design-v
774
782
  [ -f "$DV_PROMPT" ] || DV_PROMPT="templates/prompts/design-verify-subagent.md"
775
783
  ```
776
784
 
777
- Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless, `--watch` ignored):
785
+ Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
778
786
 
779
787
  ```
780
788
  node -e "
@@ -840,7 +848,7 @@ RT_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/red-team
840
848
  [ -f "$RT_PROMPT" ] || RT_PROMPT="templates/prompts/red-team-subagent.md"
841
849
  ```
842
850
 
843
- Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless, `--watch` ignored):
851
+ Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
844
852
 
845
853
  ```
846
854
  node -e "
@@ -905,7 +913,7 @@ After all work is committed but before reporting completion:
905
913
 
906
914
  1. Run threshold check — read `git diff --name-only HEAD~1` and evaluate against doc-ripple-contract.md trigger conditions
907
915
  2. If SKIP: log "Doc-ripple: SKIP — {reason}" and proceed to completion
908
- 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless, `--watch` ignored):
916
+ 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
909
917
 
910
918
  ⚙ [{model}] gsd-t-doc-ripple → blast radius analysis + parallel updates
911
919
 
@@ -72,6 +72,7 @@ HEADLESS (CI/CD) CLI
72
72
  headless exec Run any GSD-T command non-interactively via claude -p
73
73
  headless query Read project state without LLM (<100ms)
74
74
  headless --debug-loop Compaction-proof test-fix-retest loop (fresh sessions)
75
+ parallel Task-level parallel dispatch with mode-aware gating (M44)
75
76
 
76
77
  BACKLOG Manual
77
78
  ───────────────────────────────────────────────────────────────────────────────
@@ -317,6 +318,7 @@ Use these when user asks for help on a specific command:
317
318
  - **Reads**: `.gsd-t/dashboard.pid`, `.gsd-t/events/*.jsonl` (via server)
318
319
  - **Creates**: `.gsd-t/dashboard.pid` (when starting server)
319
320
  - **Use when**: Monitoring live agent activity during execute/wave phases; run `gsd-t-visualize stop` to stop the server
321
+ - **Spawn-plan panel (M44 D8, v3.18.10+)**: the transcript viewer at `/transcript/{spawnId}` now includes a right-side two-layer task panel (Layer 1 project · Layer 2 active spawn). Status icons `☐` pending, `◐` in_progress, `✓` done. Done tasks show a right-aligned token cell `in=12.5k out=1.7k $0.42` (or `—` when attribution unavailable). Token attribution is sourced from `.gsd-t/token-log.md` via the post-commit hook `scripts/gsd-t-post-commit-spawn-plan.sh`. Endpoints: `GET /api/spawn-plans` + SSE `/api/spawn-plans/stream`. Contract: `.gsd-t/contracts/spawn-plan-contract.md` v1.0.0.
320
322
 
321
323
  ### metrics
322
324
  - **Summary**: View task telemetry, process ELO, signal distribution, domain health, and cross-project comparison (with `--cross-project` flag)
@@ -339,6 +341,15 @@ Use these when user asks for help on a specific command:
339
341
  - **Creates**: `.gsd-t/debug-state.jsonl`, optional `.gsd-t/headless-{ts}.log`
340
342
  - **Use when**: Running automated fix loops in CI, or delegated from in-context commands that exhausted fix attempts
341
343
 
344
+ ### parallel
345
+ - **Summary**: Task-level parallel dispatch with mode-aware gating math (M44 D2) — wraps the M40 orchestrator with D4 depgraph + D5 file-disjointness + D6 economics gates and in-session headroom / unattended task-split decisions
346
+ - **Auto-invoked**: Conditionally — from `execute`, `wave`, `integrate`, `quick`, and `debug` integration blocks when >1 pending task passes all three gates. Single-task or veto paths fall back to sequential silently.
347
+ - **Flags**: `--mode in-session|unattended` (auto-detects from `GSD_T_UNATTENDED=1` when omitted), `--milestone Mxx`, `--domain <name>`, `--dry-run`, `--help/-h`
348
+ - **Reads**: `.gsd-t/domains/*/tasks.md` (via D1 task-graph), `.gsd-t/token-log.md` / `.gsd-t/metrics/token-usage.jsonl` (D6 corpus), `.gsd-t/.context-meter-state.json` (in-session ctxPct)
349
+ - **Writes**: `.gsd-t/events/YYYY-MM-DD.jsonl` — `gate_veto`, `parallelism_reduced`, `task_split` events (best-effort). Never writes to tasks.md.
350
+ - **Use when**: Usually auto-invoked by the integration blocks. Standalone use: preview a plan with `gsd-t parallel --dry-run`, or force a specific milestone/domain filter.
351
+ - **Contract**: `.gsd-t/contracts/wave-join-contract.md` v1.1.0 (§Mode-Aware Gating Math)
352
+
342
353
  ### promote-debt
343
354
  - **Summary**: Convert techdebt.md items into milestones
344
355
  - **Auto-invoked**: No
@@ -4,15 +4,15 @@ You are the lead agent performing integration work. This phase is ALWAYS single-
4
4
 
5
5
  ## Argument Parsing
6
6
 
7
- Parse `$ARGUMENTS`. Detect `--watch` (sets `WATCH_FLAG=true`; default `false`). Per `.gsd-t/contracts/headless-default-contract.md` §2, integrate's own agent work is interactive; all **validation** spawns below (QA in Step 5, Red Team in Step 7.5, doc-ripple in Step 9) always go headless regardless of `--watch`.
7
+ Parse `$ARGUMENTS`. M43 D4 removed the `--watch` opt-out; `--in-session`/`--headless` were never shipped. Under `.gsd-t/contracts/headless-default-contract.md` **v2.0.0** every spawn below goes headless unconditionally QA (Step 5), Red Team (Step 7.5), doc-ripple (Step 9). Integrate's own lead-agent body remains the interactive entry point for this command (it is itself the spawn target when invoked from `/gsd` or `gsd-t-wave`). A legacy `--watch` token is accepted but ignored (stderr deprecation line).
8
8
 
9
- ## Spawn Primitive — Default Headless (M38 Domain 1)
9
+ ## Spawn Primitive — Always Headless (M43 D4, v2.0.0)
10
10
 
11
- Per `.gsd-t/contracts/headless-default-contract.md` v1.0.0. Spawn classifications used below:
11
+ Per `.gsd-t/contracts/headless-default-contract.md` v2.0.0. Spawn classifications used below:
12
12
 
13
13
  - `spawnType: 'validation'` — QA subagent (Step 5 contract compliance), Red Team (Step 7.5 adversarial), doc-ripple (Step 9)
14
14
 
15
- Default path is `autoSpawnHeadless({command, spawnType: 'validation', watch: false, projectDir, sessionContext})` — validation spawns ignore `--watch`. Read-back banner surfaces each completion.
15
+ Spawn path is `autoSpawnHeadless({command, spawnType: 'validation', projectDir, sessionContext})`. Read-back banner surfaces each completion.
16
16
 
17
17
  ## Model Assignment
18
18
 
@@ -103,6 +103,26 @@ If rolled-back domains exist, report them to the user (or if Level 3: log to `.g
103
103
  node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-id "${GSD_T_PARENT_AGENT_ID:-null}" --command gsd-t-integrate --step 3 --step-label "Wire Integration Points" 2>/dev/null || true
104
104
  ```
105
105
 
106
+ ### Optional — Parallel Dispatch (M44)
107
+
108
+ When integration work spans **more than one domain simultaneously** (i.e., the integration-points.md list contains independent integration tasks across multiple domains), the ready batch may be dispatched via `gsd-t parallel` instead of the sequential task-level dispatch below. When integration touches only one domain (single-domain wiring), the conditional is a no-op and the existing sequential path runs unchanged.
109
+
110
+ - **Conditional check** — only triggers when integrating > 1 domain AND the integration tasks pass D4 depgraph + D5 file-disjointness + D6 economics gates. Otherwise the block is a no-op.
111
+ - **Mode auto-detection** — mode is auto-detected from `GSD_T_UNATTENDED=1` by `bin/gsd-t-parallel.cjs`. Do not hardcode `--mode` in this command file.
112
+ - **Fallback** — any gate veto (unmet deps, overlapping write targets, unprovable disjointness) removes the affected tasks from the parallel batch; they fall back to the sequential task-dispatcher silently. No user prompt.
113
+ - **Observability** — D2 owns the spawn observability. The parallel path writes the same `.gsd-t/events/YYYY-MM-DD.jsonl` records (`gate_veto`, `parallelism_reduced`, `task_split`) and `.gsd-t/token-log.md` rows as the sequential path via `captureSpawn`. D3 adds no new spawn machinery.
114
+ - **Zero-compaction invariant (unattended)** — for `[unattended]` runs, D2 enforces zero-compaction by splitting integration tasks when D6 estimates > 60% per-worker CW.
115
+ - **In-session invariant** — NEVER interrupts the user with a pause/resume prompt. If headroom is tight, D2 reduces the worker count (floor N=1) and emits `parallelism_reduced`. If all gates fail, falls back to sequential silently. No opt-out flag exists (consistent with M43 D4: `--in-session` / `--headless` were never shipped).
116
+
117
+ Example (mode auto-detected from env):
118
+
119
+ ```bash
120
+ gsd-t parallel --milestone {milestone} --dry-run # preview plan, no spawn
121
+ gsd-t parallel --milestone {milestone} # live dispatch
122
+ ```
123
+
124
+ Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0.
125
+
106
126
  **Stack Rules Detection (before spawning subagent):**
107
127
  Run via Bash to detect project stack and collect matching rules:
108
128
  `GSD_T_DIR=$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t; STACKS_DIR="$GSD_T_DIR/templates/stacks"; STACK_RULES=""; if [ -d "$STACKS_DIR" ]; then for f in "$STACKS_DIR"/_*.md; do [ -f "$f" ] && STACK_RULES="${STACK_RULES}$(cat "$f")"$'\n\n'; done; if [ -f "package.json" ]; then grep -q '"react"' package.json 2>/dev/null && [ -f "$STACKS_DIR/react.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/react.md")"$'\n\n'; (grep -q '"typescript"' package.json 2>/dev/null || [ -f "tsconfig.json" ]) && [ -f "$STACKS_DIR/typescript.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/typescript.md")"$'\n\n'; grep -qE '"(express|fastify|hono|koa)"' package.json 2>/dev/null && [ -f "$STACKS_DIR/node-api.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/node-api.md")"$'\n\n'; fi; [ -f "requirements.txt" ] || [ -f "pyproject.toml" ] && [ -f "$STACKS_DIR/python.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/python.md")"$'\n\n'; [ -f "go.mod" ] && [ -f "$STACKS_DIR/go.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/go.md")"$'\n\n'; [ -f "Cargo.toml" ] && [ -f "$STACKS_DIR/rust.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/rust.md")"$'\n\n'; ([ -f ".gsd-t/contracts/design-contract.md" ] || [ -f "design-tokens.json" ] || [ -d "design-tokens" ] || [ -f ".figmarc" ] || [ -f "figma.config.json" ] || grep -q '"figma"' ~/.claude/settings.json 2>/dev/null) && [ -f "$STACKS_DIR/design-to-code.md" ] && STACK_RULES="${STACK_RULES}$(cat "$STACKS_DIR/design-to-code.md")"$'\n\n'; fi`
@@ -181,7 +201,7 @@ Result: PARTIAL — needs pagination contract addition
181
201
  node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-id "${GSD_T_PARENT_AGENT_ID:-null}" --command gsd-t-integrate --step 5 --step-label "Contract Compliance Testing" 2>/dev/null || true
182
202
  ```
183
203
 
184
- Spawn a QA subagent via the Task tool to verify contract compliance at all domain boundaries — `spawnType: 'validation'` (always headless, `--watch` ignored):
204
+ Spawn a QA subagent via the Task tool to verify contract compliance at all domain boundaries — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
185
205
 
186
206
  ```
187
207
  Task subagent (spawnType: validation, general-purpose, model: sonnet):
@@ -288,7 +308,7 @@ RT_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/red-team
288
308
  [ -f "$RT_PROMPT" ] || RT_PROMPT="templates/prompts/red-team-subagent.md"
289
309
  ```
290
310
 
291
- Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless, `--watch` ignored):
311
+ Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
292
312
 
293
313
  ```
294
314
  node -e "
@@ -327,7 +347,7 @@ After all integration work is committed but before reporting completion:
327
347
 
328
348
  1. Run threshold check — read `git diff --name-only HEAD~1` and evaluate against doc-ripple-contract.md trigger conditions
329
349
  2. If SKIP: log "Doc-ripple: SKIP — {reason}" and proceed to completion
330
- 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless, `--watch` ignored):
350
+ 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
331
351
 
332
352
  ⚙ [{model}] gsd-t-doc-ripple → blast radius analysis + parallel updates
333
353
 
@@ -4,16 +4,16 @@ You are executing a small, focused task that doesn't need full phase planning. T
4
4
 
5
5
  ## Argument Parsing
6
6
 
7
- Parse `$ARGUMENTS`. The first positional arg is the quick task description (`$TASK`). Detect `--watch` (sets `WATCH_FLAG=true`; default `false`). Per `.gsd-t/contracts/headless-default-contract.md` §2, `--watch` propagates only to the **primary** inner subagent (Step 0.1 fresh-dispatch). Validation spawns (Design Verification Step 5.25, Red Team Step 5.5, doc-ripple Step 6) always go headless regardless of `--watch`.
7
+ Parse `$ARGUMENTS`. The first positional arg is the quick task description (`$TASK`). M43 D4 removed the `--watch` opt-out; `--in-session`/`--headless` were never shipped. Under `.gsd-t/contracts/headless-default-contract.md` **v2.0.0** the inner subagent spawn (Step 0.1 fresh-dispatch) and all validation spawns (Design Verification Step 5.25, Red Team Step 5.5, doc-ripple Step 6) go headless unconditionally. A legacy `--watch` token is accepted but ignored (stderr deprecation line).
8
8
 
9
- ## Spawn Primitive — Default Headless (M38 Domain 1)
9
+ ## Spawn Primitive — Always Headless (M43 D4, v2.0.0)
10
10
 
11
- Per `.gsd-t/contracts/headless-default-contract.md` v1.0.0. Spawn classifications used below:
11
+ Per `.gsd-t/contracts/headless-default-contract.md` v2.0.0. Spawn classifications used below (both always headless):
12
12
 
13
13
  - `spawnType: 'primary'` — Step 0.1 fresh-dispatch subagent running the quick task
14
14
  - `spawnType: 'validation'` — Design Verification (Step 5.25), Red Team (Step 5.5), doc-ripple (Step 6)
15
15
 
16
- Default path is `autoSpawnHeadless({command, spawnType, watch: WATCH_FLAG, projectDir, sessionContext})`. Outer `gsd-t-quick` orchestrator stays interactive; the inner subagent goes headless by default and streams in-context only when `WATCH_FLAG=true`.
16
+ Spawn path is `autoSpawnHeadless({command, spawnType, projectDir, sessionContext})`. The outer `gsd-t-quick` command body is itself the interactive spawn target for the parent `/gsd` router nested spawns from this body always go headless.
17
17
 
18
18
  ## Model Assignment
19
19
 
@@ -34,14 +34,12 @@ To give this task a fresh context window and prevent compaction during consecuti
34
34
 
35
35
  **If you are the orchestrating agent** (you received the slash command directly):
36
36
 
37
- **Token Budget Check (before spawning subagent):**
37
+ **Context observation (before spawning subagent):**
38
38
 
39
- Run via Bash:
40
- `node -e "const tb = require('./bin/token-budget.cjs'); const s = tb.getSessionStatus('.'); process.stdout.write(s.threshold);" 2>/dev/null`
39
+ Run via Bash to capture `pct` for the NEXT spawn's token-log Ctx% column:
40
+ `node -e "const tb = require('./bin/token-budget.cjs'); const s = tb.getSessionStatus('.'); process.stdout.write(String(s.pct));" 2>/dev/null`
41
41
 
42
- Apply the single-band result per `context-meter-contract.md` v1.3.0:
43
- - `normal` (or file missing) → proceed with default model (sonnet).
44
- - `threshold` → the Context Meter's PostToolUse hook has already emitted the `next-spawn-headless:true` marker; route the subagent spawn through `autoSpawnHeadless()` so the work runs in a fresh headless context.
42
+ No gating under headless-default-contract v2.0.0 every spawn goes through `autoSpawnHeadless()` regardless of band. The capture is observational only.
45
43
 
46
44
  **Stack Rules Detection (before spawning subagent):**
47
45
 
@@ -105,7 +103,7 @@ Violations are task failures, not warnings.
105
103
 
106
104
  If STACK_RULES is empty (no templates/stacks/ dir or no matches), skip silently.
107
105
 
108
- Spawn a fresh subagent via `captureSpawn` — `spawnType: 'primary'` (respects `--watch`: headless by default, in-context when `WATCH_FLAG=true`):
106
+ Spawn a fresh subagent via `captureSpawn` — `spawnType: 'primary'` (always headless per headless-default-contract v2.0.0):
109
107
 
110
108
  **OBSERVABILITY LOGGING (MANDATORY) — wrap the primary subagent spawn with `captureSpawn`:**
111
109
 
@@ -186,6 +184,25 @@ Proceed.
186
184
  node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-id "${GSD_T_PARENT_AGENT_ID:-null}" --command gsd-t-quick --step 3 --step-label "Execute" 2>/dev/null || true
187
185
  ```
188
186
 
187
+ ### Optional — Parallel Dispatch (M44, lightweight · conditional-only)
188
+
189
+ **This block is a no-op for the typical quick invocation.** `gsd-t-quick` is designed for single-focus work; forcing parallel on every quick invocation would add gate overhead without benefit.
190
+
191
+ **Trigger conditions (BOTH must hold)**:
192
+ 1. `.gsd-t/domains/` contains more than one pending task, AND
193
+ 2. All three gates (D4 depgraph + D5 file-disjointness + D6 economics) pass for the candidate batch.
194
+
195
+ **If either condition fails** — and that includes the common case of a single-task quick invocation — skip this block entirely. The sequential single-subagent path in Step 0.1 remains unchanged.
196
+
197
+ **If BOTH conditions hold** — dispatch the ready batch via `gsd-t parallel` (mode auto-detected from `GSD_T_UNATTENDED=1`; do not hardcode `--mode`):
198
+
199
+ - Fallback is silent — any gate veto drops the affected tasks back to the sequential quick path.
200
+ - D2 owns the spawn observability; the parallel path writes the same `.gsd-t/events/YYYY-MM-DD.jsonl` records and `.gsd-t/token-log.md` rows via `captureSpawn`. D3 adds no new spawn machinery.
201
+ - `[unattended]` — D2 enforces the zero-compaction contract by splitting tasks when D6 estimates > 60% per-worker CW.
202
+ - `[in-session]` — NEVER interrupts the user with a pause/resume prompt. If headroom is tight, D2 reduces the worker count (floor N=1). No opt-out flag exists (consistent with M43 D4: `--in-session` / `--headless` were never shipped).
203
+
204
+ Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0.
205
+
189
206
  ### Deviation Rules
190
207
 
191
208
  When you encounter unexpected situations:
@@ -426,7 +443,7 @@ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
426
443
  description: 'adversarial validation of quick task',
427
444
  projectDir: '.',
428
445
  notes: '{VERDICT} — {N} bugs found',
429
- spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus) — always headless, --watch ignored:
446
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus) — always headless per headless-default-contract v2.0.0:
430
447
  'Read \$RT_PROMPT and follow it. Context for this run: quick task — adversarial validation of the code just changed. Write findings to .gsd-t/red-team-report.md.' */ },
431
448
  });
432
449
  })();
@@ -452,7 +469,7 @@ After all work is committed but before reporting completion:
452
469
 
453
470
  1. Run threshold check — read `git diff --name-only HEAD~1` and evaluate against doc-ripple-contract.md trigger conditions
454
471
  2. If SKIP: log "Doc-ripple: SKIP — {reason}" and proceed to completion
455
- 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless, `--watch` ignored):
472
+ 3. If FIRE: spawn doc-ripple agent — `spawnType: 'validation'` (always headless per headless-default-contract v2.0.0):
456
473
 
457
474
  ⚙ [{model}] gsd-t-doc-ripple → blast radius analysis + parallel updates
458
475
 
@@ -4,16 +4,16 @@ You are the lead agent performing a comprehensive analysis of an existing codeba
4
4
 
5
5
  ## Argument Parsing
6
6
 
7
- Parse `$ARGUMENTS`. Detect `--watch` (sets `WATCH_FLAG=true`; default `false`). Per `.gsd-t/contracts/headless-default-contract.md` §2, `--watch` propagates to the **primary** scan spawns (Step 0 outer subagent, Step 2 dimension agents). Step 5 living-document updates and Step 8 HTML report are validation-style they always go headless.
7
+ Parse `$ARGUMENTS`. M43 D4 removed the `--watch` opt-out; `--in-session`/`--headless` were never shipped. Under `.gsd-t/contracts/headless-default-contract.md` **v2.0.0** every scan spawn goes headless unconditionally (Step 0 outer subagent, Step 2 dimension agents, Step 3 synthesis agent, Step 5 living-document updater, Step 8 HTML report generator). A legacy `--watch` token is accepted but ignored (stderr deprecation line).
8
8
 
9
- ## Spawn Primitive — Default Headless (M38 Domain 1)
9
+ ## Spawn Primitive — Always Headless (M43 D4, v2.0.0)
10
10
 
11
- Per `.gsd-t/contracts/headless-default-contract.md` v1.0.0. Spawn classifications used below:
11
+ Per `.gsd-t/contracts/headless-default-contract.md` v2.0.0. Spawn classifications used below (both always headless):
12
12
 
13
13
  - `spawnType: 'primary'` — Step 0 outer fresh-dispatch subagent, Step 2 dimension agents, Step 3 synthesis agent
14
14
  - `spawnType: 'validation'` — Step 5 living-document updater, Step 8 HTML report generator
15
15
 
16
- Default path is `autoSpawnHeadless({command, spawnType, watch: WATCH_FLAG, projectDir, sessionContext})`.
16
+ Spawn path is `autoSpawnHeadless({command, spawnType, projectDir, sessionContext})`.
17
17
 
18
18
  ## Step 0: Launch via Subagent
19
19
 
@@ -24,7 +24,7 @@ node scripts/gsd-t-watch-state.js advance --agent-id "$GSD_T_AGENT_ID" --parent-
24
24
  Scans are long-running and context-heavy. Always execute via a Task subagent for a fresh context window.
25
25
 
26
26
  **If you are the orchestrating agent** (you received the slash command directly):
27
- Spawn a fresh subagent using the Task tool — `spawnType: 'primary'` (respects `--watch`: headless by default, in-context when `WATCH_FLAG=true`):
27
+ Spawn a fresh subagent using the Task tool — `spawnType: 'primary'` (always headless per headless-default-contract v2.0.0):
28
28
  ```
29
29
  subagent_type: general-purpose
30
30
  spawnType: primary
@@ -54,13 +54,14 @@ const LOG_FILE = path.join(UDIR, 'run.log');
54
54
 
55
55
  function out(k, v) { console.log(k + '=' + JSON.stringify(v ?? null)); }
56
56
 
57
- // --- PID file ---
57
+ // --- PID file (JSON or legacy bare-integer; canonical reader handles both) ---
58
58
  let pid = null;
59
59
  let pidFileExists = fs.existsSync(PID_FILE);
60
60
  if (pidFileExists) {
61
61
  try {
62
- pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
63
- if (!Number.isFinite(pid)) pid = null;
62
+ const { readPidFile } = require('./bin/supervisor-pid-fingerprint.cjs');
63
+ const entry = readPidFile(process.cwd());
64
+ pid = entry && Number.isInteger(entry.pid) ? entry.pid : null;
64
65
  } catch (_) { pid = null; }
65
66
  }
66
67
  out('PID_FILE_EXISTS', pidFileExists);
@@ -43,7 +43,9 @@ if (!fs.existsSync(PID_FILE)) {
43
43
 
44
44
  let pid = null;
45
45
  try {
46
- pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
46
+ const { readPidFile } = require('./bin/supervisor-pid-fingerprint.cjs');
47
+ const entry = readPidFile(process.cwd());
48
+ pid = entry && Number.isInteger(entry.pid) ? entry.pid : null;
47
49
  } catch (_) {}
48
50
 
49
51
  if (!pid || !Number.isFinite(pid)) {
@@ -361,9 +363,13 @@ while (Date.now() < deadline) {
361
363
  alive = e.code === 'EPERM';
362
364
  }
363
365
  }
364
- // Also try reading the PID file the supervisor writes
366
+ // Also try reading the PID file the supervisor writes (JSON or legacy bare-integer)
365
367
  if (fs.existsSync(PID_FILE)) {
366
- try { pidFromFile = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10); } catch (_) {}
368
+ try {
369
+ const { readPidFile } = require('./bin/supervisor-pid-fingerprint.cjs');
370
+ const entry = readPidFile(process.cwd());
371
+ pidFromFile = entry && Number.isInteger(entry.pid) ? entry.pid : null;
372
+ } catch (_) {}
367
373
  }
368
374
  if (alive || pidFromFile) break;
369
375
  sleep(POLL_MS);
@@ -4,15 +4,15 @@ You are the lead agent coordinating verification of the completed work. Each ver
4
4
 
5
5
  ## Argument Parsing
6
6
 
7
- Parse `$ARGUMENTS`. Detect `--watch` (sets `WATCH_FLAG=true`; default `false`). Per `.gsd-t/contracts/headless-default-contract.md` §2, verify spawns are ALL classified as **validation** (the work product is a verdict, not a code change) — they always go headless regardless of `--watch`.
7
+ Parse `$ARGUMENTS`. M43 D4 removed the `--watch` opt-out; `--in-session`/`--headless` were never shipped. Under `.gsd-t/contracts/headless-default-contract.md` **v2.0.0** every verify spawn goes headless unconditionally. A legacy `--watch` token is accepted but ignored (stderr deprecation line).
8
8
 
9
- ## Spawn Primitive — Default Headless (M38 Domain 1)
9
+ ## Spawn Primitive — Always Headless (M43 D4, v2.0.0)
10
10
 
11
- Per `.gsd-t/contracts/headless-default-contract.md` v1.0.0. Spawn classifications used below:
11
+ Per `.gsd-t/contracts/headless-default-contract.md` v2.0.0. Spawn classifications used below:
12
12
 
13
13
  - `spawnType: 'validation'` — Step 4 test-audit subagent, Step 8 auto-invoke complete-milestone
14
14
 
15
- Default path is `autoSpawnHeadless({command, spawnType: 'validation', watch: false, projectDir, sessionContext})`. Auto-invoke of complete-milestone (Step 8) is preserved — it is spawned headless via the same primitive and surfaces via the read-back banner.
15
+ Spawn path is `autoSpawnHeadless({command, spawnType: 'validation', projectDir, sessionContext})`. Auto-invoke of complete-milestone (Step 8) is preserved — spawned headless via the same primitive and surfaced via the read-back banner.
16
16
 
17
17
  ## Model Assignment
18
18
 
@@ -421,7 +421,7 @@ If status is VERIFIED or VERIFIED-WITH-WARNINGS:
421
421
 
422
422
  **OBSERVABILITY LOGGING (MANDATORY) — wrap the complete-milestone auto-invoke with `captureSpawn`:**
423
423
 
424
- 2. Spawn through `captureSpawn` — `spawnType: 'validation'`, model: sonnet, mode: bypassPermissions (always headless, `--watch` ignored):
424
+ 2. Spawn through `captureSpawn` — `spawnType: 'validation'`, model: sonnet, mode: bypassPermissions (always headless per headless-default-contract v2.0.0):
425
425
 
426
426
  ```
427
427
  node -e "