@tekyzinc/gsd-t 2.74.13 → 3.10.10

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 (69) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/README.md +117 -1
  3. package/bin/advisor-integration.js +93 -0
  4. package/bin/check-headless-sessions.js +140 -0
  5. package/bin/context-meter-config.cjs +101 -0
  6. package/bin/context-meter-config.test.cjs +101 -0
  7. package/bin/gsd-t-unattended-platform.js +381 -0
  8. package/bin/gsd-t-unattended-safety.js +766 -0
  9. package/bin/gsd-t-unattended.js +1259 -0
  10. package/bin/gsd-t.js +723 -19
  11. package/bin/handoff-lock.js +249 -0
  12. package/bin/headless-auto-spawn.js +328 -0
  13. package/bin/model-selector.js +224 -0
  14. package/bin/runway-estimator.js +242 -0
  15. package/bin/token-budget.js +96 -89
  16. package/bin/token-optimizer.js +471 -0
  17. package/bin/token-telemetry.js +246 -0
  18. package/commands/gsd-t-audit.md +3 -3
  19. package/commands/gsd-t-backlog-list.md +38 -0
  20. package/commands/gsd-t-brainstorm.md +3 -3
  21. package/commands/gsd-t-complete-milestone.md +24 -0
  22. package/commands/gsd-t-debug.md +124 -7
  23. package/commands/gsd-t-discuss.md +10 -3
  24. package/commands/gsd-t-doc-ripple.md +32 -4
  25. package/commands/gsd-t-execute.md +107 -52
  26. package/commands/gsd-t-help.md +22 -0
  27. package/commands/gsd-t-integrate.md +67 -4
  28. package/commands/gsd-t-optimization-apply.md +91 -0
  29. package/commands/gsd-t-optimization-reject.md +94 -0
  30. package/commands/gsd-t-partition.md +7 -0
  31. package/commands/gsd-t-pause.md +3 -0
  32. package/commands/gsd-t-plan.md +10 -3
  33. package/commands/gsd-t-prd.md +3 -3
  34. package/commands/gsd-t-quick.md +71 -9
  35. package/commands/gsd-t-reflect.md +3 -7
  36. package/commands/gsd-t-resume.md +86 -1
  37. package/commands/gsd-t-status.md +31 -0
  38. package/commands/gsd-t-test-sync.md +7 -0
  39. package/commands/gsd-t-unattended-stop.md +83 -0
  40. package/commands/gsd-t-unattended-watch.md +290 -0
  41. package/commands/gsd-t-unattended.md +414 -0
  42. package/commands/gsd-t-verify.md +12 -5
  43. package/commands/gsd-t-visualize.md +3 -7
  44. package/commands/gsd-t-wave.md +82 -18
  45. package/docs/GSD-T-README.md +69 -0
  46. package/docs/architecture.md +176 -4
  47. package/docs/infrastructure.md +221 -0
  48. package/docs/methodology.md +44 -0
  49. package/docs/prd-harness-evolution.md +51 -37
  50. package/docs/requirements.md +95 -0
  51. package/docs/unattended-windows-caveats.md +245 -0
  52. package/package.json +2 -2
  53. package/scripts/context-meter/count-tokens-client.js +221 -0
  54. package/scripts/context-meter/count-tokens-client.test.js +308 -0
  55. package/scripts/context-meter/test-injector.js +55 -0
  56. package/scripts/context-meter/threshold.js +88 -0
  57. package/scripts/context-meter/threshold.test.js +255 -0
  58. package/scripts/context-meter/transcript-parser.js +252 -0
  59. package/scripts/context-meter/transcript-parser.test.js +320 -0
  60. package/scripts/gsd-t-context-meter.e2e.test.js +415 -0
  61. package/scripts/gsd-t-context-meter.js +350 -0
  62. package/scripts/gsd-t-context-meter.test.js +417 -0
  63. package/scripts/gsd-t-heartbeat.js +2 -2
  64. package/scripts/gsd-t-statusline.js +23 -8
  65. package/templates/CLAUDE-global.md +17 -1
  66. package/templates/CLAUDE-project.md +26 -6
  67. package/templates/context-meter-config.json +10 -0
  68. package/templates/prompts/README.md +1 -1
  69. package/bin/task-counter.cjs +0 -161
