@tekyzinc/gsd-t 3.29.11 → 4.0.14

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 (114) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/bin/gsd-t-parallel.cjs +64 -13
  3. package/bin/gsd-t.js +48 -376
  4. package/bin/journey-coverage.cjs +6 -3
  5. package/bin/parallel-cli.cjs +13 -1
  6. package/commands/gsd-t-complete-milestone.md +6 -12
  7. package/commands/gsd-t-debug.md +47 -533
  8. package/commands/gsd-t-design-decompose.md +24 -497
  9. package/commands/gsd-t-doc-ripple.md +23 -139
  10. package/commands/gsd-t-execute.md +41 -958
  11. package/commands/gsd-t-feature.md +2 -6
  12. package/commands/gsd-t-gap-analysis.md +3 -6
  13. package/commands/gsd-t-help.md +2 -4
  14. package/commands/gsd-t-impact.md +26 -295
  15. package/commands/gsd-t-init-scan-setup.md +7 -7
  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-scan.md +45 -652
  24. package/commands/gsd-t-verify.md +52 -569
  25. package/commands/gsd-t-wave.md +41 -430
  26. package/package.json +1 -1
  27. package/scripts/gsd-t-calibration-hook.js +3 -1
  28. package/scripts/hooks/pre-commit-journey-coverage +0 -2
  29. package/scripts/hooks/pre-commit-playwright-gate +0 -2
  30. package/templates/CLAUDE-global.md +44 -173
  31. package/templates/CLAUDE-project.md +118 -104
  32. package/templates/prompts/design-verify-subagent.md +3 -0
  33. package/templates/prompts/qa-subagent.md +3 -0
  34. package/templates/prompts/red-team-subagent.md +5 -2
  35. package/templates/workflows/_lib.js +176 -0
  36. package/templates/workflows/gsd-t-debug.workflow.js +86 -0
  37. package/templates/workflows/gsd-t-execute.workflow.js +206 -0
  38. package/templates/workflows/gsd-t-integrate.workflow.js +71 -0
  39. package/templates/workflows/gsd-t-phase.workflow.js +94 -0
  40. package/templates/workflows/gsd-t-quick.workflow.js +72 -0
  41. package/templates/workflows/gsd-t-scan.workflow.js +711 -0
  42. package/templates/workflows/gsd-t-verify.workflow.js +348 -0
  43. package/templates/workflows/gsd-t-wave.workflow.js +43 -0
  44. package/bin/check-headless-sessions.js +0 -140
  45. package/bin/context-budget-audit.cjs +0 -447
  46. package/bin/context-meter-config.cjs +0 -101
  47. package/bin/context-meter-config.test.cjs +0 -101
  48. package/bin/event-stream.cjs +0 -205
  49. package/bin/gsd-t-benchmark-orchestrator.js +0 -437
  50. package/bin/gsd-t-capture-lint.cjs +0 -440
  51. package/bin/gsd-t-economics.cjs +0 -315
  52. package/bin/gsd-t-in-session-usage.cjs +0 -213
  53. package/bin/gsd-t-orchestrator-config.cjs +0 -161
  54. package/bin/gsd-t-orchestrator-queue.cjs +0 -180
  55. package/bin/gsd-t-orchestrator-recover.cjs +0 -231
  56. package/bin/gsd-t-orchestrator-worker.cjs +0 -219
  57. package/bin/gsd-t-orchestrator.js +0 -535
  58. package/bin/gsd-t-parallel-probe.cjs +0 -132
  59. package/bin/gsd-t-ratelimit-probe-worker.cjs +0 -237
  60. package/bin/gsd-t-ratelimit-probe.cjs +0 -648
  61. package/bin/gsd-t-report-tokens.cjs +0 -549
  62. package/bin/gsd-t-stream-feed-client.cjs +0 -151
  63. package/bin/gsd-t-token-backfill.cjs +0 -366
  64. package/bin/gsd-t-token-capture.cjs +0 -321
  65. package/bin/gsd-t-token-dashboard.cjs +0 -353
  66. package/bin/gsd-t-token-regenerate-log.cjs +0 -129
  67. package/bin/gsd-t-tool-attribution.cjs +0 -377
  68. package/bin/gsd-t-tool-cost.cjs +0 -195
  69. package/bin/gsd-t-transcript-tee.cjs +0 -246
  70. package/bin/gsd-t-unattended-heartbeat.cjs +0 -188
  71. package/bin/gsd-t-unattended-platform.cjs +0 -551
  72. package/bin/gsd-t-unattended-platform.js +0 -381
  73. package/bin/gsd-t-unattended-safety.cjs +0 -773
  74. package/bin/gsd-t-unattended-safety.js +0 -788
  75. package/bin/gsd-t-unattended.cjs +0 -2109
  76. package/bin/gsd-t-unattended.js +0 -1367
  77. package/bin/gsd-t-worker-dispatch.cjs +0 -211
  78. package/bin/handoff-lock.cjs +0 -249
  79. package/bin/handoff-lock.js +0 -249
  80. package/bin/headless-auto-spawn.cjs +0 -711
  81. package/bin/headless-auto-spawn.js +0 -373
  82. package/bin/headless-exit-codes.cjs +0 -67
  83. package/bin/live-activity-report.cjs +0 -615
  84. package/bin/log-tail.cjs +0 -81
  85. package/bin/m44-proof-measure.cjs +0 -285
  86. package/bin/m46-iter-proof.cjs +0 -149
  87. package/bin/m46-worker-proof.cjs +0 -201
  88. package/bin/m55-substrate-proof.cjs +0 -134
  89. package/bin/metrics-rollup.js +0 -200
  90. package/bin/model-windows.cjs +0 -99
  91. package/bin/model-windows.test.cjs +0 -75
  92. package/bin/parallelism-report.cjs +0 -535
  93. package/bin/runway-estimator.cjs +0 -242
  94. package/bin/spawn-plan-derive.cjs +0 -163
  95. package/bin/spawn-plan-status-updater.cjs +0 -292
  96. package/bin/spawn-plan-writer.cjs +0 -204
  97. package/bin/supervisor-pid-fingerprint.cjs +0 -126
  98. package/bin/token-budget.cjs +0 -265
  99. package/bin/unattended-watch-format.cjs +0 -178
  100. package/bin/watch-progress.js +0 -155
  101. package/commands/gsd-t-unattended-stop.md +0 -85
  102. package/commands/gsd-t-unattended-watch.md +0 -465
  103. package/commands/gsd-t-unattended.md +0 -476
  104. package/commands/gsd-t-visualize.md +0 -116
  105. package/scripts/gsd-t-context-meter.e2e.test.js +0 -364
  106. package/scripts/gsd-t-context-meter.js +0 -341
  107. package/scripts/gsd-t-context-meter.test.js +0 -471
  108. package/scripts/gsd-t-dashboard-server.js +0 -1203
  109. package/scripts/gsd-t-post-commit-spawn-plan.sh +0 -86
  110. package/scripts/gsd-t-transcript.html +0 -1821
  111. package/scripts/hooks/gsd-t-conversation-capture.js +0 -439
  112. package/scripts/hooks/gsd-t-in-session-usage-hook.js +0 -84
  113. package/scripts/spawn-plan-fmt-tokens.cjs +0 -80
  114. package/templates/hooks/post-commit-spawn-plan.sh +0 -85
