@tekyzinc/gsd-t 3.13.16 → 3.16.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 (54) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +1 -0
  3. package/bin/gsd-t-benchmark-orchestrator.js +437 -0
  4. package/bin/gsd-t-capture-lint.cjs +276 -0
  5. package/bin/gsd-t-completion-check.cjs +106 -0
  6. package/bin/gsd-t-orchestrator-config.cjs +64 -0
  7. package/bin/gsd-t-orchestrator-queue.cjs +180 -0
  8. package/bin/gsd-t-orchestrator-recover.cjs +231 -0
  9. package/bin/gsd-t-orchestrator-worker.cjs +219 -0
  10. package/bin/gsd-t-orchestrator.js +534 -0
  11. package/bin/gsd-t-stream-feed-client.cjs +151 -0
  12. package/bin/gsd-t-task-brief-compactor.cjs +89 -0
  13. package/bin/gsd-t-task-brief-template.cjs +96 -0
  14. package/bin/gsd-t-task-brief.js +249 -0
  15. package/bin/gsd-t-token-backfill.cjs +366 -0
  16. package/bin/gsd-t-token-capture.cjs +306 -0
  17. package/bin/gsd-t-token-dashboard.cjs +318 -0
  18. package/bin/gsd-t-token-regenerate-log.cjs +129 -0
  19. package/bin/gsd-t-transcript-tee.cjs +246 -0
  20. package/bin/gsd-t-unattended-heartbeat.cjs +188 -0
  21. package/bin/gsd-t-unattended-platform.cjs +191 -27
  22. package/bin/gsd-t-unattended-safety.cjs +8 -1
  23. package/bin/gsd-t-unattended.cjs +192 -31
  24. package/bin/gsd-t.js +329 -2
  25. package/bin/supervisor-pid-fingerprint.cjs +126 -0
  26. package/commands/gsd-t-debug.md +63 -51
  27. package/commands/gsd-t-design-decompose.md +2 -7
  28. package/commands/gsd-t-doc-ripple.md +20 -11
  29. package/commands/gsd-t-execute.md +82 -50
  30. package/commands/gsd-t-integrate.md +43 -16
  31. package/commands/gsd-t-plan.md +20 -7
  32. package/commands/gsd-t-prd.md +19 -12
  33. package/commands/gsd-t-quick.md +64 -29
  34. package/commands/gsd-t-resume.md +51 -4
  35. package/commands/gsd-t-unattended.md +19 -20
  36. package/commands/gsd-t-verify.md +48 -32
  37. package/commands/gsd-t-visualize.md +19 -17
  38. package/commands/gsd-t-wave.md +29 -27
  39. package/docs/architecture.md +16 -0
  40. package/docs/m40-benchmark-report.md +35 -0
  41. package/docs/requirements.md +20 -0
  42. package/package.json +1 -1
  43. package/scripts/gsd-t-dashboard-server.js +291 -4
  44. package/scripts/gsd-t-dashboard.html +31 -1
  45. package/scripts/gsd-t-design-review-server.js +3 -1
  46. package/scripts/gsd-t-stream-feed-server.js +428 -0
  47. package/scripts/gsd-t-stream-feed.html +1168 -0
  48. package/scripts/gsd-t-token-aggregator.js +373 -0
  49. package/scripts/gsd-t-transcript.html +422 -0
  50. package/scripts/hooks/gsd-t-in-session-probe.js +62 -0
  51. package/scripts/hooks/pre-commit-capture-lint +26 -0
  52. package/templates/CLAUDE-global.md +69 -0
  53. package/scripts/gsd-t-agent-dashboard-server.js +0 -424
  54. package/scripts/gsd-t-agent-dashboard.html +0 -1043
@@ -358,9 +358,7 @@ After writing all contracts but BEFORE proceeding to partition or build, spawn a
358
358
 
359
359
  > **Why a separate agent?** The decompose agent that classified the charts cannot objectively verify its own classifications. It has the same blind spots that caused the misclassification. This was proven repeatedly — the same agent rubber-stamps its own work. A fresh agent with only the contracts and Figma access catches what the classifier missed.
360
360
 
361
- **OBSERVABILITY LOGGING (MANDATORY):**
362
- Before spawning — run via Bash:
363
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
361
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the Chart Classification Verifier spawn with `captureSpawn`:** route through `bin/gsd-t-token-capture.cjs` with `{command: 'gsd-t-design-decompose', step: 'Chart Classification Verifier', model: 'opus', projectDir: '.', notes: 'verification {PASSED/FAILED}'}`. The wrapper owns banner + timing + envelope parse + row write.
364
362
 