@@ -47,6 +47,9 @@ Create `.gsd-t/continue-here-{timestamp}.md`:
47
47
  {any known blockers, pending decisions, or things to watch out for}
48
48
  {None if clean}
49
49
 
50
+ ## Outstanding User Directive
51
+ {Copy any multi-step chain the user gave earlier in the session that has NOT been fully executed, verbatim. Examples: "run until milestone complete, then checkin publish update all", "complete M34 and then archive + publish". Resume honors this after the resumed phase finishes. Leave as _None_ if no outstanding chain.}
52
+
50
53
  ## User Note
51
54
  {$ARGUMENTS if provided, otherwise: _No note provided._}
52
55
 
@@ -2,6 +2,13 @@
2
2
 
3
3
  You are the lead agent creating atomic execution plans for each domain. This phase is ALWAYS single-session — one agent with full context across all domains to ensure consistency.
4
4
 
5
+ ## Model Assignment
6
+
7
+ Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
8
+
9
+ - **Default**: `sonnet` (`selectModel({phase: "plan"})`) — task decomposition is structured work.
10
+ - **Escalation**: `/advisor` convention-based fallback from `bin/advisor-integration.js` when a task touches a contract boundary or requires a decision about task granularity (too coarse → brittle execution; too fine → coordination overhead). Never silently downgrade the model under context pressure — M35 removed that behavior.
11
+
5
12
  ## Step 1: Load Full Context
6
13
 
7
14
  Read ALL of these:
@@ -376,9 +383,9 @@ Report: PASS (all checks pass) or FAIL with specific gaps listed."
376
383
  Before spawning — run via Bash:
377
384
  `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
378
385
  After subagent returns — run via Bash:
379
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
380
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task | Tasks-Since-Reset |` if missing):
381
- `| {DT_START} | {DT_END} | gsd-t-plan | Step 7 | haiku | {DURATION}s | {PASS/FAIL}, iteration {N} | | | {COUNTER} |`
386
+ `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.js'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
387
+ 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):
388
+ `| {DT_START} | {DT_END} | gsd-t-plan | Step 7 | haiku | {DURATION}s | {PASS/FAIL}, iteration {N} | | | {CTX_PCT} |`
382
389
  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):
383
390
  `| {DT_START} | gsd-t-plan | Step 7 | haiku | {DURATION}s | medium | {gap description} |`
384
391
 
@@ -23,9 +23,9 @@ Read CLAUDE.md and .gsd-t/progress.md for project context, then execute gsd-t-pr
23
23
  ```
24
24
 
25
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))`
27
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Tasks-Since-Reset |` if missing):
28
- `| {DT_START} | {DT_END} | gsd-t-prd | Step 0 | sonnet | {DURATION}s | prd: {topic summary} | {COUNTER} |`
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.js'); 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} |`
29
29
 
30
30
  Relay the subagent's summary to the user. **Do not execute Steps 1–6 yourself.**
31
31
 
@@ -2,7 +2,70 @@
2
2
 
3
3
  You are executing a small, focused task that doesn't need full phase planning. This is for bug fixes, config changes, small features, and ad-hoc work.
4
4
 
