@tekyzinc/gsd-t 3.29.10 → 4.0.12

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 (112) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/bin/gsd-t-parallel.cjs +64 -13
  3. package/bin/gsd-t-test-data-adapters/file-json-array.cjs +27 -3
  4. package/bin/gsd-t-test-data-adapters/localstorage-key-prefix.cjs +6 -1
  5. package/bin/gsd-t-test-data-adapters/sqlite-table-where.cjs +16 -1
  6. package/bin/gsd-t-test-data-ledger.cjs +1 -0
  7. package/bin/gsd-t.js +48 -376
  8. package/bin/journey-coverage.cjs +6 -3
  9. package/bin/parallel-cli.cjs +13 -1
  10. package/commands/gsd-t-debug.md +47 -533
  11. package/commands/gsd-t-design-decompose.md +24 -497
  12. package/commands/gsd-t-doc-ripple.md +23 -139
  13. package/commands/gsd-t-execute.md +41 -958
  14. package/commands/gsd-t-help.md +0 -2
  15. package/commands/gsd-t-impact.md +26 -295
  16. package/commands/gsd-t-integrate.md +44 -369
  17. package/commands/gsd-t-milestone.md +25 -124
  18. package/commands/gsd-t-partition.md +28 -539
  19. package/commands/gsd-t-plan.md +26 -472
  20. package/commands/gsd-t-prd.md +25 -311
  21. package/commands/gsd-t-quick.md +1 -1
  22. package/commands/gsd-t-resume.md +0 -33
  23. package/commands/gsd-t-verify.md +52 -569
  24. package/commands/gsd-t-wave.md +41 -430
  25. package/package.json +1 -1
  26. package/scripts/gsd-t-calibration-hook.js +3 -1
  27. package/scripts/hooks/pre-commit-journey-coverage +0 -2
  28. package/scripts/hooks/pre-commit-playwright-gate +0 -2
  29. package/templates/CLAUDE-global.md +43 -173
  30. package/templates/CLAUDE-project.md +118 -104
  31. package/templates/prompts/design-verify-subagent.md +3 -0
  32. package/templates/prompts/qa-subagent.md +3 -0
  33. package/templates/prompts/red-team-subagent.md +5 -2
  34. package/templates/workflows/_lib.js +176 -0
  35. package/templates/workflows/gsd-t-debug.workflow.js +86 -0
  36. package/templates/workflows/gsd-t-execute.workflow.js +206 -0
  37. package/templates/workflows/gsd-t-integrate.workflow.js +71 -0
  38. package/templates/workflows/gsd-t-phase.workflow.js +94 -0
  39. package/templates/workflows/gsd-t-quick.workflow.js +72 -0
  40. package/templates/workflows/gsd-t-verify.workflow.js +348 -0
  41. package/templates/workflows/gsd-t-wave.workflow.js +43 -0
  42. package/bin/check-headless-sessions.js +0 -140
  43. package/bin/context-budget-audit.cjs +0 -447
  44. package/bin/context-meter-config.cjs +0 -101
  45. package/bin/context-meter-config.test.cjs +0 -101
  46. package/bin/event-stream.cjs +0 -205
  47. package/bin/gsd-t-benchmark-orchestrator.js +0 -437
  48. package/bin/gsd-t-capture-lint.cjs +0 -440
  49. package/bin/gsd-t-economics.cjs +0 -315
  50. package/bin/gsd-t-in-session-usage.cjs +0 -213
  51. package/bin/gsd-t-orchestrator-config.cjs +0 -161
  52. package/bin/gsd-t-orchestrator-queue.cjs +0 -180
  53. package/bin/gsd-t-orchestrator-recover.cjs +0 -231
  54. package/bin/gsd-t-orchestrator-worker.cjs +0 -219
  55. package/bin/gsd-t-orchestrator.js +0 -535
  56. package/bin/gsd-t-parallel-probe.cjs +0 -132
  57. package/bin/gsd-t-ratelimit-probe-worker.cjs +0 -237
  58. package/bin/gsd-t-ratelimit-probe.cjs +0 -648
  59. package/bin/gsd-t-report-tokens.cjs +0 -549
  60. package/bin/gsd-t-stream-feed-client.cjs +0 -151
  61. package/bin/gsd-t-token-backfill.cjs +0 -366
  62. package/bin/gsd-t-token-capture.cjs +0 -321
  63. package/bin/gsd-t-token-dashboard.cjs +0 -353
  64. package/bin/gsd-t-token-regenerate-log.cjs +0 -129
  65. package/bin/gsd-t-tool-attribution.cjs +0 -377
  66. package/bin/gsd-t-tool-cost.cjs +0 -195
  67. package/bin/gsd-t-transcript-tee.cjs +0 -246
  68. package/bin/gsd-t-unattended-heartbeat.cjs +0 -188
  69. package/bin/gsd-t-unattended-platform.cjs +0 -551
  70. package/bin/gsd-t-unattended-platform.js +0 -381
  71. package/bin/gsd-t-unattended-safety.cjs +0 -773
  72. package/bin/gsd-t-unattended-safety.js +0 -788
  73. package/bin/gsd-t-unattended.cjs +0 -2109
  74. package/bin/gsd-t-unattended.js +0 -1367
  75. package/bin/gsd-t-worker-dispatch.cjs +0 -211
  76. package/bin/handoff-lock.cjs +0 -249
  77. package/bin/handoff-lock.js +0 -249
  78. package/bin/headless-auto-spawn.cjs +0 -711
  79. package/bin/headless-auto-spawn.js +0 -373
  80. package/bin/headless-exit-codes.cjs +0 -67
  81. package/bin/live-activity-report.cjs +0 -615
  82. package/bin/log-tail.cjs +0 -81
  83. package/bin/m44-proof-measure.cjs +0 -285
  84. package/bin/m46-iter-proof.cjs +0 -149
  85. package/bin/m46-worker-proof.cjs +0 -201
  86. package/bin/m55-substrate-proof.cjs +0 -134
  87. package/bin/metrics-rollup.js +0 -200
  88. package/bin/model-windows.cjs +0 -99
  89. package/bin/model-windows.test.cjs +0 -75
  90. package/bin/parallelism-report.cjs +0 -535
  91. package/bin/runway-estimator.cjs +0 -242
  92. package/bin/spawn-plan-derive.cjs +0 -163
  93. package/bin/spawn-plan-status-updater.cjs +0 -292
  94. package/bin/spawn-plan-writer.cjs +0 -204
  95. package/bin/supervisor-pid-fingerprint.cjs +0 -126
  96. package/bin/token-budget.cjs +0 -265
  97. package/bin/unattended-watch-format.cjs +0 -178
  98. package/bin/watch-progress.js +0 -155
  99. package/commands/gsd-t-unattended-stop.md +0 -85
  100. package/commands/gsd-t-unattended-watch.md +0 -465
  101. package/commands/gsd-t-unattended.md +0 -476
  102. package/commands/gsd-t-visualize.md +0 -116
  103. package/scripts/gsd-t-context-meter.e2e.test.js +0 -364
  104. package/scripts/gsd-t-context-meter.js +0 -341
  105. package/scripts/gsd-t-context-meter.test.js +0 -471
  106. package/scripts/gsd-t-dashboard-server.js +0 -1203
  107. package/scripts/gsd-t-post-commit-spawn-plan.sh +0 -86
  108. package/scripts/gsd-t-transcript.html +0 -1821
  109. package/scripts/hooks/gsd-t-conversation-capture.js +0 -439
  110. package/scripts/hooks/gsd-t-in-session-usage-hook.js +0 -84
  111. package/scripts/spawn-plan-fmt-tokens.cjs +0 -80
  112. package/templates/hooks/post-commit-spawn-plan.sh +0 -85