365
363
  ⚙ [opus] gsd-t-design-decompose → Chart Classification Verifier
366
364
 
@@ -443,10 +441,7 @@ If ALL ✅ MATCH:
443
441
  "
444
442
  ```
445
443
 
446
- After subagent returns run via Bash:
447
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
448
-
449
- Compute tokens/compaction per standard pattern. Append to `.gsd-t/token-log.md`.
444
+ After the `captureSpawn` wrapper returns, the row is already written to `.gsd-t/token-log.md` under the canonical header with Tokens = `in=N out=N cr=N cc=N $X.XX` (or `—` if no envelope). No post-processing needed.
450
445
 
451
446
  **If VERIFICATION FAILED**: Fix every misclassified element contract before proceeding:
452
447
  1. Rename the contract file to match the correct chart type
@@ -97,19 +97,28 @@ For each document or logical group:
97
97
  ⚙ [haiku] gsd-t-doc-ripple → update {document}
98
98
  (Use sonnet for docs/architecture.md and docs/requirements.md — these need reasoning.)
99
99
 
100
- **OBSERVABILITY LOGGING (MANDATORY) — for each subagent spawn:**
100
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap each document-update subagent with `captureSpawn`:**
101
101
 
102
- Before spawning — run via Bash:
103
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
104
-
105
- After subagent returns — run via Bash:
106
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
107
-
108
- Read the real context% from the Context Meter state file:
109
- `CTX_PCT=$(node -e "try{const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct))}catch(_){process.stdout.write('N/A')}")`
102
+ ```
103
+ node -e "
104
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
105
+ (async () => {
106
+ await captureSpawn({
107
+ command: 'gsd-t-doc-ripple',
108
+ step: 'Step 5',
109
+ model: '{haiku|sonnet}',
110
+ description: 'update {document}',
111
+ projectDir: '.',
112
+ domain: 'doc-ripple',
113
+ task: '-',
114
+ notes: 'update:{document}',
115
+ spawnFn: async () => { /* Task subagent call for the document-update prompt below */ },
116
+ });
117
+ })();
118
+ "
119
+ ```
110
120
 
111
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task | Ctx% |` if missing):
112
- `| {DT_START} | {DT_END} | gsd-t-doc-ripple | Step 5 | {model} | {DURATION}s | update:{document} | doc-ripple | — | {CTX_PCT} |`
121
+ `captureSpawn` parses `result.usage` and writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
113
122
 
114
123
  **Each document-update subagent prompt:**
115
124
  ```
@@ -170,18 +170,30 @@ Each domain's work runs via a lightweight domain task-dispatcher. The dispatcher
170
170
  - Up to 5 prior task summaries (10-20 lines each, most recent first)
171
171
  - Past failure/learning entries for this domain (max 5 lines)
172
172
 
173
- **OBSERVABILITY LOGGING (MANDATORY) — repeat for every task subagent spawn:**
173
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap every task subagent spawn with `captureSpawn`:**
174
174
 
175
- Before spawning run via Bash:
176
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
175
+ Route the spawn through `bin/gsd-t-token-capture.cjs` so the real `usage` envelope is parsed. The wrapper owns banner + timing + envelope parse + row write + JSONL record. Example for a per-task dispatch:
177
176
 
178
- After subagent returns — run via Bash:
179
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
180
-
181
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task | Ctx% |` if missing):
182
- `| {DT_START} | {DT_END} | gsd-t-execute | task:{task-id} | sonnet | {DURATION}s | {pass/fail} | {domain-name} | task-{task-id} | {CTX_PCT} |`
177
+ ```
178
+ node -e "
179
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
180
+ (async () => {
181
+ await captureSpawn({
182
+ command: 'gsd-t-execute',
183
+ step: 'task:{task-id}',
184
+ model: 'sonnet',
185
+ description: 'domain: {domain-name} task: {task-id}',
186
+ projectDir: '.',
187
+ domain: '{domain-name}',
188
+ task: '{task-id}',
189
+ notes: '{pass/fail}',
190
+ spawnFn: async () => { /* Task(...) or spawn('claude', ...) call */ },
191
+ });
192
+ })();
193
+ "
194
+ ```
183
195
 