5
- ## Step 0: Launch via Subagent
5
+ ## Model Assignment
6
+
7
+ Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
8
+
9
+ - **Default**: `sonnet` (`selectModel({phase: "quick"})`) — routine one-off task.
10
+ - **Mechanical subroutines** (demote to `haiku`): test runners (`selectModel({phase: "quick", task_type: "test_runner"})`).
11
+ - **Red Team (Step 5.5)**: `opus` — adversarial reasoning always runs at top tier.
12
+ - **Escalation**: `/advisor` convention-based fallback from `bin/advisor-integration.js` at declared high-stakes sub-decisions (see `.gsd-t/M35-advisor-findings.md`). Never silently downgrade the model or skip Red Team / doc-ripple under context pressure — M35 removed that behavior.
13
+
14
+ ## Per-Spawn Token Bracket (MANDATORY — wrap EVERY Task subagent spawn)
15
+
16
+ Per `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0. Every Task subagent spawn below **MUST** be wrapped in this token bracket so `.gsd-t/token-metrics.jsonl` gets one record per spawn. This is additive — the existing OBSERVABILITY LOGGING blocks in each spawn site are preserved unmodified alongside this bracket.
17
+
18
+ **Before each spawn — read starting context tokens:**
19
+
20
+ ```bash
21
+ T0_TOKENS=$(node -e "try{const s=require('fs').readFileSync('.gsd-t/.context-meter-state.json','utf8');process.stdout.write(String(JSON.parse(s).inputTokens||0))}catch(_){process.stdout.write('0')}")
22
+ T0_PCT=$(node -e "try{const tb=require('./bin/token-budget.js');process.stdout.write(String(tb.getSessionStatus('.').pct||0))}catch(_){process.stdout.write('0')}")
23
+ ```
24
+
25
+ **After each spawn — record the bracket:**
26
+
27
+ ```bash
28
+ T1_TOKENS=$(node -e "try{const s=require('fs').readFileSync('.gsd-t/.context-meter-state.json','utf8');process.stdout.write(String(JSON.parse(s).inputTokens||0))}catch(_){process.stdout.write('0')}")
29
+ T1_PCT=$(node -e "try{const tb=require('./bin/token-budget.js');process.stdout.write(String(tb.getSessionStatus('.').pct||0))}catch(_){process.stdout.write('0')}")
30
+ node -e "require('./bin/token-telemetry.js').recordSpawn({timestamp:new Date().toISOString(),milestone:process.env.GSD_T_MILESTONE||'',command:'gsd-t-quick',phase:'quick',step:'${STEP:-}',domain:'${DOMAIN:-}',domain_type:'${DOMAIN_TYPE:-}',task:'${TASK:-}',model:'${MODEL:-sonnet}',duration_s:${DURATION:-0},input_tokens_before:${T0_TOKENS},input_tokens_after:${T1_TOKENS},tokens_consumed:${T1_TOKENS}-${T0_TOKENS},context_window_pct_before:${T0_PCT},context_window_pct_after:${T1_PCT},outcome:'${OUTCOME:-success}',halt_type:${HALT_TYPE:-null},escalated_via_advisor:${ESCALATED_VIA_ADVISOR:-false}})" 2>/dev/null || true
31
+ ```
32
+
33
+ The bracket is additive to the existing `.gsd-t/token-log.md` OBSERVABILITY LOGGING rows. Both sinks coexist — token-log.md is human-readable, token-metrics.jsonl is machine-readable for `gsd-t metrics` aggregation.
34
+
35
+ ## Step 0: Runway Check (MANDATORY — before any other work in a fresh session)
36
+
37
+ Quick tasks are always single-task, so `remaining_tasks=1`. Run via Bash:
38
+
39
+ ```bash
40
+ node -e "
41
+ const r = require('./bin/runway-estimator.js').estimateRunway({
42
+ command: 'gsd-t-quick',
43
+ domain_type: '',
44
+ remaining_tasks: 1,
45
+ projectDir: '.'
46
+ });
47
+ console.log(JSON.stringify(r, null, 2));
48
+ if (!r.can_start) {
49
+ console.log('⛔ Insufficient runway — projected ' + r.projected_end_pct + '% (current ' + r.current_pct + '%, ' + r.pct_per_task + '%/task, ' + r.confidence + ' confidence, ' + r.confidence_basis + ' records)');
50
+ console.log('Auto-spawning headless to continue in a fresh context.');
51
+ const s = require('./bin/headless-auto-spawn.js').autoSpawnHeadless({
52
+ command: 'gsd-t-quick', args: [], continue_from: '.'
53
+ });
54
+ console.log('Session ID: ' + s.id);
55
+ console.log('Status: tail ' + s.logPath);
56
+ console.log('');
57
+ console.log('Your interactive session remains idle — you can use it for other work.');
58
+ console.log('You will be notified when the headless run completes.');
59
+ process.exit(0);
60
+ }
61
+ "
62
+ ```
63
+
64
+ If `can_start === false`, the headless continuation has been spawned and the interactive session must stop here. Do NOT proceed to Step 0.1.
65
+
66
+ **Contract**: `.gsd-t/contracts/runway-estimator-contract.md` v1.0.0; stop threshold (85%) mirrors `.gsd-t/contracts/token-budget-contract.md` v3.0.0.
67
+
68
+ ## Step 0.1: Launch via Subagent
6
69
 
7
70
  To give this task a fresh context window and prevent compaction during consecutive quick runs, always execute via a Task subagent.
8
71
 
@@ -17,11 +80,10 @@ Before spawning — run via Bash:
17
80
  Run via Bash:
18
81
  `node -e "const tb = require('./bin/token-budget.js'); const s = tb.getSessionStatus('.'); process.stdout.write(s.threshold);" 2>/dev/null`
19
82
 
20
- Apply the result:
83
+ Apply the result (three-band model per `token-budget-contract.md` v3.0.0 — never silently degrade quality):
21
84
  - `normal` or file missing → proceed with default model (sonnet)
22
- - `downgrade` → downgrade subagent model from sonnet to haiku for non-critical tasks; apply `getDegradationActions()` model overrides
23
- - `conserve` → run quick task inline (skip subagent spawn overhead); skip Red Team and doc-ripple
24
- - `stop` → output: "Token budget exhausted — quick task deferred. Resume after session reset." and halt
85
+ - `warn` (≥70%) log the warning to `.gsd-t/token-log.md` and proceed at full quality. **Do NOT downgrade models, skip Red Team, or skip doc-ripple** M35 removed that behavior intentionally.
86
+ - `stop` (≥85%) output: "Context gate reached ({pct}%). Quick task deferred. Resume after session reset." and halt.
25
87
 
26
88
  **Stack Rules Detection (before spawning subagent):**
27
89
 
@@ -96,8 +158,8 @@ Read CLAUDE.md and .gsd-t/progress.md for project context, then execute gsd-t-qu
96
158
 
97
159
  After subagent returns — run via Bash:
98
160
  `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
