@tekyzinc/gsd-t 2.74.13 → 2.76.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 (61) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +71 -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.js +709 -16
  8. package/bin/headless-auto-spawn.js +290 -0
  9. package/bin/model-selector.js +224 -0
  10. package/bin/runway-estimator.js +242 -0
  11. package/bin/token-budget.js +96 -89
  12. package/bin/token-optimizer.js +471 -0
  13. package/bin/token-telemetry.js +246 -0
  14. package/commands/gsd-t-audit.md +3 -3
  15. package/commands/gsd-t-backlog-list.md +38 -0
  16. package/commands/gsd-t-brainstorm.md +3 -3
  17. package/commands/gsd-t-complete-milestone.md +24 -0
  18. package/commands/gsd-t-debug.md +124 -7
  19. package/commands/gsd-t-discuss.md +10 -3
  20. package/commands/gsd-t-doc-ripple.md +32 -4
  21. package/commands/gsd-t-execute.md +107 -52
  22. package/commands/gsd-t-help.md +19 -0
  23. package/commands/gsd-t-integrate.md +67 -4
  24. package/commands/gsd-t-optimization-apply.md +91 -0
  25. package/commands/gsd-t-optimization-reject.md +94 -0
  26. package/commands/gsd-t-partition.md +7 -0
  27. package/commands/gsd-t-pause.md +3 -0
  28. package/commands/gsd-t-plan.md +10 -3
  29. package/commands/gsd-t-prd.md +3 -3
  30. package/commands/gsd-t-quick.md +71 -9
  31. package/commands/gsd-t-reflect.md +3 -7
  32. package/commands/gsd-t-resume.md +36 -0
  33. package/commands/gsd-t-status.md +31 -0
  34. package/commands/gsd-t-test-sync.md +7 -0
  35. package/commands/gsd-t-verify.md +12 -5
  36. package/commands/gsd-t-visualize.md +3 -7
  37. package/commands/gsd-t-wave.md +82 -18
  38. package/docs/GSD-T-README.md +52 -0
  39. package/docs/architecture.md +95 -0
  40. package/docs/infrastructure.md +117 -0
  41. package/docs/methodology.md +36 -0
  42. package/docs/prd-harness-evolution.md +51 -37
  43. package/docs/requirements.md +66 -0
  44. package/package.json +1 -1
  45. package/scripts/context-meter/count-tokens-client.js +221 -0
  46. package/scripts/context-meter/count-tokens-client.test.js +308 -0
  47. package/scripts/context-meter/test-injector.js +55 -0
  48. package/scripts/context-meter/threshold.js +88 -0
  49. package/scripts/context-meter/threshold.test.js +255 -0
  50. package/scripts/context-meter/transcript-parser.js +252 -0
  51. package/scripts/context-meter/transcript-parser.test.js +320 -0
  52. package/scripts/gsd-t-context-meter.e2e.test.js +415 -0
  53. package/scripts/gsd-t-context-meter.js +350 -0
  54. package/scripts/gsd-t-context-meter.test.js +417 -0
  55. package/scripts/gsd-t-heartbeat.js +2 -2
  56. package/scripts/gsd-t-statusline.js +23 -8
  57. package/templates/CLAUDE-global.md +5 -1
  58. package/templates/CLAUDE-project.md +26 -6
  59. package/templates/context-meter-config.json +10 -0
  60. package/templates/prompts/README.md +1 -1
  61. package/bin/task-counter.cjs +0 -161
@@ -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
 
@@ -11,6 +11,18 @@ You are resuming work after an interruption. This handles both same-session paus
11
11
  **Cross-session** (first command in a new session, no prior conversation context):
12
12
  - Run Step 1 to load full state
13
13
 
14
+ ## Step 0.5: Headless Read-Back Banner (MANDATORY)
15
+
16
+ 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:
17
+
18
+ ```bash
19
+ node bin/check-headless-sessions.js . 2>/dev/null || true
20
+ ```
21
+
22
+ 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.
23
+
24
+ Contract: `.gsd-t/contracts/headless-auto-spawn-contract.md` v1.0.0
25
+
14
26
  ## Step 1: Load Full State (cross-session only)
15
27
 
16
28
  Read in this exact order:
@@ -69,4 +81,28 @@ Otherwise, pick up from the logical next action based on current state:
69
81
  - Blocked → Explain what's needed to unblock
70
82
  - Verify failed → Show remediation tasks
71
83
 
84
+ ## Step 5: Auto-Advance Through End of Milestone (MANDATORY)
85
+
86
+ **Resume does NOT stop at the end of a wave or phase. It must chain all the way to `COMPLETED` status.**
87
+
88
+ 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:
89
+
90
+ | If resume just finished… | Auto-advance to |
91
+ |--------------------------|-----------------|
92
+ | A task (mid-wave, tasks remaining) | next task in the same wave |
93
+ | The last task of a wave (waves remaining) | next wave |
94
+ | The last task of the last wave | `/user:gsd-t-verify` (which auto-invokes `/user:gsd-t-complete-milestone` per verify Step 8) |
95
+ | `/user:gsd-t-verify` (VERIFIED or VERIFIED-WITH-WARNINGS) | `/user:gsd-t-complete-milestone` (verify already spawns this — do not re-invoke) |
96
+ | `/user:gsd-t-complete-milestone` | honor any outstanding multi-step user directive (see below) |
97
+
98
+ **Never stop at "Wave N complete" or "Task N done" and wait.** The only stopping points are:
99
+ 1. VERIFY-FAILED (report failures)
100
+ 2. Destructive action needing approval
101
+ 3. Unrecoverable error after 2 fix attempts + debug-loop exit 4
102
+ 4. `COMPLETED` status reached AND no outstanding user directive
103
+
104
+ **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.
105
+
106
+ **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.
107
+
72
108
  $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
@@ -2,6 +2,13 @@
2
2
 
3
3
  You are the lead agent coordinating verification of the completed work. Each verification dimension should be thorough and independent.
4
4
 
5
+ ## Model Assignment
6
+
7
+ Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
8
+
9
+ - **Default**: `opus` (`selectModel({phase: "verify"})`) — milestone verification is the final quality gate before completion. High stakes.
10
+ - **Escalation**: already at opus; there is no stronger tier. Verify judgments are always made at full quality.
11
+
5
12
  ## Step 1: Load State
6
13
 
7
14
  Read:
@@ -161,9 +168,9 @@ Before spawning — run via Bash:
161
168
  `T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
162
169
  Spawn a Task subagent to run the full test suite and contract audit.
163
170
  After subagent returns — run via Bash:
164
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
165
- 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):
166
- `| {DT_START} | {DT_END} | gsd-t-verify | Step 4 | haiku | {DURATION}s | test audit + contract review | {COUNTER} |`
171
+ `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")`
172
+ Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
173
+ `| {DT_START} | {DT_END} | gsd-t-verify | Step 4 | haiku | {DURATION}s | test audit + contract review | {CTX_PCT} |`
167
174
  Collect all reports, synthesize, create remediation plan.
168
175
  ```
169
176
 
@@ -367,9 +374,9 @@ Report back: one-line status summary."
367
374
  ```
368
375
 
369
376
  After subagent returns — run via Bash:
370
- `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
377
+ `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")`
371
378
  Append to `.gsd-t/token-log.md`:
372
- `| {DT_START} | {DT_END} | gsd-t-verify | Step 8 | sonnet | {DURATION}s | auto-complete-milestone | | | {COUNTER} |`
379
+ `| {DT_START} | {DT_END} | gsd-t-verify | Step 8 | sonnet | {DURATION}s | auto-complete-milestone | | | {CTX_PCT} |`
373
380
 
374
381
  3. Verify subagent result: Read `.gsd-t/progress.md` — confirm status is COMPLETED. If not, report the failure.
375
382
 