package/CHANGELOG.md CHANGED
@@ -2,6 +2,182 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [4.0.12] - 2026-05-29
6
+
7
+ ### Removed — M61-carryover test cleanup (green the suite)
8
+
9
+ The SC7 cockpit walkthrough surfaced ~23 unit + ~19 E2E pre-existing failures, all tests asserting conventions or files that M61 intentionally retired (command→Workflow conversion removed the marker/wire-in blocks; D4 retired the viewer/dashboard). Delete-with-subject cleanup — no behavior change.
10
+
11
+ - Removed wire-in/marker tests: `m56-d3-wire-in`, `m56-d4-wire-in`, `m55-d5-wire-in-{execute,verify}`, `m56-d5-stream-json-gap-closures` (the last required D3-deleted `gsd-t-capture-lint.cjs`).
12
+ - Removed 8 viewer/transcript unit tests + 3 journey-coverage staging tests coupled to the deleted viewer HTML.
13
+ - Removed orphaned E2E specs: all 6 `e2e/viewer/*`, 13 viewer-dependent `e2e/journeys/*`, `main-session-stream`, all 4 `e2e/live-journeys/*`. Kept the 3 `verify-gate-blocks-*` journeys (verify-gate is KEEP).
14
+ - Deleted `scripts/gsd-t-transcript.html` (96KB retired D4 viewer); pruned `.gsd-t/journey-manifest.json` 19→3 specs; generalized `bin/journey-coverage.cjs` `VIEWER_FILE_PATTERNS` to `scripts/*.html`; cleaned 2 pre-commit hooks.
15
+ - `test/stack-rules.test.js`: dropped per-command-file Detection-block assertions (kept engine + QA-protocol checks). `test/filesystem.test.js`: command counts 55→51 / 49→45 (D2 retired 4 commands).
16
+
17
+ Suite now 1267 pass / 1 known flake (`verifyPlaywrightHealth` — passes 20/0 isolated; suite-contention subprocess timeout) / 3 sqlite-skip. E2E 3 pass. journey-coverage clean. bin/ unchanged at 20,271 LOC.
18
+
19
+ ## [4.0.11] - 2026-05-29 (M65 Orchestration-Shell Retirement — patch)
20
+
21
+ Completes the M61 D6 deferral: deletes the M40/M44 orchestration shell that the native Workflow scripts replaced. Scope was corrected from the raw brief after a live reference scan proved `parallel-cli*` and `gsd-t-parallel.cjs` are KEEP-list substrate (verify-gate Track-2 + the `_lib` file-disjointness prover), not retireable shell — they were retained.
22
+
23
+ ### Removed (bin/, −1,780 LOC: 22,051 → 20,271)
24
+
25
+ | File(s) | Native replacement |
26
+ |---------|--------------------|
27
+ | `bin/gsd-t-orchestrator.js` + `-worker.cjs` + `-queue.cjs` + `-config.cjs` | `templates/workflows/gsd-t-execute.workflow.js` |
28
+ | `bin/spawn-plan-{writer,status-updater,derive}.cjs` + `scripts/spawn-plan-fmt-tokens.cjs` | Native `/workflows` progress + Agent View |
29
+ | `bin/headless-exit-codes.cjs` | `mapHeadlessExitCode` inlined into `bin/gsd-t.js` (5-code contract + M45 boundary-anchored regexes verbatim) |
30
+ | `scripts/gsd-t-post-commit-spawn-plan.sh` + `templates/hooks/post-commit-spawn-plan.sh` | — (spawn-plan panel retired with the M61-D4 viewer) |
31
+
32
+ ### Removed CLI subcommands
33
+ - `gsd-t orchestrate` — superseded by `gsd-t-execute.workflow.js`.
34
+
35
+ ### Removed tests (delete-with-subject)
36
+ - `test/m40-orchestrator-{config,queue,worker}.test.js`, `test/m44-d8-{spawn-plan-writer,spawn-plan-status-updater,post-commit-hook}.test.js` (each tested only a co-deleted module).
37
+
38
+ ### Changed
39
+ - `bin/gsd-t-parallel.cjs` — inlined `computeInSessionHeadroom`/`computeUnattendedGate`/`DEFAULT_SUMMARY_SIZE_PCT` (wave-join-contract §Mode-Aware Gating Math, constants 85/60/4) off the deleted orchestrator-config; refreshed stale header.
40
+ - `bin/gsd-t.js` — purged 10 stale `PROJECT_BIN_TOOLS` entries pointing at M61-deleted files (would have broken `update-all`).
41
+ - `commands/gsd-t-help.md` — removed spawn-plan/parallelism panel bullets (referenced deleted hook + retired dashboard).
42
+ - `commands/gsd-t-resume.md` — removed dead Step 0.3 "Orchestrator Run Recovery" section.
43
+
44
+ ### Deferred (NOT in M65)
45
+ - `bin/orchestrator.js` + `bin/design-orchestrator.js` — the design-build pipeline orchestrator; `gsd-t design-build` is documented but has no live dispatch case (unwired). Wire-back-or-retire is a separate decision.
46
+
47
+ ### Verification
48
+ - Red Team (opus): GRUDGING PASS — 0 CRITICAL/HIGH, both inlines byte-faithful (25-case adversarial corpus → 100% parity vs parent sources).
49
+ - QA (sonnet): PASS — zero M65-caused failures; −66 test-count drop fully accounted by the 6 deleted files.
50
+ - `/code-review ultra`: skipped (pure deletion + verbatim inlines, covered by RT+QA).
51
+ - `gsd-t doctor` clean; `gsd-t build-coverage` PASS; `gsd-t parallel --dry-run` exit 0 (KEEP-canary).
52
+ - Verdict **VERIFIED-WITH-WARNINGS**: the verify-gate/ci-parity reds are 100% inherited M61 D1–D8 carryover (23 broken unit tests + ~18 orphaned viewer E2E specs importing the M61-D4-deleted `gsd-t-dashboard-server.js`), proven against parent commit `5a5c6c0^` (1427 pass / 22 fail). M65 introduced zero regressions. Carryover flagged for a dedicated M61-cleanup milestone.
53
+
54
+ ## [4.0.10] - 2026-05-29 (M61 Platform Reconciliation — major)
55
+
56
+ ### BREAKING CHANGES
57
+
58
+ GSD-T v4.0.10 retires ~18,000 LOC of orchestration infrastructure built across M34–M55 to compensate for limitations Claude Code has since absorbed natively (1M context window, native background Workflows with `parallel()`/`pipeline()`/`budget`/schema-validation, `/usage`, `/context`, `/workflows`, comprehensive hooks, `/code-review ultra`).
59
+
60
+ The v3.x source is preserved on the `v3.x-legacy` git branch as a safety net. `npm install @tekyzinc/gsd-t@3.x` continues to work.
61
+
62
+ #### Removed CLI subcommands
63
+
64
+ | Subcommand | Replacement |
65
+ |------------|-------------|
66
+ | `gsd-t unattended` (+ `-watch`, `-stop`) | Native background Workflows + `/loop` skill |
67
+ | `gsd-t backfill-tokens` | None — historical analysis was never load-bearing |
68
+ | `gsd-t capture-lint` | None — the OBSERVABILITY block convention itself is retired |
69
+ | `gsd-t tool-cost` | OpenTelemetry exports (Enterprise) or `/usage` aggregate |
70
+ | `gsd-t report tokens` | `/usage` |
71
+ | `gsd-t stream-feed` | `/workflows` + Agent View |
72
+ | `gsd-t benchmark-orchestrator` | None — operator-run benchmark driver |
73
+
74
+ #### Removed slash commands
75
+
76
+ | Command | Replacement |
77
+ |---------|-------------|
78
+ | `/gsd-t-unattended`, `/gsd-t-unattended-watch`, `/gsd-t-unattended-stop` | Native background Workflows |
79
+ | `/gsd-t-visualize` | `/workflows` |
80
+
81
+ #### Removed CLAUDE.md rules
82
+
83
+ | Rule (global + project) | Replacement |
84
+ |------------------------|-------------|
85
+ | **Observability Logging (MANDATORY)** | Workflow `budget` global + native `/usage` |
86
+ | **Token Capture Rule (MANDATORY)** | Same |
87
+ | **In-Session Conversation Capture (M45 D2)** | Native session transcript + `/workflows` view |
88
+ | **Always-Headless Spawn (M43 D4) — Channel Separation** | Native Workflows are inherently background |
89
+ | **Context Meter (M34/M38)** | Native `/context` + Workflow `budget.remaining()` |
90
+ | **Mandatory Preflight Before Spawn (M55)** | REWRITTEN as Preflight Gate — invoked inside Workflow scripts via `_lib.runPreflight()` |
91
+ | **Brief-First Worker Rule (M55)** | REWRITTEN — invoked inside Workflow `agent()` calls; per-domain briefs generated inside `parallel()` map |
92
+ | **Two-Track Verify-Gate (M55)** | REWRITTEN as a stage inside `gsd-t-verify.workflow.js`, now followed by M57 CI-parity + M58 test-data purge + orthogonal validation triad |
93
+
94
+ #### Removed contracts
95
+
96
+ `headless-contract.md`, `headless-default-contract.md`, `context-meter-contract.md`, `dashboard-server-contract.md`, `conversation-capture-contract.md`, `live-activity-contract.md`, `parallelism-report-contract.md`, `compaction-events-contract.md`, `event-schema-contract.md`, `economics-estimator-contract.md`, `metrics-schema-contract.md`.
97
+
98
+ #### Added contracts
99
+
100
+ - **`orthogonal-validation-contract.md` v1.0.0 STABLE** — locks `/code-review ultra` + Red Team + QA as orthogonal objective functions. No collapse, no substitution, no transitive trust. `skipUltra=true` is INELIGIBLE for `VERIFIED`.
101
+
102
+ #### Added files
103
+
104
+ - **`templates/workflows/_lib.js`** — shared Workflow helpers (`runPreflight`, `generateBrief`, `proveFileDisjointness`, `runVerifyGate`, `loadProtocol`, `readDomainTasks`, `readScope`). Prefers project-local `bin/<tool>.cjs` with PATH fallback.
105
+ - **`templates/workflows/gsd-t-execute.workflow.js`** — canonical execute phase as native Workflow.
106
+ - **`templates/workflows/gsd-t-verify.workflow.js`** — verify phase with M57 + M58 gates + orthogonal triad.
107
+ - **`templates/workflows/gsd-t-wave.workflow.js`** — composes execute + verify.
108
+ - **`templates/workflows/gsd-t-integrate.workflow.js`**, **`-debug`**, **`-quick`**, **`-phase`** (generic upper-stage runner).
109
+
110
+ #### Reframed validation protocols
111
+
112
+ `templates/prompts/{qa,red-team,design-verify}-subagent.md` methodology bodies unchanged. Only the invocation-context preamble updated: when invoked as a Workflow `agent()` stage, final emission is a StructuredOutput JSON envelope matching the schema; when invoked as a Task subagent (legacy path), final emission is the markdown report. Same methodology; different envelope.
113
+
114
+ Red Team verdict string canonicalized: `GRUDGING PASS` → `GRUDGING-PASS` across schema enum, protocol body, global rule, and 3 command files.
115
+
116
+ #### Command file conversions
117
+
118
+ All 12 GSD-T command files converted from prose-orchestrator scaffolding (~6,000 lines total) to thin Workflow invokers (~700 lines total):
119
+ - `execute` (984 → 67), `verify` (595 → 78), `wave` (454 → 65), `integrate` (394 → 69), `debug` (558 → 72), `quick` (legacy preserved → minimal), `partition` (560 → 49), `plan` (491 → 45), `impact` (314 → 45), `milestone` (143 → 44), `prd` (330 → 44), `design-decompose` (517 → 44), `doc-ripple` (156 → 40).
120
+
121
+ Each command file now describes WHAT (its phase's purpose) and invokes its corresponding Workflow script with explicit `args` shape.
122
+
123
+ #### Migration guide
124
+
125
+ | If you were using… | …now use this |
126
+ |--------------------|---------------|
127
+ | `gsd-t-unattended` for cross-session orchestration | Native background Workflows + `/loop` for recurring tasks |
128
+ | `gsd-t backfill-tokens` for historical cost analysis | OpenTelemetry exports (Enterprise) |
129
+ | `captureSpawn`/`recordSpawnRow` wrappers in your own scripts | Workflow `budget.spent()` / `/usage` |
130
+ | `gsd-t stream-feed` watching dashboard | `/workflows` + Agent View |
131
+ | Custom orchestrator code on top of `gsd-t-orchestrator.js` | Write a Workflow script in `templates/workflows/` style |
132
+ | Editing `commands/gsd-t-*.md` to add steps | Edit the corresponding `templates/workflows/*.workflow.js` |
133
+
134
+ If you cannot migrate immediately, pin `"@tekyzinc/gsd-t": "3.x"` in package.json. v3.x is preserved on the `v3.x-legacy` git branch.
135
+
136
+ ### Verification
137
+
138
+ - Baseline locked at v3.29.11: bin/ = 37,785 LOC / 109 files.
139
+ - Post-M61: bin/ = 19,855 LOC / 78 files. Reduction: -17,930 LOC (47% of bin/ retired; 70% of way to SC1 target ≤12,000).
140
+ - Full unit suite: 41 failures remain post-Wave-3. 100% are command-file format tests (M56-D3 markers, Stack Rules, preflight wire-in blocks, OBSERVABILITY LOGGING tests, `shim_one_liner_*`) for the legacy command-file shape the Workflow conversions explicitly replace, + command-count tests for retired subcommands. Zero new behavior regressions.
141
+ - 4.8 audit (fresh-context Opus 4.8 review Workflow) returned `agree-with-edits` on all 8 artifact groups: core architecture sound, no revert needed.
142
+ - Retire→native map archived under `.gsd-t/milestones/m61-platform-reconciliation-2026-05-29/retire-to-native-map.md`.
143
+
144
+ ### Deferred to follow-up milestones
145
+
146
+ - **M62 (post-M61): Cross-project propagation** — run `gsd-t version-update-all` to propagate v4.0.10 to all registered projects (rewrite their CLAUDE.md + retire docs; cleanup `~/.claude/settings.json` hooks for retired infrastructure).
147
+ - **SC7 cockpit walkthrough** — scripted desktop-only walkthrough of a small post-M61 backlog item (zero terminal keystrokes). User-driven.
148
+ - **D6 port-then-delete completion** — `bin/gsd-t-orchestrator.js`, `gsd-t-orchestrator-{worker,queue,config}.cjs`, `gsd-t-parallel.cjs`, `parallel-cli.cjs`, `spawn-plan-writer.cjs` are stubbed to load cleanly post-D2/D4 but await final deletion after a real M58 reproduction via the Workflow scripts validates the migration. Expected ~6,000 LOC additional reduction.
149
+ - **Deeper SC7 walkthrough on a UI-heavy milestone** — broader test of desktop's browser-tooling advantage.
150
+
151
+ ## [3.29.11] - 2026-05-29 09:57 PDT
152
+
153
+ ### Fixed — CRITICAL test-data adapter data-destruction bug (M60)
154
+
155
+ Found by a native-Workflow Red Team bake-off (Opus 4.8, perspective-diverse
156
+ adversarial review) while evaluating GSD-T against native Claude Code 4.8
157
+ capability. M58's own in-session Red Team had passed this as "6/6 defended"
158
+ — the claim was wrong.
159
+
160
+ - **Bug**: `bin/gsd-t-test-data-adapters/file-json-array.cjs` and
161
+ `localstorage-key-prefix.cjs` guarded with
162
+ `typeof taggedPrefix === 'string' && taggedPrefix.length > 0 && !id.startsWith(...)`.
163
+ An empty/undefined `taggedPrefix` short-circuits the whole condition, so
164
+ **no guard runs** — `gsd-t test-data --purge` would delete untagged
165
+ production records and report `errors:0` (gate GREEN). No adapter enforced
166
+ `projectDir` containment on the `store` path, making it a write-anywhere
167
+ delete primitive. Reproduced live before fixing.
168
+ - **Fix** (additive refusal only — removes capability, never adds destructive
169
+ behavior): both adapters now hard-refuse empty/undefined `taggedPrefix`
170
+ (matching the already-correct `sqlite-table-where` adapter); `file-json-array`
171
+ and `sqlite-table-where` enforce the containment predicate
172
+ `resolved.startsWith(root + sep) && resolved !== root` when `projectDir` is
173
+ supplied; `purgeRunInserts` threads `projectDir` into every adapter call.
174
+ - **Tests**: new `test/m60-redteam-regressions.test.js` (10 tests, one per
175
+ finding + happy-path + back-compat). M58 suite 44/44 unchanged.
176
+ - **Contract**: `test-data-tagging-contract.md` → v1.1.0 STABLE (empty-prefix
177
+ refusal + path containment now normative).
178
+ - Backward-compatible: the happy path (non-empty prefix, in-project path, or
179
+ no `projectDir`) is unchanged.
180
+
5
181
  ## [3.29.10] - 2026-05-27 10:09 PDT
6
182
 
7
183
  ### Changed — Timestamp precision in progress.md (forward-only)
@@ -10,14 +10,15 @@
10
10
  * - D1 task graph (bin/gsd-t-task-graph.cjs)
11
11
  * - D4 depgraph validation (bin/gsd-t-depgraph-validate.cjs)
12
12
  * - D5 file-disjointness (bin/gsd-t-file-disjointness.cjs)
13
- * - D6 economics estimator (bin/gsd-t-economics.cjs)
14
- * - token-budget (bin/token-budget.cjs) — in-session ctxPct
15
- * - mode-aware gating math (bin/gsd-t-orchestrator-config.cjs)
13
+ * - mode-aware gating math (inlined below — formerly bin/gsd-t-orchestrator-config.cjs)
16
14
  *
17
- * Does NOT replace `bin/gsd-t-orchestrator.js`. `runParallel` prepares the
18
- * validated ready-task set and plan; the existing orchestrator machinery
19
- * owns the actual worker spawn. In T2 this module emits the plan;
20
- * the downstream orchestrator consumes it.
15
+ * M61/M65 note: the economics estimator (gsd-t-economics.cjs), token-budget,
16
+ * and the M40 orchestrator (bin/gsd-t-orchestrator.js) were retired the
17
+ * orchestration core moved to native Workflow scripts (templates/workflows/).
18
+ * This module survives as the file-disjointness/ready-task planner consumed by
19
+ * `_lib.proveFileDisjointness()`; its mode-aware gating helpers, which used to
20
+ * live in gsd-t-orchestrator-config.cjs, are inlined below (M65) so this file
21
+ * no longer depends on the retired orchestrator config.
21
22
  *
22
23
  * Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0 (§Mode-Aware Gating Math).
23
24
  *
@@ -35,11 +36,61 @@ const path = require("node:path");
35
36
  const { buildTaskGraph, getReadyTasks } = require(path.join(__dirname, "gsd-t-task-graph.cjs"));
36
37
  const { validateDepGraph } = require(path.join(__dirname, "gsd-t-depgraph-validate.cjs"));
37
38
  const { proveDisjointness } = require(path.join(__dirname, "gsd-t-file-disjointness.cjs"));
38
- const { estimateTaskFootprint } = require(path.join(__dirname, "gsd-t-economics.cjs"));
39
- const {
40
- computeInSessionHeadroom,
41
- computeUnattendedGate,
42
- } = require(path.join(__dirname, "gsd-t-orchestrator-config.cjs"));
39
+ // M61 D3: gsd-t-economics retired. estimateTaskFootprint produced a per-task
40
+ // token+cost estimate the planner could consult for in-session-headroom
41
+ // math. Native budget primitives (Workflow `budget` + /usage) replace it.
42
+ // Stub to a zero-footprint estimate so the planner proceeds with default
43
+ // assumptions instead of crashing.
44
+ const estimateTaskFootprint = () => ({
45
+ inputTokens: 0, outputTokens: 0, costUSD: 0, source: "m61-stub",
46
+ });
47
+
48
+ // ─── Mode-aware gating math (inlined from gsd-t-orchestrator-config.cjs, M65) ──
49
+ // Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0 §Mode-Aware Gating Math.
50
+ const IN_SESSION_CW_CEILING_PCT = 85;
51
+ const UNATTENDED_PER_WORKER_CW_PCT = 60;
52
+ const DEFAULT_SUMMARY_SIZE_PCT = 4;
53
+
54
+ /**
55
+ * [in-session] headroom gate. Returns `{ok, reducedCount}`.
56
+ * ok=true iff `ctxPct + workerCount * summarySize ≤ IN_SESSION_CW_CEILING_PCT`.
57
+ * Otherwise reduces N repeatedly; final floor is N=1. NEVER refuses.
58
+ */
59
+ function computeInSessionHeadroom(opts) {
60
+ const o = opts || {};
61
+ const ctxPct = Number.isFinite(o.ctxPct) ? o.ctxPct : 0;
62
+ const requested = Number.isFinite(o.workerCount) ? Math.max(0, Math.floor(o.workerCount)) : 0;
63
+ const summarySize = Number.isFinite(o.summarySize) ? o.summarySize : DEFAULT_SUMMARY_SIZE_PCT;
64
+ const ceiling = IN_SESSION_CW_CEILING_PCT;
65
+
66
+ if (ctxPct + requested * summarySize <= ceiling) {
67
+ return { ok: true, reducedCount: requested };
68
+ }
69
+ let n = requested - 1;
70
+ while (n > 1) {
71
+ if (ctxPct + n * summarySize <= ceiling) {
72
+ return { ok: true, reducedCount: n };
73
+ }
74
+ n -= 1;
75
+ }
76
+ return { ok: true, reducedCount: 1 };
77
+ }
78
+
79
+ /**
80
+ * [unattended] per-worker CW gate. Returns `{ok, split}`.
81
+ * ok=true, split=false if `estimatedCwPct ≤ threshold` (default 60).
82
+ * ok=false, split=true otherwise — caller MUST slice the task into multiple
83
+ * iters (this function only signals the split requirement).
84
+ */
85
+ function computeUnattendedGate(opts) {
86
+ const o = opts || {};
87
+ const estimatedCwPct = Number.isFinite(o.estimatedCwPct) ? o.estimatedCwPct : 0;
88
+ const threshold = Number.isFinite(o.threshold) ? o.threshold : UNATTENDED_PER_WORKER_CW_PCT;
89
+ if (estimatedCwPct > threshold) {
90
+ return { ok: false, split: true };
91
+ }
92
+ return { ok: true, split: false };
93
+ }
43
94
 
44
95
  // token-budget is optional at require-time so unit tests can stub via dependency injection.
45
96
  let _tokenBudget = null;
@@ -155,7 +206,7 @@ function runParallel(opts) {
155
206
  const dryRun = !!(opts && opts.dryRun);
156
207
  const summarySize = Number.isFinite(opts && opts.summarySize)
157
208
  ? opts.summarySize
158
- : require(path.join(__dirname, "gsd-t-orchestrator-config.cjs")).DEFAULT_SUMMARY_SIZE_PCT;
209
+ : DEFAULT_SUMMARY_SIZE_PCT;
159
210
 
160
211
  const graph = buildTaskGraph({ projectDir });
161
212
  let candidates = getReadyTasks(graph);
@@ -5,23 +5,47 @@
5
5
  * `store` is the file path; `id` is the value of the `id` field on the matching row.
6
6
  *
7
7
  * Refuses to delete a record whose `id` does not start with `taggedPrefix`.
8
- * Atomic rewrite (write-temp + rename).
8
+ * `taggedPrefix` is REQUIRED and non-empty an empty/omitted prefix would
9
+ * disable the guard entirely (Red Team CRITICAL, M60). Atomic rewrite
10
+ * (write-temp + rename).
11
+ *
12
+ * When `projectDir` is supplied, `store` MUST resolve inside it — the adapter
13
+ * refuses paths outside-AND-equal-to projectDir (containment predicate from
14
+ * feedback_destructive_path_ops_containment). Prevents a tampered ledger from
15
+ * becoming a write-anywhere delete primitive.
9
16
  */
10
17
  const fs = require('node:fs');
11
18
  const path = require('node:path');
12
19
 
13
20
  const KIND = 'file-json-array';
14
21
 
15
- function purge({ store, id, taggedPrefix }) {
22
+ function assertContained(store, projectDir) {
23
+ if (typeof projectDir !== 'string' || projectDir.length === 0) {
24
+ return; // no projectDir supplied — containment not enforceable, caller's choice
25
+ }
26
+ const root = path.resolve(projectDir);
27
+ const resolved = path.resolve(store);
28
+ if (!(resolved.startsWith(root + path.sep) && resolved !== root)) {
29
+ throw new Error(
30
+ `file-json-array: store path "${store}" resolves outside projectDir "${projectDir}" — refused (containment guard)`
31
+ );
32
+ }
33
+ }
34
+
35
+ function purge({ store, id, taggedPrefix, projectDir }) {
16
36
  if (typeof store !== 'string' || store.length === 0) {
17
37
  throw new Error('file-json-array: store must be a non-empty file path');
18
38
  }
19
39
  if (typeof id !== 'string' || id.length === 0) {
20
40
  throw new Error('file-json-array: id must be a non-empty string');
21
41
  }
22
- if (typeof taggedPrefix === 'string' && taggedPrefix.length > 0 && !id.startsWith(taggedPrefix)) {
42
+ if (typeof taggedPrefix !== 'string' || taggedPrefix.length === 0) {
43
+ throw new Error('file-json-array: taggedPrefix is required and must be non-empty (guard cannot be disabled)');
44
+ }
45
+ if (!id.startsWith(taggedPrefix)) {
23
46
  throw new Error(`file-json-array: tag prefix mismatch (id="${id}", taggedPrefix="${taggedPrefix}")`);
24
47
  }
48
+ assertContained(store, projectDir);
25
49
 
26
50
  if (!fs.existsSync(store)) {
27
51
  return 'absent';
@@ -22,7 +22,12 @@ async function purge({ page, store, id, taggedPrefix }) {
22
22
  if (typeof id !== 'string' || id.length === 0) {
23
23
  throw new Error('localStorage-key-prefix: id must be a non-empty string');
24
24
  }
25
- if (typeof taggedPrefix === 'string' && taggedPrefix.length > 0 && !id.startsWith(taggedPrefix)) {
25
+ // taggedPrefix is REQUIRED and non-empty an empty/omitted prefix would
26
+ // disable the guard entirely (Red Team CRITICAL, M60).
27
+ if (typeof taggedPrefix !== 'string' || taggedPrefix.length === 0) {
28
+ throw new Error('localStorage-key-prefix: taggedPrefix is required and must be non-empty (guard cannot be disabled)');
29
+ }
30
+ if (!id.startsWith(taggedPrefix)) {
26
31
  throw new Error(`localStorage-key-prefix: tag prefix mismatch (id="${id}", taggedPrefix="${taggedPrefix}")`);
27
32
  }
28
33
 
@@ -8,11 +8,25 @@
8
8
  * still loads when the module isn't installed. Tests self-skip in that case.
9
9
  */
10
10
  const fs = require('node:fs');
11
+ const path = require('node:path');
11
12
 
12
13
  const KIND = 'sqlite-table-where';
13
14
 
14
15
  const IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
15
16
 
17
+ function assertContained(dbPath, projectDir) {
18
+ if (typeof projectDir !== 'string' || projectDir.length === 0) {
19
+ return; // no projectDir supplied — containment not enforceable, caller's choice
20
+ }
21
+ const root = path.resolve(projectDir);
22
+ const resolved = path.resolve(dbPath);
23
+ if (!(resolved.startsWith(root + path.sep) && resolved !== root)) {
24
+ throw new Error(
25
+ `sqlite-table-where: dbPath "${dbPath}" resolves outside projectDir "${projectDir}" — refused (containment guard)`
26
+ );
27
+ }
28
+ }
29
+
16
30
  function parseStore(store) {
17
31
  if (typeof store !== 'string') {
18
32
  throw new Error('sqlite-table-where: store must be "dbPath|table|idColumn"');
@@ -34,7 +48,7 @@ function parseStore(store) {
34
48
  return { dbPath, table, idColumn };
35
49
  }
36
50
 
37
- function purge({ store, id, taggedPrefix }) {
51
+ function purge({ store, id, taggedPrefix, projectDir }) {
38
52
  const { dbPath, table, idColumn } = parseStore(store);
39
53
  if (typeof id !== 'string' || id.length === 0) {
40
54
  throw new Error('sqlite-table-where: id must be a non-empty string');
@@ -45,6 +59,7 @@ function purge({ store, id, taggedPrefix }) {
45
59
  if (!id.startsWith(taggedPrefix)) {
46
60
  throw new Error(`sqlite-table-where: tag prefix mismatch (id="${id}", taggedPrefix="${taggedPrefix}")`);
47
61
  }
62
+ assertContained(dbPath, projectDir);
48
63
  if (!fs.existsSync(dbPath)) {
49
64
  return 'absent';
50
65
  }
@@ -129,6 +129,7 @@ async function purgeRunInserts({ projectDir, runId, dryRun }) {
129
129
  store: row.store,
130
130
  id: row.id,
131
131
  taggedPrefix: row.taggedPrefix,
132
+ projectDir, // thread through so path adapters can enforce containment (M60)
132
133
  });
133
134
  if (result === 'purged') {
134
135
  purged.push(row);