99
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Tasks-Since-Reset |` if missing):
100
- `| {DT_START} | {DT_END} | gsd-t-quick | Step 0 | sonnet | {DURATION}s | quick: {task summary} | {COUNTER} |`
161
+ Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
162
+ `| {DT_START} | {DT_END} | gsd-t-quick | Step 0 | sonnet | {DURATION}s | quick: {task summary} | {CTX_PCT} |`
101
163
 
102
164
  Relay the subagent's summary to the user. **Do not execute Steps 1–5 yourself.**
103
165
 
@@ -341,10 +403,10 @@ Spawn Task subagent (general-purpose, model: opus):
341
403
  After subagent returns — run via Bash:
342
404
  ```
343
405
  T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))
344
- COUNTER=$(node bin/task-counter.cjs status 2>/dev/null | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{process.stdout.write(String(JSON.parse(s).count||''))}catch(_){process.stdout.write('')}})")
406
+ CTX_PCT=$(node -e "try{const tb=require('./bin/token-budget.js'); process.stdout.write(String(tb.getSessionStatus('.').pct))}catch(_){process.stdout.write('N/A')}")
345
407
  ```
346
408
  Append to `.gsd-t/token-log.md`:
347
- `| {DT_START} | {DT_END} | gsd-t-quick | Red Team | opus | {DURATION}s | {VERDICT} — {N} bugs found | | | {COUNTER} |`
409
+ `| {DT_START} | {DT_END} | gsd-t-quick | Red Team | opus | {DURATION}s | {VERDICT} — {N} bugs found | | | {CTX_PCT} |`
348
410
 
349
411
  **If Red Team VERDICT is FAIL:**
350
412
  1. Fix all CRITICAL and HIGH bugs (up to 2 fix cycles)
@@ -21,14 +21,10 @@ Skip Step 0 — you are already the subagent."
21
21
  **OBSERVABILITY LOGGING — after subagent returns:**
22
22
 
23
23
  Run via Bash:
24
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
24
+ `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.js'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
25
25
 