184
- Where `{CTX_PCT}` is the current `pct` value returned by `getSessionStatus()` (Step 3.5). As of v2.0.0 (M34), `pct` reads the **real** `input_tokens` count from `.gsd-t/.context-meter-state.json` — the count_tokens-based measurement produced by the Context Meter PostToolUse hook. When the state file is absent or stale, the fallback heuristic writes a best-effort percentage and this column reads `N/A` instead. The previous `Tasks-Since-Reset` column (v2.74.12) is retired.
196
+ `captureSpawn` writes the row to `.gsd-t/token-log.md` under the canonical header (`| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Tokens | Notes | Domain | Task | Ctx% |`) — upgrading old headers in place. The **Tokens** cell renders as `in=N out=N cr=N cc=N $X.XX` when `result.usage` is present, or `—` when absent. Never `0`. Never `N/A`. The wrapper also pulls `Ctx%` from `getSessionStatus()` automatically (Step 3.5 context) `pct` reads the real `input_tokens` count from `.gsd-t/.context-meter-state.json` produced by the Context Meter PostToolUse hook; when the state file is absent or stale, it reads `N/A`.
185
197
 
186
198
  **For each domain (in wave order), run the domain task-dispatcher:**
187
199
 
@@ -753,9 +765,7 @@ If it DOES exist AND this domain touched UI files — spawn the **Design Verific
753
765
 
754
766
  ⚙ [opus] Design Verification → visual comparison for domain {domain-name}
755
767
 
756
- **OBSERVABILITY LOGGING (MANDATORY):**
757
- Before spawning — run via Bash:
758
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
768
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the Design Verification spawn with `captureSpawn`:**
759
769
 
760
770
  Resolve the templated prompt path first so the orchestrator never holds the full ~3500-token verification protocol in its own context:
761
771
 
@@ -764,23 +774,35 @@ DV_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/design-v
764
774
  [ -f "$DV_PROMPT" ] || DV_PROMPT="templates/prompts/design-verify-subagent.md"
765
775
  ```
766
776
 
767
- Then spawn the subagent with this short prompt — `spawnType: 'validation'` (always headless, `--watch` ignored):
768
-
769
- ```
770
- Task subagent (spawnType: validation, general-purpose, model: opus):
771
- "You are the Design Verification Agent. Read $DV_PROMPT and follow it exactly.
772
- Do not deviate from that protocol. Context for this run:
773
- - domain: {domain-name}
774
- - design contract: .gsd-t/contracts/design-contract.md
775
- - files modified by this domain: {list}
776
- Report back the verdict, match count, breakpoints verified, deviation count
777
- and summary, and the full comparison table per the protocol's Step 7."
778
- ```
779
-
780
- After subagent returns — run via Bash:
781
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "try{const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct))}catch(_){process.stdout.write('N/A')}")`
782
- Append to `.gsd-t/token-log.md`:
783
- `| {DT_START} | {DT_END} | gsd-t-execute | Design Verify | opus | {DURATION}s | {VERDICT} — {MATCH}/{TOTAL} elements for {domain-name} | | | {CTX_PCT} |`
777
+ Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless, `--watch` ignored):
778
+
779
+ ```
780
+ node -e "
781
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
782
+ (async () => {
783
+ await captureSpawn({
784
+ command: 'gsd-t-execute',
785
+ step: 'Design Verify',
786
+ model: 'opus',
787
+ description: 'visual comparison for domain {domain-name}',
788
+ projectDir: '.',
789
+ domain: '{domain-name}',
790
+ task: '-',
791
+ notes: '{VERDICT} {MATCH}/{TOTAL} elements',
792
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus):
793
+ 'You are the Design Verification Agent. Read $DV_PROMPT and follow it exactly.
794
+ Do not deviate from that protocol. Context for this run:
795
+ - domain: {domain-name}
796
+ - design contract: .gsd-t/contracts/design-contract.md
797
+ - files modified by this domain: {list}
798
+ Report back the verdict, match count, breakpoints verified, deviation count
799
+ and summary, and the full comparison table per the protocol's Step 7.' */ },
800
+ });
801
+ })();
802
+ "
803
+ ```
804
+
805
+ `captureSpawn` parses `result.usage` and appends a row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
784
806
 
785
807
  **Artifact Gate (MANDATORY):**
786
808
  After the Design Verification Agent returns, check `.gsd-t/contracts/design-contract.md`:
@@ -809,9 +831,7 @@ After all tasks in the CURRENT DOMAIN pass their tests, spawn an adversarial Red
809
831
 
810
832
  ⚙ [opus] Red Team → adversarial validation for domain {domain-name}
811
833
 
812
- **OBSERVABILITY LOGGING (MANDATORY):**
813
- Before spawning — run via Bash:
814
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
834
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the Red Team spawn with `captureSpawn`:**
815
835
 
816
836
  Resolve the templated prompt path so the orchestrator never holds the full ~3500-token Red Team protocol in its own context:
817
837
 
@@ -820,24 +840,36 @@ RT_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/red-team
820
840
  [ -f "$RT_PROMPT" ] || RT_PROMPT="templates/prompts/red-team-subagent.md"