@@ -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-visualize | Step 0 | sonnet | {DURATION}s | dashboard launched | {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-visualize | Step 0 | sonnet | {DURATION}s | dashboard launched | {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,15 +2,77 @@
2
2
 
3
3
  You are the wave orchestrator. You do NOT execute phases yourself. Instead, you spawn an **independent agent for each phase**, giving each a fresh context window. This eliminates context accumulation across phases and prevents mid-wave compaction.
4
4
 
5
- ## Step 0: Reset Phase-Count Gate (MANDATORY — first thing in a fresh session)
5
+ ## Model Assignment
6
+
7
+ Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0. Each phase spawn picks its tier from `bin/model-selector.js` — the wave orchestrator itself is routine coordination work.
8
+
9
+ - **Wave orchestrator (this agent)**: `sonnet` (`selectModel({phase: "wave"})`).
10
+ - **Per-phase spawns**: each phase agent selects its own tier — `partition` → opus, `discuss` → opus, `plan` → sonnet, `execute` → sonnet (with mechanical haiku subroutines and opus Red Team), `test-sync` → sonnet, `integrate` → sonnet, `verify` → opus, `doc-ripple` → sonnet. The phase command files carry their own Model Assignment blocks.
11
+ - **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 phases under context pressure — M35 removed that behavior.
12
+
13
+ ## Per-Spawn Token Bracket (MANDATORY — wrap EVERY phase agent spawn)
14
+
15
+ Per `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0. Every phase agent spawn in the Phase Agent Spawn Pattern 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.
16
+
17
+ **Before each phase spawn — read starting context tokens:**
18
+
19
+ ```bash
20
+ 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')}")
21
+ 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')}")
22
+ ```
23
+
24
+ **After each phase spawn — record the bracket:**
25
+
26
+ ```bash
27
+ 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')}")
28
+ 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')}")
29
+ node -e "require('./bin/token-telemetry.js').recordSpawn({timestamp:new Date().toISOString(),milestone:process.env.GSD_T_MILESTONE||'',command:'gsd-t-wave',phase:'${PHASE:-}',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
30
+ ```
31
+
32
+ The bracket is additive to the existing `.gsd-t/token-log.md` OBSERVABILITY LOGGING rows. Both sinks coexist — token-log.md is human-readable with context percentage, token-metrics.jsonl is machine-readable with the full 18-field schema for `gsd-t metrics --tokens/--halts/--context-window` aggregation.
33
+
34
+ ## Step 0: Runway Check (MANDATORY — before any other work in a fresh session)
35
+
36
+ Count the wave's total task count (sum of atomic tasks across domains in the current wave). Then run via Bash:
37
+
38
+ ```bash
39
+ node -e "
40
+ const r = require('./bin/runway-estimator.js').estimateRunway({
41
+ command: 'gsd-t-wave',
42
+ domain_type: '',
43
+ remaining_tasks: {N},
44
+ projectDir: '.'
45
+ });
46
+ console.log(JSON.stringify(r, null, 2));
47
+ if (!r.can_start) {
48
+ 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)');
49
+ console.log('Auto-spawning headless to continue in a fresh context.');
50
+ const s = require('./bin/headless-auto-spawn.js').autoSpawnHeadless({
51
+ command: 'gsd-t-wave', args: [], continue_from: '.'
52
+ });
53
+ console.log('Session ID: ' + s.id);
54
+ console.log('Status: tail ' + s.logPath);
55
+ console.log('');
56
+ console.log('Your interactive session remains idle — you can use it for other work.');
57
+ console.log('You will be notified when the headless run completes.');
58
+ process.exit(0);
59
+ }
60
+ "
61
+ ```
62
+
63
+ If `can_start === false`, the headless continuation has already been spawned and the interactive session must stop here. Do NOT proceed to Step 0.1.
64
+
65
+ **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.
66
+
67
+ ## Step 0.1: Verify Context Gate Readiness (MANDATORY — first thing in a fresh session)
6
68
 
7
69
  Run via Bash:
8
70
 
9
71
  ```bash
10
- node bin/task-counter.cjs reset
72
+ node -e "const tb = require('./bin/token-budget.js'); const s = tb.getSessionStatus('.'); console.log(JSON.stringify(s));"
11
73
  ```
12
74
 
13
- This clears `.gsd-t/.task-counter` so the new wave session starts at 0. The gate logic is in the Phase Agent Spawn Pattern below — it forces a /clear-and-resume after N phase spawns to prevent the wave orchestrator from itself running out of context. Default N=5, override per-project via `.gsd-t/task-counter-config.json` (`{"limit":8}`) or env `GSD_T_TASK_LIMIT=8`.
75
+ This calls `getSessionStatus()` (v2.0.0) which reads `.gsd-t/.context-meter-state.json` produced by the Context Meter PostToolUse hook. The returned `threshold` drives the gate logic in the Phase Agent Spawn Pattern below — it enforces the three-band stop boundary (85%) so the wave orchestrator itself never runs out of context mid-wave. When the state file is absent or stale, the call falls back to a historical heuristic from `.gsd-t/token-log.md`. Band boundaries and `modelWindowSize` are configured in `.gsd-t/context-meter-config.json` and `bin/token-budget.js` (THRESHOLDS constant).
14
76
 
15
77
  ## Step 1: Load State (Lightweight)
16
78
 
@@ -96,10 +158,10 @@ If STACK_RULES is empty (no templates/stacks/ dir or no matches), skip silently.
96
158
  Run via Bash:
97
159
  `node -e "const tb = require('./bin/token-budget.js'); const s = tb.getSessionStatus('.'); process.stdout.write(s.threshold);" 2>/dev/null`
98
160
 
161
+ Three-band model per `token-budget-contract.md` v3.0.0 (never silently degrade quality):
99
162
  - `normal` or file missing → proceed normally
100
- - `downgrade` → apply model overrides from `getDegradationActions()` in the phase agent prompt
101
- - `conserve` → checkpoint progress, skip non-essential phases (test-sync if code unchanged, discuss if already done)
102
- - `stop` → checkpoint all progress and output: "Token budget exhausted — wave paused. Resume after session reset." then halt
163
+ - `warn` (≥70%) log the warning to `.gsd-t/token-log.md` and proceed at full quality; **do NOT downgrade models or skip phases** — M35 removed that behavior intentionally
164
+ - `stop` (≥85%) → checkpoint all progress and output: "Wave orchestrator context gate reached ({pct}%). Progress saved. Resume after session reset." then halt
103
165
 
104
166
  **OBSERVABILITY LOGGING (MANDATORY) — repeat for every phase spawn:**
105
167
  Before spawning — run via Bash:
@@ -126,29 +188,31 @@ Task agent (subagent_type: "general-purpose", mode: "bypassPermissions"):
126
188
  After phase agent returns — run via Bash:
127
189
  `T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
128
190
 
129
- **Wave Orchestrator Phase-Count Gate (MANDATORY) — replaces the broken context-percent check from v2.74.x:**
191
+ **Wave Orchestrator Context Gate (MANDATORY) — real-count measurement via Context Meter state file:**
130
192
 
131
193
  Run via Bash AFTER each phase agent returns:
132
194
 
133
195
  ```bash
134
- node bin/task-counter.cjs increment phase
196
+ node -e "const tb=require('./bin/token-budget.js'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s)); if(s.threshold==='stop')process.exit(10); if(s.threshold==='warn')process.exit(13);"
135
197
  ```
136
198
 
137
- Read the JSON status the command prints. If `should_stop` is `true` (or the command's exit code is `10`):
138
- 1. Save checkpoint to `.gsd-t/progress.md` — record which phases are complete, which remain.
139
- 2. Output exactly: `⏸️ Wave orchestrator phase-count gate reached ({count}/{limit} phases in this session). Progress saved. Run /clear then /user:gsd-t-wave to continue from the next phase.`
140
- 3. **STOP the wave loop.** Do NOT spawn the next phase agent. The next session resumes from saved state.
199
+ The JSON on stdout contains `{consumed, estimated_remaining, pct, threshold}` — capture `pct` as `{CTX_PCT}` for the token-log row.
200
+
201
+ Exit-code handling (three-band model per `token-budget-contract.md` v3.0.0):
202
+ - `0` (normal, <70%) proceed to the next phase at full quality.
203
+ - `13` (warn, 70–85%) → log the warning to `.gsd-t/token-log.md` and proceed to the next phase at full quality. **Never downgrade models or skip phases** — the runway estimator (m35-runway-estimator) is responsible for halting cleanly before reaching `stop`.
204
+ - `10` (stop, ≥85%) → STOP the wave loop. Save checkpoint to `.gsd-t/progress.md` — record which phases are complete, which remain. Output exactly: `⏸️ Wave orchestrator context gate reached ({pct}% of model window). Progress saved. Run /clear then /user:gsd-t-wave to continue from the next phase.` Do NOT spawn the next phase agent.
141
205
 
142
- The wave orchestrator shares the same `bin/task-counter.cjs` counter as the execute orchestrator. Each phase spawn (PARTITION, DISCUSS, PLAN, IMPACT, EXECUTE, TEST-SYNC, INTEGRATE, VERIFY+COMPLETE, DOC-RIPPLE) increments the counter by 1. With the default limit of 5, a wave will run at most 5 phase agents per session before forcing a /clear-and-resume typically two sessions per full wave. Override via `.gsd-t/task-counter-config.json` (`{"limit":8}`) or `GSD_T_TASK_LIMIT=8`.
206
+ As of v2.0.0 (M34), the wave orchestrator reads the SAME `bin/token-budget.js` real-source measurement as the execute orchestrator — both trace back to `.gsd-t/.context-meter-state.json` produced by the Context Meter PostToolUse hook. Each phase spawn (PARTITION, DISCUSS, PLAN, IMPACT, EXECUTE, TEST-SYNC, INTEGRATE, VERIFY+COMPLETE, DOC-RIPPLE) causes post-call updates to the state file, so each subsequent gate check reflects the real context consumption trajectory. When the state file is absent or stale, the call falls back to the historical heuristic.
143
207
 
144
- The previous version of this gate relied on `CLAUDE_CONTEXT_TOKENS_USED`/`_MAX` env vars which Claude Code does not export that check was inert and let the orchestrator drain context until forced compaction. The deterministic on-disk counter has the same intent (force a /clear before context runs out) but actually works.
208
+ The previous v1.x version relied on an environment-variable-based context check which Claude Code never populated; v2.74.12 stood in a proxy task counter; v2.0.0 (M34) retires both and uses the real count_tokens measurement.
145
209
 
146
- **On wave entry**, the wave orchestrator runs `node bin/task-counter.cjs reset` exactly once (see Step 0 it is the very first thing the wave does in a fresh session). The reset is the SIGNAL that this is a clean post-/clear session.
210
+ **On wave entry**, Step 0 runs `getSessionStatus()` once for a readiness confirmation. No counter reset is needed `/clear` plus the next tool call will cause the Context Meter hook to refresh the state file with the new session's starting `input_tokens`.
147
211
 
148
- 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):
149
- `| {DT_START} | {DT_END} | gsd-t-wave | {PHASE} | sonnet | {DURATION}s | phase: {PHASE} | | | {COUNTER} |`
212
+ 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):
213
+ `| {DT_START} | {DT_END} | gsd-t-wave | {PHASE} | sonnet | {DURATION}s | phase: {PHASE} | | | {CTX_PCT} |`
150
214
 