26
- Compute tokens:
27
- - No compaction (TOK_END >= TOK_START): `TOKENS=$((TOK_END-TOK_START))`, COMPACTED=null
28
- - Compaction detected (TOK_END < TOK_START): `TOKENS=$(((TOK_MAX-TOK_START)+TOK_END))`, COMPACTED=$DT_END
29
-
30
- Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Tasks-Since-Reset |` if missing):
31
- `| {DT_START} | {DT_END} | gsd-t-reflect | Step 0 | sonnet | {DURATION}s | retrospective generated | {COUNTER} |`
26
+ Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
27
+ `| {DT_START} | {DT_END} | gsd-t-reflect | Step 0 | sonnet | {DURATION}s | retrospective generated | {CTX_PCT} |`
32
28
 
33
29
  Return the subagent's output and stop. Only skip Step 0 if you are already running as a subagent.
34
30
 
@@ -2,7 +2,34 @@
2
2
 
3
3
  You are resuming work after an interruption. This handles both same-session pauses (user pressed Esc to interject) and cross-session recovery (new Claude Code session).
4
4
 
5
- ## Step 0: Detect Resume Mode
5
+ ## Step 0: Unattended Supervisor Auto-Reattach
6
+
7
+ **This step runs FIRST, before reading any docs, contracts, or continue-here files.**
8
+
9
+ Check whether an unattended supervisor is actively running for this project:
10
+
11
+ 1. Check if `.gsd-t/.unattended/supervisor.pid` exists.
12
+ - **Does not exist** → no supervisor running. Fall through to Step 0.1.
13
+
14
+ 2. **File exists**: Read the PID (single integer on one line). Run:
15
+ ```bash
16
+ kill -0 <pid> 2>/dev/null && echo "alive" || echo "dead"
17
+ ```
18
+ - **"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.
19
+ - **"alive"** → supervisor process is live. Proceed to step 3.
20
+
21
+ 3. **Supervisor is alive**: Read `.gsd-t/.unattended/state.json`. Check `state.status`:
22
+ - **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).
23
+ - **Non-terminal status** (`initializing`, `running`, or any unrecognized value) → **AUTO-REATTACH**:
24
+ - Print the current watch status using the data in `state.json` (elapsed time, current iteration, milestone/wave/task, last worker exit code).
25
+ - Call `ScheduleWakeup(270, '/user:gsd-t-unattended-watch', reason='resumed watch')`.
26
+ - **STOP reading resume.md entirely. Do NOT proceed to Step 0.1 or any later step. Do NOT read docs, contracts, or continue-here files. Do NOT display a headless read-back banner.** The watcher will display the live status block and re-schedule itself. Return now.
27
+
28
+ Contract reference: `unattended-supervisor-contract.md` §9 (Resume Auto-Reattach Handshake)
29
+
30
+ ---
31
+
32
+ ## Step 0.1: Detect Resume Mode
6
33
 
7
34
  **Same-session** (conversation context still available — you can see prior messages about the active phase/task):
8
35
  - Skip to Step 2 — you already have the context loaded
@@ -11,6 +38,40 @@ You are resuming work after an interruption. This handles both same-session paus
11
38
  **Cross-session** (first command in a new session, no prior conversation context):
12
39
  - Run Step 1 to load full state
13
40
 
41
+ ## Step 0.2: Handoff Lock Wait (headless resume only)
42
+
43
+ Before reading any continue-here file or state file, check if a parent process wrote a handoff lock for this session:
44
+
45
+ ```bash
46
+ node -e "
47
+ const sessionId = process.env.CLAUDE_HEADLESS_SESSION_ID;
48
+ if (!sessionId) { process.exit(0); }
49
+ const hl = require('./bin/handoff-lock.js');
50
+ hl.waitForLockRelease('.', sessionId, 5000)
51
+ .then(() => process.exit(0))
52
+ .catch(e => { console.error('[resume] handoff lock wait timed out:', e.message); process.exit(0); });
53
+ "
54
+ ```
55
+
56
+ - If `CLAUDE_HEADLESS_SESSION_ID` is not set (interactive resume) → the script exits immediately; no wait needed.
57
+ - If set → wait up to **5 seconds** for the parent's handoff lock to be released before reading `.gsd-t/continue-here-*.md` or any other state file. On timeout, log and proceed anyway (parent may have crashed after spawning).
58
+
59
+ This prevents the child side of a headless runway-handoff from reading a partial continue-here file written by the parent. Contract: `headless-auto-spawn-contract.md` v1.0.0, m35-gap-fixes T2 deferred hook.
60
+
61
+ ---
62
+
63
+ ## Step 0.5: Headless Read-Back Banner (MANDATORY)
64
+
65
+ Before loading full state, surface any completed headless sessions the user hasn't seen yet. Run this once at the start of every resume invocation:
66
+
67
+ ```bash
68
+ node bin/check-headless-sessions.js . 2>/dev/null || true
69
+ ```
70
+
71
+ This prints a `## Headless runs since you left` banner listing any completed sessions with their duration, outcome, and log path, then marks them surfaced so the banner never re-appears for the same session. If no completed sessions exist, it prints nothing.
72
+
73
+ Contract: `.gsd-t/contracts/headless-auto-spawn-contract.md` v1.0.0
74
+
14
75
  ## Step 1: Load Full State (cross-session only)