821
841
  ```
822
842
 
823
- Then spawn the subagent with this short prompt — `spawnType: 'validation'` (always headless, `--watch` ignored):
824
-
825
- ```
826
- Task subagent (spawnType: validation, general-purpose, model: opus):
827
- "You are a Red Team QA adversary. Read $RT_PROMPT and follow it exactly.
828
- Do not deviate from that protocol. Context for this run:
829
- - domain: {domain-name}
830
- - files modified by this domain: {list}
831
- - tasks just completed: {task-id list}
832
- Report back the verdict (FAIL or GRUDGING PASS), bugs found by severity,
833
- attack categories exhausted, and the path to the written
834
- .gsd-t/red-team-report.md."
835
- ```
836
-
837
- After subagent returns run via Bash:
838
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "try{const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct))}catch(_){process.stdout.write('N/A')}")`
839
- Append to `.gsd-t/token-log.md`:
840
- `| {DT_START} | {DT_END} | gsd-t-execute | Red Team | opus | {DURATION}s | {VERDICT} — {N} bugs found in {domain-name} | | | {CTX_PCT} |`
843
+ Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless, `--watch` ignored):
844
+
845
+ ```
846
+ node -e "
847
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
848
+ (async () => {
849
+ await captureSpawn({
850
+ command: 'gsd-t-execute',
851
+ step: 'Red Team',
852
+ model: 'opus',
853
+ description: 'adversarial validation for domain {domain-name}',
854
+ projectDir: '.',
855
+ domain: '{domain-name}',
856
+ task: '-',
857
+ notes: '{VERDICT}{N} bugs found',
858
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus):
859
+ 'You are a Red Team QA adversary. Read $RT_PROMPT and follow it exactly.
860
+ Do not deviate from that protocol. Context for this run:
861
+ - domain: {domain-name}
862
+ - files modified by this domain: {list}
863
+ - tasks just completed: {task-id list}
864
+ Report back the verdict (FAIL or GRUDGING PASS), bugs found by severity,
865
+ attack categories exhausted, and the path to the written
866
+ .gsd-t/red-team-report.md.' */ },
867
+ });
868
+ })();
869
+ "
870
+ ```
871
+
872
+ `captureSpawn` parses `result.usage` and appends a row to `.gsd-t/token-log.md`. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
841
873
 
842
874
  **If Red Team VERDICT is FAIL:**
843
875
  1. Fix all CRITICAL and HIGH bugs immediately (up to 2 fix attempts per bug)
@@ -209,13 +209,26 @@ After all scripted tests pass:
209
209
  Note: Exploratory findings do NOT count against the scripted test pass/fail ratio."
210
210
  ```
211
211
 
212
- **OBSERVABILITY LOGGING (MANDATORY):**
213
- Before spawning — run via Bash:
214
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
215
- After subagent returns — run via Bash:
216
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
217
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task | Ctx% |` if missing):
218
- `| {DT_START} | {DT_END} | gsd-t-integrate | Step 5 | haiku | {DURATION}s | {pass/fail}, {N} boundaries tested | | | {CTX_PCT} |`
212
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the Step 5 validation spawn with `captureSpawn`:**
213
+
214
+ ```
215
+ node -e "
216
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
217
+ (async () => {
218
+ await captureSpawn({
219
+ command: 'gsd-t-integrate',
220
+ step: 'Step 5',
221
+ model: 'haiku',
222
+ description: 'cross-boundary integration QA',
223
+ projectDir: '.',
224
+ notes: '{pass/fail}, {N} boundaries tested',
225
+ spawnFn: async () => { /* Task validation subagent call */ },
226
+ });
227
+ })();
228
+ "
229
+ ```
230
+
231
+ `captureSpawn` writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
219
232
  If QA found issues, append each to `.gsd-t/qa-issues.md` (create with header `| Date | Command | Step | Model | Duration(s) | Severity | Finding |` if missing):
220
233
  `| {DT_START} | gsd-t-integrate | Step 5 | haiku | {DURATION}s | {severity} | {finding} |`
221
234
 
@@ -270,22 +283,36 @@ After integration tests pass, spawn an adversarial Red Team agent on the integra
270
283
  ⚙ [opus] Red Team → adversarial validation of integrated system
271
284
 
272
285
  Resolve the templated prompt path via Bash:
273
- ```
286
+ ```bash
274
287
  RT_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/red-team-subagent.md"
275
288
  [ -f "$RT_PROMPT" ] || RT_PROMPT="templates/prompts/red-team-subagent.md"