151
- Where `{COUNTER}` is the `count` field from the JSON the increment command just printed.
215
+ Where `{CTX_PCT}` is the `pct` field from the JSON the getSessionStatus command just printed.
152
216
 
153
217
  ### Phase Sequence
154
218
 
@@ -423,6 +423,58 @@ Recommended `.gsd-t/config.json`:
423
423
  }
424
424
  ```
425
425
 
426
+ ### Context Meter (M34)
427
+
428
+ The Context Meter is a PostToolUse hook that runs after every tool call, streams the current Claude Code transcript to the Anthropic `count_tokens` API, and writes the exact input-token count and threshold band to `.gsd-t/.context-meter-state.json`. The GSD-T orchestrator (`gsd-t-execute`, `gsd-t-wave`, `gsd-t-quick`, `gsd-t-integrate`, `gsd-t-debug`) reads this state file via `token-budget.getSessionStatus()` as the authoritative context-burn signal — replacing the v2.74.12 task-counter proxy.
429
+
430
+ Setup:
431
+
432
+ 1. **Export an API key** — `export ANTHROPIC_API_KEY="sk-ant-..."` (free-tier key is sufficient; `count_tokens` is inexpensive).
433
+ 2. **Install the hook** — `npx @tekyzinc/gsd-t install` (registers the PostToolUse hook globally) then `npx @tekyzinc/gsd-t init` in each project (copies the hook runtime and config template).
434
+ 3. **Verify with doctor** — `npx @tekyzinc/gsd-t doctor` hard-gates on API key presence, hook registration, script existence, config validity, and a live `count_tokens` dry-run.
435
+ 4. **Check status** — `npx @tekyzinc/gsd-t status` shows a Context line with `{pct}% of {window} tokens ({band}) — last check {time ago}`.
436
+
437
+ `.gsd-t/context-meter-config.json` controls the meter:
438
+
439
+ ```json
440
+ {
441
+ "enabled": true,
442
+ "apiKeyEnvVar": "ANTHROPIC_API_KEY",
443
+ "modelWindowSize": 200000,
444
+ "thresholdPct": 85,
445
+ "checkFrequency": 1
446
+ }
447
+ ```
448
+
449
+ Threshold bands used by the orchestrator gate (v3.0.0 three-band model as of M35 / v2.76.10):
450
+
451
+ | Band | Range | Orchestrator action |
452
+ |-----------|-------------|-----------------------------------------------------------------|
453
+ | normal | 0–69% | Proceed as normal |
454
+ | warn | 70–84% | Surface warning; runway estimator refuses if projection crosses |
455
+ | stop | ≥85% | Halt cleanly; headless auto-spawn continues in a fresh context |
456
+
457
+ **Zero silent quality degradation.** There is no `downgrade` or `conserve` band anymore. When the runway estimator (`bin/runway-estimator.js`) projects a run will cross the 85% stop threshold, the command refuses to start. Instead of printing "please `/clear` and resume," it calls `bin/headless-auto-spawn.js` which detaches a child process to continue the work. The interactive session receives a single ⛔ banner and exits cleanly; the user is never blocked.
458
+
459
+ **Per-phase model selection** — see `bin/model-selector.js` for the declarative rules table (≥13 phase mappings). Each command file carries a `## Model Assignment` block documenting which phases run on haiku / sonnet / opus. Complexity signals (`cross_module_refactor`, `security_boundary`, `data_loss_risk`, `contract_design`) escalate sonnet→opus at plan time.
460
+
461
+ **`/advisor` escalation** — mid-phase escalation channel. If `/advisor` is programmable in the runtime, subagents invoke it directly; otherwise, the convention-based fallback (`bin/advisor-integration.js`) appends a `missed_escalation` marker to `.gsd-t/token-log.md` that surfaces at `gsd-t-reflect`. See `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
462
+
463
+ **`gsd-t metrics` CLI** — `gsd-t metrics --tokens [--by model,command,phase,milestone,domain,domain_type]` aggregates `.gsd-t/token-metrics.jsonl` into a count/total/mean/median/p95 table. `gsd-t metrics --halts` breaks halts down by type (`clean`, `runway-refusal`, `headless-handoff`, `native-compact`). `gsd-t metrics --tokens --context-window` buckets spawns by `context_window_pct_before` in 10% increments. See `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0.
464
+
465
+ **Optimization apply/reject** — `/user:gsd-t-optimization-apply {ID}` promotes a pending recommendation; `/user:gsd-t-optimization-reject {ID} [--reason "text"]` dismisses it with a 5-milestone cooldown. Both are idempotent. See `commands/gsd-t-optimization-apply.md` and `commands/gsd-t-optimization-reject.md`.
466
+
467
+ **Observability logging columns** — as of M34, the `.gsd-t/token-log.md` header includes `Ctx%` (the real session-wide context percentage at the time of the subagent spawn) replacing the earlier `Tasks-Since-Reset` column. The old column was a proxy count of how many tasks had run since the last `/clear`; the new column is the actual measurement.
468
+
469
+ **Upgrading from pre-M34** — `gsd-t update-all` handles the migration automatically:
470
+ - Copies the hook script, runtime files, and config template into every registered project
471
+ - Runs a one-time task-counter retirement (`bin/task-counter.cjs` + `.task-counter*` files deleted, `.gsd-t/.task-counter-retired-v1` marker written)
472
+ - Idempotent on second run
473
+
474
+ After upgrading, you **must** set `ANTHROPIC_API_KEY` or `gsd-t doctor` will fail.
475
+
476
+ **Historical note on v2.74.12–13**: between 2026-03 and 2026-04, the orchestrator used `bin/task-counter.cjs` as a proxy — it assumed N tasks ≈ M% context used. That was itself a replacement for an earlier env-var-based check (`CLAUDE_CONTEXT_TOKENS_USED` / `CLAUDE_CONTEXT_TOKENS_MAX`) that never worked because Claude Code does not export those vars. The Context Meter (v2.75.10, M34) is the first version that measures context burn from the authoritative source: the Anthropic API itself.
477
+
426
478
  ---
427
479
 
428
480
  ## License