15
76
 
16
77
  Read in this exact order:
@@ -69,4 +130,28 @@ Otherwise, pick up from the logical next action based on current state:
69
130
  - Blocked → Explain what's needed to unblock
70
131
  - Verify failed → Show remediation tasks
71
132
 
133
+ ## Step 5: Auto-Advance Through End of Milestone (MANDATORY)
134
+
135
+ **Resume does NOT stop at the end of a wave or phase. It must chain all the way to `COMPLETED` status.**
136
+
137
+ When the resumed work reaches a natural handoff point, do NOT print a "Next Up" hint and wait for the user. At Level 3 Full Auto, keep going. The successor mapping in CLAUDE-global.md is the contract — resume honors it exactly like any other command:
138
+
139
+ | If resume just finished… | Auto-advance to |
140
+ |--------------------------|-----------------|
141
+ | A task (mid-wave, tasks remaining) | next task in the same wave |
142
+ | The last task of a wave (waves remaining) | next wave |
143
+ | The last task of the last wave | `/user:gsd-t-verify` (which auto-invokes `/user:gsd-t-complete-milestone` per verify Step 8) |
144
+ | `/user:gsd-t-verify` (VERIFIED or VERIFIED-WITH-WARNINGS) | `/user:gsd-t-complete-milestone` (verify already spawns this — do not re-invoke) |
145
+ | `/user:gsd-t-complete-milestone` | honor any outstanding multi-step user directive (see below) |
146
+
147
+ **Never stop at "Wave N complete" or "Task N done" and wait.** The only stopping points are:
148
+ 1. VERIFY-FAILED (report failures)
149
+ 2. Destructive action needing approval
150
+ 3. Unrecoverable error after 2 fix attempts + debug-loop exit 4
151
+ 4. `COMPLETED` status reached AND no outstanding user directive
152
+
153
+ **Outstanding User Directive** (from the continue-here file): If the continue-here file contains an `## Outstanding User Request` or `## User Note` section with a multi-step chain (e.g., "run until milestone complete, then checkin publish update-all"), resume MUST continue executing that chain AFTER complete-milestone finishes. Parse the remaining steps and invoke them in order. Do not stop and ask — the directive was already given.
154
+
155
+ **Self-check before printing a "Next Up" hint**: Before emitting any `## ▶ Next Up` block, ask: "Is this a Level 3 auto-advance transition?" If yes (which it almost always is at end-of-wave or end-of-milestone under Level 3), SKIP the hint and invoke the next command directly. The hint exists for commands with no successor OR for lower autonomy levels, NOT for the resume-driven path back to COMPLETED.
156
+
72
157
  $ARGUMENTS