276
- T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")
277
289
  ```
278
290
 
279
- Spawn Task subagent (spawnType: validation, general-purpose, model: opus) — always headless, `--watch` ignored:
280
- > "Read `$RT_PROMPT` and follow it. Context: cross-domain integration run. **Additional category for this run: Cross-Domain Boundaries** — test data flow across every domain boundary; does data arriving from domain A get validated by domain B; what happens when A sends malformed data that passed A's own validation. Write findings to `.gsd-t/red-team-report.md`."
291
+ Then spawn through `captureSpawn` — `spawnType: 'validation'` (always headless, `--watch` ignored):
281
292
 
282
- After subagent returns — run via Bash:
283
293
  ```
284
- T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))
285
- CTX_PCT=$(node -e "try{const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct))}catch(_){process.stdout.write('N/A')}")
294
+ node -e "
295
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
296
+ (async () => {
297
+ await captureSpawn({
298
+ command: 'gsd-t-integrate',
299
+ step: 'Red Team',
300
+ model: 'opus',
301
+ description: 'cross-domain adversarial validation',
302
+ projectDir: '.',
303
+ notes: '{VERDICT} — {N} bugs found',
304
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus):
305
+ 'Read \$RT_PROMPT and follow it. Context: cross-domain integration run.
306
+ Additional category for this run: Cross-Domain Boundaries — test data flow across every
307
+ domain boundary; does data arriving from domain A get validated by domain B; what happens
308
+ when A sends malformed data that passed A own validation.
309
+ Write findings to .gsd-t/red-team-report.md.' */ },
310
+ });
311
+ })();
312
+ "
286
313
  ```
287
- Append to `.gsd-t/token-log.md`:
288
- `| {DT_START} | {DT_END} | gsd-t-integrate | Red Team | opus | {DURATION}s | {VERDICT} {N} bugs found | | | {CTX_PCT} |`
314
+
315
+ `captureSpawn` writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
289
316
 
290
317
  **If FAIL:** fix CRITICAL/HIGH bugs (≤2 cycles) → re-run. Persistent bugs → `.gsd-t/deferred-items.md`.
291
318
  **If GRUDGING PASS:** proceed to doc-ripple.
@@ -415,13 +415,26 @@ Check:
415
415
  Report: PASS (all checks pass) or FAIL with specific gaps listed."
416
416
  ```
417
417
 
418
- **OBSERVABILITY LOGGING (MANDATORY):**
419
- Before spawning — run via Bash:
420
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
421
- After subagent returns — run via Bash:
422
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
423
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task | Ctx% |` if missing):
424
- `| {DT_START} | {DT_END} | gsd-t-plan | Step 7 | haiku | {DURATION}s | {PASS/FAIL}, iteration {N} | | | {CTX_PCT} |`
418
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the validation spawn with `captureSpawn`:**
419
+
420
+ ```
421
+ node -e "
422
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
423
+ (async () => {
424
+ await captureSpawn({
425
+ command: 'gsd-t-plan',
426
+ step: 'Step 7',
427
+ model: 'haiku',
428
+ description: 'plan validation, iteration {N}',
429
+ projectDir: '.',
430
+ notes: '{PASS/FAIL}, iteration {N}',
431
+ spawnFn: async () => { /* Task validation subagent call */ },
432
+ });
433
+ })();
434
+ "
435
+ ```
436
+
437
+ `captureSpawn` parses `result.usage` and writes the row to `.gsd-t/token-log.md` under the canonical header (Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`).
425
438
  If validation FAIL, append each gap to `.gsd-t/qa-issues.md` (create with header `| Date | Command | Step | Model | Duration(s) | Severity | Finding |` if missing):
426
439
  `| {DT_START} | gsd-t-plan | Step 7 | haiku | {DURATION}s | medium | {gap description} |`
427
440
 
@@ -10,22 +10,29 @@ To give PRD generation a fresh context window:
10
10
 
11
11
  **If you are the orchestrating agent** (you received the slash command directly):
12
12
 
13
- **OBSERVABILITY LOGGING (MANDATORY):**
14
- Before spawning — run via Bash:
15
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
13
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the PRD subagent spawn with `captureSpawn`:**
16
14
 
17
- Spawn a fresh subagent using the Task tool:
18
15
  ```
19
- subagent_type: general-purpose
20
- prompt: "You are running gsd-t-prd for this request: {$ARGUMENTS}
21
- Working directory: {current project root}
22
- Read CLAUDE.md and .gsd-t/progress.md for project context, then execute gsd-t-prd starting at Step 1."
16
+ node -e "
17
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
18
+ (async () => {
19
+ await captureSpawn({
20
+ command: 'gsd-t-prd',
21
+ step: 'Step 0',
22
+ model: 'sonnet',
23
+ description: 'prd: {topic summary}',
24
+ projectDir: '.',
25
+ notes: 'prd: {topic summary}',
26
+ spawnFn: async () => { /* Task subagent (subagent_type: general-purpose):
27
+ 'You are running gsd-t-prd for this request: {\$ARGUMENTS}
28
+ Working directory: {current project root}
29
+ Read CLAUDE.md and .gsd-t/progress.md for project context, then execute gsd-t-prd starting at Step 1.' */ },
30
+ });
31
+ })();
32
+ "
23
33
  ```