@@ -0,0 +1,348 @@
1
+ // templates/workflows/gsd-t-verify.workflow.js
2
+ //
3
+ // Runtime: Anthropic native Workflow tool only (not standalone-Node parseable).
4
+ // Globals provided by runtime: agent, parallel, pipeline, log, phase, budget, args.
5
+ //
6
+ // Canonical verify-phase Workflow. Replaces the gsd-t-verify command shell with
7
+ // a deterministic pipeline:
8
+ // preflight → brief → verify-gate (deterministic, hard-fail) →
9
+ // parallel( /code-review ultra cooperative, Red Team adversarial, QA mechanics ) →
10
+ // synthesis ( merge findings WITHOUT collapsing categories — see orthogonal-validation-contract.md )
11
+ //
12
+ // args shape:
13
+ // {
14
+ // milestone: "M61",
15
+ // projectDir: ".", // optional
16
+ // skipUltra: false, // optional — skip /code-review ultra if rate-limited
17
+ // }
18
+
19
+ export const meta = {
20
+ name: "gsd-t-verify",
21
+ description:
22
+ "GSD-T verify phase: preflight → brief → verify-gate → CI-parity gate (M57) → test-data purge gate (M58) → parallel(code-review-ultra, Red Team, QA) → synthesis",
23
+ phases: [
24
+ { title: "Preflight", detail: "preflight + brief" },
25
+ { title: "Verify-Gate", detail: "deterministic two-track verify-gate" },
26
+ { title: "CI-Parity", detail: "M57 build-coverage + ci-parity (FAIL-blocking)" },
27
+ { title: "Test-Data Purge", detail: "M58 test-data --purge (FAIL-blocking)" },
28
+ { title: "Orthogonal Triad", detail: "code-review ultra ∥ Red Team ∥ QA" },
29
+ { title: "Synthesis", detail: "merge without collapsing categories" },
30
+ ],
31
+ };
32
+
33
+ const lib = require("./_lib.js");
34
+
35
+ const projectDir = (args && args.projectDir) || ".";
36
+ const milestone = (args && args.milestone) || null;
37
+ const skipUltra = (args && args.skipUltra) || false;
38
+ const skipUltraReason = (args && args.skipUltraReason) || null;
39
+
40
+ // 4.8-audit fix: skipUltra requires a recorded reason per
41
+ // orthogonal-validation-contract.md Rule #2. Refuse without one.
42
+ if (skipUltra && !skipUltraReason) {
43
+ log("verify: args.skipUltra=true requires args.skipUltraReason: string (per contract Rule #2)");
44
+ return { status: "failed", reason: "skipUltra-without-reason" };
45
+ }
46
+
47
+ // ───── Schemas ─────
48
+
49
+ const REVIEW_ULTRA_SCHEMA = {
50
+ type: "object",
51
+ required: ["category", "findings"],
52
+ additionalProperties: false,
53
+ properties: {
54
+ category: { const: "correctness-and-cleanup" },
55
+ findings: {
56
+ type: "array",
57
+ items: {
58
+ type: "object",
59
+ required: ["severity", "file", "summary"],
60
+ properties: {
61
+ severity: { type: "string", enum: ["important", "nit", "pre-existing"] },
62
+ file: { type: "string" },
63
+ line: { type: "integer" },
64
+ summary: { type: "string" },
65
+ suggestion: { type: "string" },
66
+ },
67
+ },
68
+ },
69
+ notes: { type: "string" },
70
+ },
71
+ };
72
+
73
+ const RED_TEAM_SCHEMA = {
74
+ type: "object",
75
+ required: ["category", "verdict", "bugs"],
76
+ additionalProperties: false,
77
+ properties: {
78
+ category: { const: "adversarial-security-boundaries" },
79
+ verdict: { type: "string", enum: ["FAIL", "GRUDGING-PASS"] },
80
+ bugs: {
81
+ type: "array",
82
+ items: {
83
+ type: "object",
84
+ required: ["severity", "title", "lens"],
85
+ properties: {
86
+ severity: { type: "string", enum: ["CRITICAL", "HIGH", "MEDIUM", "LOW"] },
87
+ title: { type: "string" },
88
+ lens: { type: "string" },
89
+ file: { type: "string" },
90
+ repro: { type: "string" },
91
+ },
92
+ },
93
+ },
94
+ notes: { type: "string" },
95
+ },
96
+ };
97
+
98
+ const QA_SCHEMA = {
99
+ type: "object",
100
+ required: ["category", "suiteResult", "shallowTests", "contractCompliance"],
101
+ additionalProperties: false,
102
+ properties: {
103
+ category: { const: "test-mechanics-and-compliance" },
104
+ suiteResult: {
105
+ type: "object",
106
+ required: ["pass", "fail"],
107
+ properties: {
108
+ pass: { type: "integer" },
109
+ fail: { type: "integer" },
110
+ skipped: { type: "integer" },
111
+ },
112
+ },
113
+ shallowTests: {
114
+ type: "array",
115
+ items: {
116
+ type: "object",
117
+ required: ["file", "test", "reason"],
118
+ properties: {
119
+ file: { type: "string" },
120
+ test: { type: "string" },
121
+ reason: { type: "string" },
122
+ },
123
+ },
124
+ },
125
+ contractCompliance: {
126
+ type: "object",
127
+ required: ["compliant", "violations"],
128
+ properties: {
129
+ compliant: { type: "boolean" },
130
+ violations: { type: "array", items: { type: "string" } },
131
+ },
132
+ },
133
+ notes: { type: "string" },
134
+ },
135
+ };
136
+
137
+ const VERDICT_SCHEMA = {
138
+ type: "object",
139
+ required: ["overallVerdict", "summary"],
140
+ additionalProperties: false,
141
+ properties: {
142
+ overallVerdict: { type: "string", enum: ["VERIFIED", "VERIFIED-WITH-WARNINGS", "VERIFY-FAILED"] },
143
+ summary: { type: "string" },
144
+ blockingFindings: { type: "array", items: { type: "string" } },
145
+ },
146
+ };
147
+
148
+ // ───── Script body ─────
149
+
150
+ if (!milestone) {
151
+ log("verify: args.milestone required");
152
+ return { status: "failed", reason: "missing-milestone" };
153
+ }
154
+
155
+ phase("Preflight");
156
+ const pre = lib.runPreflight({ projectDir });
157
+ if (!pre.ok) {
158
+ log(`preflight FAIL — halting verify`);
159
+ return { status: "failed", reason: "preflight-failed", preflight: pre.envelope };
160
+ }
161
+ const brief = lib.generateBrief({ kind: "verify", milestone, projectDir });
162
+
163
+ phase("Verify-Gate");
164
+ const vg = lib.runVerifyGate({ projectDir });
165
+ if (!vg.ok) {
166
+ log(`verify-gate FAIL exitCode=${vg.exitCode} — halting before triad`);
167
+ return {
168
+ status: "verify-gate-failed",
169
+ overallVerdict: "VERIFY-FAILED",
170
+ verifyGate: vg.envelope,
171
+ };
172
+ }
173
+ log(`verify-gate green`);
174
+
175
+ // ─── M57 CI-Parity Gate (FAIL-blocking) ───────────────────────────────────
176
+ // Per commands/gsd-t-verify.md Step 2.6 + cli-build-coverage-contract.md +
177
+ // ci-parity-contract.md. NEITHER track is currently inside verify-gate.cjs.
178
+ // Origin: TimeTracking v1.10.12 shipped VERIFIED+tagged with a new dir absent
179
+ // from Dockerfile COPY — silent CI-divergence regression. M57 made this gate
180
+ // mandatory; Workflow MUST preserve it or we re-introduce that exact failure.
181
+ // Detected by user/worker in parallel session 2026-05-29 13:00.
182
+ phase("CI-Parity");
183
+ const { spawnSync } = require("child_process");
184
+ function _runJsonCli(subcmd, argv = []) {
185
+ // Use _lib-style resolution — prefer project-local bin/<tool>.cjs
186
+ const fsMod = require("fs");
187
+ const pMod = require("path");
188
+ const localMap = {
189
+ "build-coverage": "gsd-t-build-coverage.cjs",
190
+ "ci-parity": "gsd-t-ci-parity.cjs",
191
+ "test-data": "gsd-t-test-data-ledger.cjs",
192
+ };
193
+ const local = pMod.join(projectDir, "bin", localMap[subcmd] || "");
194
+ const cmd = fsMod.existsSync(local) ? process.execPath : "gsd-t";
195
+ const args = fsMod.existsSync(local) ? [local, ...argv] : [subcmd, ...argv];
196
+ const r = spawnSync(cmd, args, { cwd: projectDir, stdio: "pipe" });
197
+ let envelope = null;
198
+ try { envelope = r.stdout ? JSON.parse(r.stdout.toString()) : null; } catch (_) {}
199
+ return {
200
+ ok: r.status === 0,
201
+ exitCode: r.status,
202
+ envelope,
203
+ stderr: r.stderr && r.stderr.toString(),
204
+ };
205
+ }
206
+ const bc = _runJsonCli("build-coverage", ["--json"]);
207
+ if (!bc.ok) {
208
+ log(`M57 build-coverage FAIL exitCode=${bc.exitCode} — halting (FAIL-blocking)`);
209
+ return { status: "ci-parity-failed", overallVerdict: "VERIFY-FAILED", buildCoverage: bc.envelope };
210
+ }
211
+ const cip = _runJsonCli("ci-parity", ["--json"]);
212
+ if (!cip.ok) {
213
+ log(`M57 ci-parity FAIL exitCode=${cip.exitCode} — halting (FAIL-blocking)`);
214
+ return { status: "ci-parity-failed", overallVerdict: "VERIFY-FAILED", ciParity: cip.envelope };
215
+ }
216
+ log(`M57 CI-parity gate green`);
217
+
218
+ // ─── M58 Test-Data Purge Gate (FAIL-blocking) ─────────────────────────────
219
+ // Per commands/gsd-t-verify.md Step 4.5 + test-data-tagging-contract.md v1.1.0.
220
+ // Origin: GSD-T-Board v0.1.10 shipped VERIFIED with 2442 E2E_TEST_* orphans
221
+ // live in production data. M58 made post-E2E purge mandatory; M60 hardened
222
+ // the adapters against empty-prefix bypass. Workflow MUST preserve.
223
+ phase("Test-Data Purge");
224
+ const verifyRunId = `verify-${milestone || "M??"}-${Date.now().toString(36)}`;
225
+ const td = _runJsonCli("test-data", ["--purge", "--run", verifyRunId, "--json"]);
226
+ if (!td.ok) {
227
+ log(`M58 test-data purge FAIL exitCode=${td.exitCode} — halting (FAIL-blocking)`);
228
+ return { status: "test-data-purge-failed", overallVerdict: "VERIFY-FAILED", testDataPurge: td.envelope };
229
+ }
230
+ log(`M58 test-data purge green — proceeding to orthogonal triad`);
231
+
232
+ phase("Orthogonal Triad");
233
+
234
+ const briefRef = brief.briefPath || "(brief generation failed — re-walk repo)";
235
+
236
+ // Load the methodology protocols KEPT in templates/prompts/. The protocol body
237
+ // IS the methodology — Workflow just hosts the agent() call.
238
+ const redTeamProtocol = lib.loadProtocol("red-team");
239
+ const qaProtocol = lib.loadProtocol("qa");
240
+
241
+ const stages = [
242
+ // Stage A — /code-review ultra (cooperative correctness + cleanup)
243
+ // Per orthogonal-validation-contract.md: this finds bugs+cleanups in the
244
+ // "build it right" lens. NEVER substitutes for Red Team.
245
+ !skipUltra && (() => agent(
246
+ [
247
+ `You are running a /code-review ultra cooperative pass for milestone \`${milestone}\`.`,
248
+ ``,
249
+ `**Brief (REQUIRED):** ${briefRef}`,
250
+ ``,
251
+ `Per .gsd-t/contracts/orthogonal-validation-contract.md, your scope is`,
252
+ `**correctness + cleanup** — reuse, simplification, efficiency, altitude cleanups.`,
253
+ `You are COOPERATIVE — assume the code is being built in good faith. You are`,
254
+ `NOT looking for adversarial security bugs (Red Team's job) or test-mechanics`,
255
+ `issues (QA's job). Report only findings in your category.`,
256
+ ``,
257
+ `Severity: "important" (must-fix bugs), "nit" (style/clarity), "pre-existing"`,
258
+ `(out of milestone scope but worth flagging).`,
259
+ ``,
260
+ `Return JSON per the schema.`,
261
+ ].join("\n"),
262
+ { label: "code-review-ultra", phase: "Orthogonal Triad", schema: REVIEW_ULTRA_SCHEMA, model: "opus" }
263
+ )),
264
+
265
+ // Stage B — Red Team (adversarial / security / boundaries)
266
+ () => agent(
267
+ [
268
+ `You are the Red Team adversarial validator for milestone \`${milestone}\`.`,
269
+ ``,
270
+ `**Brief (REQUIRED):** ${briefRef}`,
271
+ ``,
272
+ `Per .gsd-t/contracts/orthogonal-validation-contract.md, your scope is`,
273
+ `**adversarial / security / boundaries**. You are NOT cooperative — your`,
274
+ `success is measured in bugs FOUND, not tests passed. Try to break the code.`,
275
+ ``,
276
+ `Run the Red Team protocol:`,
277
+ "----- BEGIN RED TEAM PROTOCOL -----",
278
+ redTeamProtocol.slice(0, 8000),
279
+ "----- END RED TEAM PROTOCOL -----",
280
+ ``,
281
+ `Verdict is FAIL if you found any CRITICAL or HIGH severity bug; GRUDGING-PASS`,
282
+ `if you searched exhaustively and found nothing. Return JSON per the schema.`,
283
+ ].join("\n"),
284
+ { label: "red-team", phase: "Orthogonal Triad", schema: RED_TEAM_SCHEMA, model: "opus" }
285
+ ),
286
+
287
+ // Stage C — QA (test execution + shallow-test detection + contract compliance)
288
+ () => agent(
289
+ [
290
+ `You are the QA validator for milestone \`${milestone}\`.`,
291
+ ``,
292
+ `**Brief (REQUIRED):** ${briefRef}`,
293
+ ``,
294
+ `Per .gsd-t/contracts/orthogonal-validation-contract.md, your scope is`,
295
+ `**test mechanics + contract compliance**. Run the test suite. Report pass/fail/skip`,
296
+ `counts. Detect shallow tests (layout-only assertions that pass on an empty HTML page).`,
297
+ `Verify contract compliance against .gsd-t/contracts/.`,
298
+ ``,
299
+ `Run the QA protocol:`,
300
+ "----- BEGIN QA PROTOCOL -----",
301
+ qaProtocol.slice(0, 8000),
302
+ "----- END QA PROTOCOL -----",
303
+ ``,
304
+ `Return JSON per the schema.`,
305
+ ].join("\n"),
306
+ { label: "qa", phase: "Orthogonal Triad", schema: QA_SCHEMA, model: "sonnet" }
307
+ ),
308
+ ].filter(Boolean);
309
+
310
+ const triadResults = await parallel(stages);
311
+
312
+ phase("Synthesis");
313
+ const synthesisPrompt = [
314
+ `You are the synthesis agent. Three orthogonal validators have run.`,
315
+ `**Do NOT collapse categories**: a Red Team CRITICAL is not the same as a`,
316
+ `/code-review ultra "important" finding. Per orthogonal-validation-contract.md,`,
317
+ `they're declared orthogonal objective functions and must stay distinct in the report.`,
318
+ ``,
319
+ `Validator results:`,
320
+ "```json",
321
+ JSON.stringify(triadResults, null, 2),
322
+ "```",
323
+ ``,
324
+ `Compute the overall verdict per orthogonal-validation-contract.md v1.0.0:`,
325
+ `- VERIFIED iff: Red Team verdict=GRUDGING-PASS AND QA suiteResult.fail=0 AND QA shallowTests=[] AND QA contractCompliance.compliant=true AND code-review ultra ran AND has no "important" findings. **skipUltra=${skipUltra} → ${skipUltra ? "INELIGIBLE for VERIFIED (skipUltra=true downgrades to VERIFIED-WITH-WARNINGS at best per Rule #2)" : "eligible"}.**`,
326
+ `- VERIFIED-WITH-WARNINGS if: Red Team GRUDGING-PASS, QA suite green, contracts compliant, AND any of: code-review ultra has "important" findings, OR skipUltra=true (reason: ${skipUltraReason || "(none — would have failed above)"}), OR QA shallowTests.length === 1 (single non-core).`,
327
+ `- VERIFY-FAILED otherwise (Red Team FAIL, QA fail>0, contract violations>0, shallowTests ≥ 2 or in core paths).`,
328
+ ``,
329
+ `Return JSON per VERDICT_SCHEMA with blockingFindings listing concrete things that must fix.`,
330
+ ].join("\n");
331
+
332
+ const verdict = await agent(synthesisPrompt, {
333
+ label: "synthesis",
334
+ phase: "Synthesis",
335
+ schema: VERDICT_SCHEMA,
336
+ model: "opus",
337
+ });
338
+
339
+ return {
340
+ status: verdict.overallVerdict === "VERIFY-FAILED" ? "failed" : "complete",
341
+ overallVerdict: verdict.overallVerdict,
342
+ verifyGate: vg.envelope,
343
+ buildCoverage: bc.envelope,
344
+ ciParity: cip.envelope,
345
+ testDataPurge: td.envelope,
346
+ triad: triadResults,
347
+ verdict,
348
+ };
@@ -0,0 +1,43 @@
1
+ // templates/workflows/gsd-t-wave.workflow.js
2
+ //
3
+ // Runtime: Anthropic native Workflow tool only.
4
+ // Full milestone wave: execute then verify, with C-checkpoint gates between.
5
+ //
6
+ // args: { milestone, domains: [...], projectDir?, autoIntegrate? }
7
+
8
+ export const meta = {
9
+ name: "gsd-t-wave",
10
+ description: "Execute then verify a milestone end-to-end, with integrate barrier",
11
+ phases: [
12
+ { title: "Execute", detail: "domain workers + integrate" },
13
+ { title: "Verify", detail: "orthogonal triad + verify-gate" },
14
+ ],
15
+ };
16
+
17
+ const lib = require("./_lib.js");
18
+
19
+ const projectDir = (args && args.projectDir) || ".";
20
+ const milestone = (args && args.milestone) || null;
21
+ const domains = (args && args.domains) || [];
22
+
23
+ if (!milestone || !domains.length) {
24
+ log("wave: args.milestone and args.domains required");
25
+ return { status: "failed", reason: "missing-args" };
26
+ }
27
+
28
+ phase("Execute");
29
+ const execResult = await workflow("gsd-t-execute", { milestone, domains, projectDir });
30
+ if (execResult.status !== "complete") {
31
+ log(`execute status=${execResult.status} — halting before verify`);
32
+ return { status: execResult.status, stage: "execute", execResult };
33
+ }
34
+
35
+ phase("Verify");
36
+ const verifyResult = await workflow("gsd-t-verify", { milestone, projectDir });
37
+
38
+ return {
39
+ status: verifyResult.status === "complete" ? "complete" : "verify-failed",
40
+ milestone,
41
+ execResult,
42
+ verifyResult,
43
+ };
@@ -1,140 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * GSD-T Check Headless Sessions — Read-back banner helper
5
- *
6
- * Scans .gsd-t/headless-sessions/ for completed sessions that have not yet
7
- * been surfaced to the user. Consumed by `gsd-t-resume` and `gsd-t-status`
8
- * to print a "Headless runs since you left" banner at the start of their
9
- * output. After surfacing, marks the session file with `surfaced: true`
10
- * so the banner never re-appears for the same session.
11
- *
12
- * Zero external dependencies (Node.js built-ins only).
13
- *
14
- * Contract: .gsd-t/contracts/headless-auto-spawn-contract.md v1.0.0
15
- * Consumers: commands/gsd-t-resume.md, commands/gsd-t-status.md
16
- */
17
-
18
- const fs = require("fs");
19
- const path = require("path");
20
-
21
- const SESSIONS_DIR_REL = path.join(".gsd-t", "headless-sessions");
22
-
23
- module.exports = {
24
- checkCompletedSessions,
25
- markSurfaced,
26
- formatBanner,
27
- printBannerIfAny,
28
- };
29
-
30
- /**
31
- * @param {string} [projectDir]
32
- * @returns {Array<object>} unsurfaced completed sessions, oldest first
33
- */
34
- function checkCompletedSessions(projectDir) {
35
- const dir = path.join(projectDir || process.cwd(), SESSIONS_DIR_REL);
36
- if (!fs.existsSync(dir)) return [];
37
-
38
- const entries = [];
39
- let files;
40
- try {
41
- files = fs.readdirSync(dir);
42
- } catch (_) {
43
- return [];
44
- }
45
-
46
- for (const f of files) {
47
- if (!f.endsWith(".json")) continue;
48
- if (f.endsWith("-context.json")) continue;
49
- const fp = path.join(dir, f);
50
- try {
51
- const s = JSON.parse(fs.readFileSync(fp, "utf8"));
52
- if (s && s.status === "completed" && s.surfaced !== true) {
53
- entries.push(s);
54
- }
55
- } catch (_) {
56
- // skip malformed session files silently
57
- }
58
- }
59
-
60
- entries.sort((a, b) => {
61
- const ta = a.endTimestamp || a.startTimestamp || "";
62
- const tb = b.endTimestamp || b.startTimestamp || "";
63
- return ta.localeCompare(tb);
64
- });
65
-
66
- return entries;
67
- }
68
-
69
- /**
70
- * Mark a session as surfaced so the banner won't re-appear for it.
71
- * @param {string} projectDir
72
- * @param {string} id
73
- */
74
- function markSurfaced(projectDir, id) {
75
- const fp = path.join(projectDir || process.cwd(), SESSIONS_DIR_REL, `${id}.json`);
76
- if (!fs.existsSync(fp)) return;
77
- try {
78
- const s = JSON.parse(fs.readFileSync(fp, "utf8"));
79
- s.surfaced = true;
80
- fs.writeFileSync(fp, JSON.stringify(s, null, 2) + "\n");
81
- } catch (_) {
82
- /* ignore */
83
- }
84
- }
85
-
86
- /**
87
- * Format a human-readable banner for the given sessions. Does not print.
88
- * @param {Array<object>} sessions
89
- * @returns {string}
90
- */
91
- function formatBanner(sessions) {
92
- if (!sessions || sessions.length === 0) return "";
93
- const lines = [];
94
- lines.push("## Headless runs since you left");
95
- lines.push("");
96
- for (const s of sessions) {
97
- const duration = computeDurationLabel(s.startTimestamp, s.endTimestamp);
98
- const outcome = s.exitCode === 0 ? "success" : `exit ${s.exitCode}`;
99
- const cmd = s.command || "(unknown)";
100
- lines.push(`- **${s.id}** — ${cmd} — ${duration} — ${outcome}`);
101
- if (s.logPath) lines.push(` Log: \`${s.logPath}\``);
102
- }
103
- lines.push("");
104
- return lines.join("\n");
105
- }
106
-
107
- /**
108
- * Convenience wrapper: check, print to stdout if any, mark surfaced.
109
- * Returns number of sessions surfaced.
110
- */
111
- function printBannerIfAny(projectDir) {
112
- const sessions = checkCompletedSessions(projectDir);
113
- if (sessions.length === 0) return 0;
114
- process.stdout.write(formatBanner(sessions) + "\n");
115
- for (const s of sessions) markSurfaced(projectDir, s.id);
116
- return sessions.length;
117
- }
118
-
119
- function computeDurationLabel(startIso, endIso) {
120
- if (!startIso || !endIso) return "unknown duration";
121
- const start = Date.parse(startIso);
122
- const end = Date.parse(endIso);
123
- if (!isFinite(start) || !isFinite(end) || end < start) return "unknown duration";
124
- const secs = Math.round((end - start) / 1000);
125
- if (secs < 60) return `${secs}s`;
126
- const mins = Math.floor(secs / 60);
127
- const rem = secs % 60;
128
- if (mins < 60) return `${mins}m ${rem}s`;
129
- const hrs = Math.floor(mins / 60);
130
- const remMins = mins % 60;
131
- return `${hrs}h ${remMins}m`;
132
- }
133
-
134
- // ── CLI entry point ─────────────────────────────────────────────────────────
135
-
136
- if (require.main === module) {
137
- const projectDir = process.argv[2] || process.cwd();
138
- const n = printBannerIfAny(projectDir);
139
- process.exit(n > 0 ? 0 : 0);
140
- }