@@ -19,6 +19,37 @@ Wait for the subagent to complete. Relay its output to the user. **Do not read f
19
19
  **If you are the spawned subagent** (your prompt says "running gsd-t-status"):
20
20
  Continue below.
21
21
 
22
+ ## Step 0: Headless Read-Back Banner (MANDATORY)
23
+
24
+ Before reading any files, surface any completed headless sessions the user hasn't seen yet. Run this once at the start of every status invocation:
25
+
26
+ ```bash
27
+ node bin/check-headless-sessions.js . 2>/dev/null || true
28
+ ```
29
+
30
+ This prints a `## Headless runs since you left` banner listing any completed sessions with their duration, outcome, and log path, then marks them surfaced so the banner never re-appears for the same session. If no completed sessions exist, it prints nothing. The banner appears at the very top of status output — before the main status table.
31
+
32
+ Contract: `.gsd-t/contracts/headless-auto-spawn-contract.md` v1.0.0
33
+
34
+ ## Step 0.5: Optimization Backlog Pending Count (one-liner)
35
+
36
+ Immediately after the headless banner, surface the count of pending token-optimizer recommendations. Show only when `N > 0` — when `N === 0`, omit the line entirely (no noise).
37
+
38
+ ```bash
39
+ node -e "
40
+ try {
41
+ const opt = require('./bin/token-optimizer.js');
42
+ const entries = opt.parseBacklog(opt.readBacklog('.'));
43
+ const pending = entries.filter(e => e.status === 'pending').length;
44
+ if (pending > 0) {
45
+ console.log('Optimization backlog: ' + pending + ' pending recommendation(s) — /user:gsd-t-backlog-list --file optimization-backlog.md');
46
+ }
47
+ } catch (_) { /* optimizer unavailable — silent */ }
48
+ "
49
+ ```
50
+
51
+ Contract: `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0
52
+
22
53
  ## Read These Files
23
54
 
24
55
  1. `.gsd-t/progress.md`
@@ -2,6 +2,13 @@
2
2
 
3
3
  You are maintaining test coverage as code changes. Your job is to identify stale tests, coverage gaps, and dead tests, then generate tasks to address them.
4
4
 
5
+ ## Model Assignment
6
+
7
+ Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
8
+
9
+ - **Default**: `sonnet` (`selectModel({phase: "test-sync"})`) — test alignment is routine refactoring work.
10
+ - **Escalation**: `/advisor` convention-based fallback from `bin/advisor-integration.js` when a test touches a contract boundary or requires judgment about what "missing coverage" means. Never silently skip test-sync under context pressure — M35 removed that behavior.
11
+
5
12
  This command is:
6
13
  - **Auto-invoked** during execute phase (after each task) and verify phase
7
14
  - **Standalone** when user wants to audit test health
@@ -0,0 +1,83 @@
1
+ # GSD-T: Unattended Stop — Signal Supervisor to Halt
2
+
3
+ **Model**: haiku (trivial sentinel toucher — no reasoning needed)
4
+
5
+ You are signaling the unattended supervisor to halt cleanly between worker iterations by writing the stop sentinel file at `.gsd-t/.unattended/stop`. This is a fire-and-forget command: no PID kill, no wait, no confirmation prompt.
6
+
7
+ See `unattended-supervisor-contract.md` §10 (Stop Mechanism) for the full handshake.
8
+
9
+ ## Step 1: Check Supervisor State Directory Exists
10
+
11
+ Run via Bash:
12
+
13
+ ```bash
14
+ if [ ! -d ".gsd-t/.unattended" ]; then
15
+ echo "No supervisor state directory — nothing to stop."
16
+ exit 0
17
+ fi
18
+ ```
19
+
20
+ If the directory does not exist, exit 0 (not an error — there is simply nothing to signal).
21
+
22
+ ## Step 2: Check Supervisor PID File Exists
23
+
24
+ Run via Bash:
25
+
26
+ ```bash
27
+ if [ ! -f ".gsd-t/.unattended/supervisor.pid" ]; then
28
+ echo "No supervisor running in this project (no PID file at .gsd-t/.unattended/supervisor.pid)."
29
+ exit 0
30
+ fi
31
+ ```
32
+
33
+ If the PID file is missing, the supervisor has already finalized cleanly. Exit 0 without writing the sentinel.
34
+
35
+ ## Step 3: Read Current Session Snapshot
36
+
37
+ Run via Bash to grab the session ID and current iteration from `state.json` (best-effort — tolerate missing or partial state):
38
+
39
+ ```bash
40
+ node -e "
41
+ try {
42
+ const s = JSON.parse(require('fs').readFileSync('.gsd-t/.unattended/state.json', 'utf8'));
43
+ console.log('SESSION=' + (s.sessionId || 'unknown'));
44
+ console.log('ITER=' + (s.iter ?? 'unknown'));
45
+ console.log('STATUS=' + (s.status || 'unknown'));
46
+ } catch (e) {
47
+ console.log('SESSION=unknown');
48
+ console.log('ITER=unknown');
49
+ console.log('STATUS=unknown');
50
+ }
51
+ "
52
+ ```
53
+
54
+ ## Step 4: Write the Stop Sentinel
55
+
56
+ Write `.gsd-t/.unattended/stop` containing the current ISO timestamp as the body (for diagnostics — the supervisor only checks for the file's existence, not its contents):
57
+
58
+ ```bash
59
+ node -e "require('fs').writeFileSync('.gsd-t/.unattended/stop', new Date().toISOString())"
60
+ ```
61
+
62
+ This is race-free, terminal-close-safe, and language-agnostic (per contract §10).
63
+
64
+ ## Step 5: Print Confirmation
65
+
66
+ Output the confirmation block:
67
+
68
+ ```
69
+ 🛑 Stop sentinel written. Supervisor will halt between next worker iterations (within ~5 minutes). State file will finalize with status=stopped.
70
+
71
+ Session: {SESSION from Step 3}
72
+ Iter: {ITER from Step 3}
73
+ Status: {STATUS from Step 3}
74
+
75
+ The current worker will run to completion (up to ~1h). Stop is honored at the next pre-worker checkpoint.
76
+ No kill signal is sent — this is a clean cooperative halt.
77
+ ```
78
+
79
+ ## Step 6: Return Immediately
80
+
81
+ Do NOT wait for the supervisor to acknowledge. Do NOT poll state.json. Do NOT call ScheduleWakeup. The supervisor will finalize state.json with `status=stopped` on its next iteration check — that's the watch loop's job to observe, not this command's.
82
+
83
+ $ARGUMENTS