24
34
 
25
- After subagent returns run via Bash:
26
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
27
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
28
- `| {DT_START} | {DT_END} | gsd-t-prd | Step 0 | sonnet | {DURATION}s | prd: {topic summary} | {CTX_PCT} |`
35
+ `captureSpawn` parses `result.usage` and writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
29
36
 
30
37
  Relay the subagent's summary to the user. **Do not execute Steps 1–6 yourself.**
31
38
 
@@ -34,10 +34,6 @@ 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
- **OBSERVABILITY LOGGING (MANDATORY):**
38
- Before spawning — run via Bash:
39
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
40
-
41
37
  **Token Budget Check (before spawning subagent):**
42
38
 
43
39
  Run via Bash:
@@ -109,20 +105,32 @@ Violations are task failures, not warnings.
109
105
 
110
106
  If STACK_RULES is empty (no templates/stacks/ dir or no matches), skip silently.
111
107
 
112
- Spawn a fresh subagent using the Task tool — `spawnType: 'primary'` (respects `--watch`: headless by default, in-context when `WATCH_FLAG=true`):
108
+ Spawn a fresh subagent via `captureSpawn` — `spawnType: 'primary'` (respects `--watch`: headless by default, in-context when `WATCH_FLAG=true`):
109
+
110
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the primary subagent spawn with `captureSpawn`:**
111
+
113
112
  ```
114
- subagent_type: general-purpose
115
- spawnType: primary
116
- prompt: "You are running gsd-t-quick for this request: {$ARGUMENTS}
117
- Working directory: {current project root}
118
- Read CLAUDE.md and .gsd-t/progress.md for project context, then execute gsd-t-quick starting at Step 1.
119
- {STACK_RULES block — if non-empty, append the ## Stack Rules section defined above; omit if empty}"
113
+ node -e "
114
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
115
+ (async () => {
116
+ await captureSpawn({
117
+ command: 'gsd-t-quick',
118
+ step: 'Step 0',
119
+ model: 'sonnet',
120
+ description: 'quick: {task summary}',
121
+ projectDir: '.',
122
+ notes: 'quick: {task summary}',
123
+ spawnFn: async () => { /* Task subagent (general-purpose, spawnType: primary, model: sonnet):
124
+ 'You are running gsd-t-quick for this request: {\$ARGUMENTS}
125
+ Working directory: {current project root}
126
+ Read CLAUDE.md and .gsd-t/progress.md for project context, then execute gsd-t-quick starting at Step 1.
127
+ {STACK_RULES block — if non-empty, append the ## Stack Rules section defined above; omit if empty}' */ },
128
+ });
129
+ })();
130
+ "
120
131
  ```
121
132
 
122
- After subagent returns run via Bash:
123
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
124
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
125
- `| {DT_START} | {DT_END} | gsd-t-quick | Step 0 | sonnet | {DURATION}s | quick: {task summary} | {CTX_PCT} |`
133
+ `captureSpawn` parses `result.usage` and writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
126
134
 
127
135
  Relay the subagent's summary to the user. **Do not execute Steps 1–5 yourself.**
128
136
 
@@ -305,11 +313,30 @@ After tests pass, check if `.gsd-t/contracts/design-contract.md` exists. If it d
305
313
 
306
314
  If it DOES exist and this task involved UI changes — spawn the Design Verification Agent. This agent's ONLY job is to open a browser, compare the built frontend against the original design, and produce a structured comparison table. It writes NO feature code.
307
315
 
308
- ⚙ [{model}] Design Verification → visual comparison of built frontend vs design
316
+ ⚙ [opus] Design Verification → visual comparison of built frontend vs design
317
+
318
+ **OBSERVABILITY LOGGING (MANDATORY) — wrap the Design Verification subagent spawn with `captureSpawn`:**
319
+
320
+ ```
321
+ node -e "
322
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
323
+ (async () => {
324
+ await captureSpawn({
325
+ command: 'gsd-t-quick',
326
+ step: 'Design Verify',
327
+ model: 'opus',
328
+ description: 'visual comparison of built frontend vs design',
329
+ projectDir: '.',
330
+ notes: 'design-verify',
331
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus) — body below */ },
332
+ });
333
+ })();
334
+ "
335
+ ```
336
+
337
+ `captureSpawn` parses `result.usage` and writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
309
338
 
310
- **OBSERVABILITY LOGGING (MANDATORY):**
311
- Before spawning — run via Bash:
312
- `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
339
+ **Design Verification subagent prompt body (passed to `spawnFn`):**
313
340
 
314
341
  ```
315
342
  Task subagent (spawnType: validation, general-purpose, model: opus):
@@ -366,8 +393,6 @@ cannot be redeemed by visual polish.
366
393
  10. Report: DESIGN VERIFIED | DESIGN DEVIATIONS FOUND ({count})"
367
394
  ```
368
395
 
369
- After subagent returns — run observability Bash and append to token-log.md.
370
-
371
396
  **Artifact Gate:** Read `.gsd-t/contracts/design-contract.md` — if no `## Verification Status` section with a comparison table exists, re-spawn (1 retry).
372
397
 
373
398
  **If deviations found:** Fix them (max 2 cycles), re-verify. If persistent, log to `.gsd-t/deferred-items.md`.
@@ -386,19 +411,29 @@ Resolve the templated prompt path via Bash (same pattern as execute.md):
386
411
  ```
387
412
  RT_PROMPT="$(npm root -g 2>/dev/null)/@tekyzinc/gsd-t/templates/prompts/red-team-subagent.md"
388
413
  [ -f "$RT_PROMPT" ] || RT_PROMPT="templates/prompts/red-team-subagent.md"
389
- T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")
390
414
  ```
391
415
 
392
- Spawn Task subagent (spawnType: validation, general-purpose, model: opus) always headless, `--watch` ignored:
393
- > "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`."
416
+ **OBSERVABILITY LOGGING (MANDATORY) wrap the Red Team subagent spawn with `captureSpawn`:**
394
417
 
395
- After subagent returns — run via Bash:
396
418
  ```
397
- T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))
398
- CTX_PCT=$(node -e "try{const tb=require('./bin/token-budget.cjs'); process.stdout.write(String(tb.getSessionStatus('.').pct))}catch(_){process.stdout.write('N/A')}")
419
+ node -e "
420
+ const { captureSpawn } = require('./bin/gsd-t-token-capture.cjs');
421
+ (async () => {
422
+ await captureSpawn({
423
+ command: 'gsd-t-quick',
424
+ step: 'Red Team',
425
+ model: 'opus',
426
+ description: 'adversarial validation of quick task',
427
+ projectDir: '.',
428
+ notes: '{VERDICT} — {N} bugs found',
429
+ spawnFn: async () => { /* Task subagent (spawnType: validation, general-purpose, model: opus) — always headless, --watch ignored:
430
+ '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
+ });
432
+ })();
433
+ "
399
434
  ```
400
- Append to `.gsd-t/token-log.md`:
401
- `| {DT_START} | {DT_END} | gsd-t-quick | Red Team | opus | {DURATION}s | {VERDICT} {N} bugs found | | | {CTX_PCT} |`
435
+
436
+ `captureSpawn` parses `result.usage` and writes the row to `.gsd-t/token-log.md` under the canonical header. Tokens column renders as `in=N out=N cr=N cc=N $X.XX` or `—`, never `N/A`.
402
437
 
403
438
  **If Red Team VERDICT is FAIL:**
404
439
  1. Fix all CRITICAL and HIGH bugs (up to 2 fix cycles)
@@ -17,12 +17,26 @@ Check whether an unattended supervisor is actively running for this project:
17
17
  1. Check if `.gsd-t/.unattended/supervisor.pid` exists.
18
18
  - **Does not exist** → no supervisor running. Fall through to Step 0.1.
19
19
 
20
- 2. **File exists**: Read the PID (single integer on one line). Run:
20
+ 2. **File exists**: Run the liveness + fingerprint check via the helper:
21
21
  ```bash
22
- kill -0 <pid> 2>/dev/null && echo "alive" || echo "dead"
22
+ node -e "
23
+ const { readPidFile, verifyFingerprint } = require('./bin/supervisor-pid-fingerprint.cjs');
24
+ const entry = readPidFile(process.cwd());
25
+ if (!entry) { console.log('no_pid_file'); process.exit(0); }
26
+ try { process.kill(entry.pid, 0); } catch { console.log('dead:' + entry.pid); process.exit(0); }
27
+ const r = verifyFingerprint(entry, process.cwd());
28
+ if (r.ok === true) console.log('alive_verified:' + entry.pid);
29
+ else if (r.ok === null) console.log('alive_legacy_pid:' + entry.pid);
30
+ else console.log('alive_but_stale:' + entry.pid + ':' + r.reason);
31
+ "
23
32
  ```
24
- - **"dead"** → supervisor exited (cleanly or crashed). The PID file is stale. Log: `[resume] supervisor PID <pid> no longer alive — stale PID file, falling through to normal resume`. Fall through to Step 0.1.
25
- - **"alive"** → supervisor process is live. Proceed to step 3.
33
+
34
+ Five possible outcomes:
35
+ - `no_pid_file` → no supervisor running, fall through to Step 0.1.
36
+ - `dead:<pid>` → supervisor exited (cleanly or crashed). PID file stale. Log: `[resume] supervisor PID <pid> no longer alive — stale PID file, falling through to normal resume`. Fall through.
37
+ - `alive_verified:<pid>` → our supervisor, same project, ps confirms command line. Proceed to step 3 (AUTO-REATTACH).
38
+ - `alive_legacy_pid:<pid>` → PID file is legacy bare-integer form; we can only confirm "some process with this PID exists." Log a one-line warning: `[resume] supervisor PID <pid> file uses legacy bare-integer form — next supervisor launch will upgrade to JSON fingerprint`. Proceed to step 3 as if verified (preserves behavior for any already-running legacy supervisors).
39
+ - `alive_but_stale:<pid>:<reason>` → process alive but **not** our supervisor (different project recycled PID, or non-gsd-t process). Log: `[resume] supervisor PID <pid> no longer identifies our supervisor (reason: <reason>) — treating as stale, falling through to normal resume`. Fall through to Step 0.1.
26
40
 
27
41
  3. **Supervisor is alive**: Read `.gsd-t/.unattended/state.json`. Check `state.status`:
28
42
  - **Terminal status** (`done`, `failed`, `stopped`, `crashed`) → the supervisor has finished and is waiting for cleanup. Fall through to Step 0.1 so normal resume flow runs (it will see progress.md state and continue from where the supervisor left off).
@@ -74,6 +88,39 @@ This prevents the child side of a headless spawn from reading a partial continue
74
88
 
75
89
  ---
76
90
 
91
+ ## Step 0.3: Orchestrator Run Recovery (M40 D6)
92
+
93
+ ```bash
94
+ 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-resume --step 0 --step-label ".3: Orchestrator Run Recovery (M40 D6)" 2>/dev/null || true
95
+ ```
96
+
97
+ If an orchestrator run was interrupted (crash, SIGINT, kill, parent timeout), `.gsd-t/orchestrator/state.json` will still exist with a non-terminal `status`. Detect this and offer to resume it via the deterministic `--resume` path rather than attempting prose-driven reconciliation:
98
+
99
+ ```bash
100
+ node -e "
101
+ const fs = require('fs');
102
+ const path = require('path');
103
+ const fp = path.join('.gsd-t', 'orchestrator', 'state.json');
104
+ if (!fs.existsSync(fp)) process.exit(0);
105
+ let s; try { s = JSON.parse(fs.readFileSync(fp, 'utf8')); } catch { process.exit(0); }
106
+ const TERMINAL = new Set(['done','failed','stopped','interrupted','completed']);
107
+ if (!s || TERMINAL.has(s.status)) process.exit(0);
108
+ const running = Object.entries(s.tasks || {}).filter(([,t]) => t && t.status === 'running');
109
+ console.error('▶ Orchestrator run still in-flight (status=' + (s.status||'?') + ', ' + running.length + ' running task(s))');
110
+ console.error(' Resume via: node bin/gsd-t-orchestrator.js orchestrate --milestone ' + (s.milestone || '<id>') + ' --resume');
111
+ console.error(' This calls recoverRunState() to reconcile in-flight tasks (ok/ambiguous/failed) before continuing.');
112
+ " || true
113
+ ```
114
+
115
+ Rules:
116
+ - **State absent or terminal** → nothing to do; fall through.
117
+ - **Non-terminal** → surface the recovery hint and, at Level 3, auto-invoke the orchestrator with `--resume` when the current milestone matches `state.milestone`. Ambiguous tasks (commit but no progress entry) are flagged in the orchestrator output and require operator triage — do **not** silently claim them done.
118
+ - The recovery algorithm, archiving, and ambiguous handling are covered by unit tests in `test/m40-recovery.test.js` and implemented in `bin/gsd-t-orchestrator-recover.cjs`.
119
+
120
+ Contract: stream-json-sink v1.1.0, wave-join v1.x, completion-signal v1.x.
121
+
122
+ ---
123
+
77
124
  ## Step 0.5: Headless Read-Back Banner (MANDATORY)
78
125
 
79
126
  ```bash