@tekyzinc/gsd-t 4.0.14 → 4.0.16

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [4.0.16] - 2026-06-02 (M69 Workflow scriptPath Resolution — patch)
6
+
7
+ ### Fixed — workflow commands now run from any project, not just the GSD-T source repo
8
+
9
+ Every workflow-backed command (`gsd-t-scan`, `-execute`, `-verify`, `-wave`, `-integrate`, `-debug`, and the 6 `-phase`-runner commands) hard-coded a relative `scriptPath: "templates/workflows/..."`. That path only resolves when CWD is the GSD-T source repo; from any consumer project the workflow script (which ships inside the installed package, not the project) is unreachable, so `Workflow({scriptPath})` silently fails and the agent falls back to a hand-driven run. This is why a deep scan in a consumer project produced the register but not the 5 `.gsd-t/scan/*.md` dimension files — the M67 Document phase never executed.
10
+
11
+ - `bin/gsd-t.js`: new `gsd-t workflow-path <name>` subcommand — prints the ABSOLUTE path to `gsd-t-<name>.workflow.js` resolved from the CLI's own `PKG_ROOT`. Accepts name aliases (with/without `gsd-t-` prefix or `.workflow.js` suffix). Exit 0 + path; exit 4 + available list on unknown name; exit 64 on missing arg. Resolves from any CWD (works for global/local/npx installs since it follows the invoked binary).
12
+ - `commands/gsd-t-{scan,execute,verify,wave,integrate,debug,partition,plan,impact,milestone,prd,doc-ripple,design-decompose}.md` (13 files): replaced the relative `scriptPath` with an instruction to resolve the absolute path first via `gsd-t workflow-path <name>`.
13
+ - `templates/CLAUDE-global.md`, `commands/gsd-t-help.md`: documented the resolution requirement + the new subcommand.
14
+ - `test/m69-workflow-path.test.js`: +6 tests (resolves known/aliased/all-8 workflows, CWD-independence, exit 4 unknown, exit 64 usage).
15
+
16
+ Effect: `/gsd-t-scan` (and all workflow commands) now run correctly from any registered project with no special prompt or absolute-path workaround.
17
+
18
+ ### Added — `.gsd-t/techdebt_in_plain_english.md` scan output
19
+
20
+ The scan Document phase now also writes a non-technical companion to the tech-debt register: every TD item restated in layman's terms, why it matters in business/user consequences, and a concrete real-world analogy, with severity translated into plain urgency. For founders/PMs/stakeholders who need the findings without the jargon.
21
+
22
+ - `templates/workflows/gsd-t-scan.workflow.js`: +1 `docTargets` entry (`techdebt-plain-english`); included in the document-phase git commit.
23
+ - `commands/gsd-t-scan.md`: Document Ripple lists the new output.
24
+
25
+ Suite: 1278 pass / 0 fail / 4 skip — zero regressions.
26
+
27
+ ## [4.0.15] - 2026-06-01 (M68 update-all Retired-Tool Prune — patch)
28
+
29
+ ### Fixed — update-all now prunes bin tools retired in M61/M65
30
+
31
+ `update-all` kept the propagated 7-tool subset fresh but never deleted tools GSD-T retired — the `DEPRECATED_BIN_STRAYS` sweep list only carried `gsd-t.js`. Result: 22 of 24 registered projects carried 11-17 dead `.cjs` files (the M61/M65 token-telemetry, unattended-relay, headless-spawn, and context-meter clusters), and the "already current" summary masked it. Surfaced when a project appeared not to update.
32
+
33
+ - `bin/gsd-t.js`: added the 17 M61/M65-retired tools to `DEPRECATED_BIN_STRAYS`; generalized the stray sweep so retired `.cjs` are pruned only when they carry a GSD-T provenance marker (`_hasGsdtProvenance`) — a user's same-named file without the marker is left untouched. `gsd-t.js` keeps its bespoke "GSD-T CLI Installer" header match.
34
+ - `test/bin-gsd-t-resilience.test.js`: +2 regression tests (retired-provenance `.cjs` swept; user-authored same-named `.cjs` survives).
35
+ - One-off: pruned 273 retired `.cjs` across the 21 affected projects (proved no live requirers first — the only references were retirement-breadcrumb comments).
36
+
37
+ Suite: 1269 pass / 0 fail / 4 skip — zero regressions.
38
+
5
39
  ## [4.0.14] - 2026-05-29 (M67 Scan Deep Document Phase — patch)
6
40
 
7
41
  ### Added — deterministic deep document cross-population in the scan Workflow
package/bin/gsd-t.js CHANGED
@@ -2473,11 +2473,60 @@ const PROJECT_BIN_TOOLS = [
2473
2473
 
2474
2474
  // Files that older versions of this installer copied into project bin/ but
2475
2475
  // are no longer part of PROJECT_BIN_TOOLS. On each update-all pass, sweep the
2476
- // project's bin/ and remove any stray file that still byte-matches the source
2477
- // copy in this package — that proves it's an old installer artifact, not a
2478
- // user's own file sharing the same name. User-owned files (byte-divergent)
2479
- // are left alone.
2480
- const DEPRECATED_BIN_STRAYS = ["gsd-t.js"];
2476
+ // project's bin/ and remove any stray that carries GSD-T provenance — that
2477
+ // proves it's an old installer artifact, not a user's own file sharing the
2478
+ // name. User-owned files (no GSD-T provenance marker) are left alone.
2479
+ //
2480
+ // M68: the M61/M65 retirement removed the token-telemetry + unattended +
2481
+ // headless-spawn + context-meter clusters from the package and from
2482
+ // PROJECT_BIN_TOOLS, but never added them here — so update-all kept the current
2483
+ // 7 tools fresh while leaving 11-17 dead .cjs lingering in every project's bin/.
2484
+ // Adding them closes that gap so future retirements prune cleanly.
2485
+ // Each retired tool maps to one or more VERBATIM header sentinels it actually
2486
+ // shipped with (recovered from git history at the commit before each was deleted).
2487
+ // A stray is swept only when its content contains the exact product header — proof
2488
+ // it was SHIPPED by this installer, not merely that it mentions "gsd-t". This is the
2489
+ // M68 red-team fix: the prior loose substring (`/gsd-t/` over 1200 chars) would have
2490
+ // deleted a user's own same-named helper that happened to reference a `.gsd-t/` path.
2491
+ // A user file can match only by reproducing a verbatim product header — implausible.
2492
+ const DEPRECATED_BIN_STRAY_SIGNATURES = {
2493
+ "gsd-t.js": ["GSD-T CLI Installer"], // bespoke installer header
2494
+ // M61 D3 — token telemetry / context-runway cluster
2495
+ "gsd-t-token-capture.cjs": ["GSD-T Token Capture", "gsd-t-token-capture"],
2496
+ "token-telemetry.cjs": ["GSD-T Token Telemetry"],
2497
+ "token-budget.cjs": ["GSD-T Token Budget"],
2498
+ "token-optimizer.cjs": ["GSD-T Token Optimizer"],
2499
+ "runway-estimator.cjs": ["GSD-T Runway", "runway-estimator"],
2500
+ // Verbatim shipped comment header (no bare "GSD-T" — red-team HIGH-1: a bare token
2501
+ // would delete a user's same-named file that merely mentions GSD-T).
2502
+ "context-budget-audit.cjs": ["Context Budget Audit — measures the static context cost"],
2503
+ "context-meter-config.cjs": ["Context Meter config loader (M34)"],
2504
+ "context-meter-config.test.cjs": ["context-meter-config"],
2505
+ // M61 D2 — unattended relay + headless spawn cluster
2506
+ "gsd-t-unattended.cjs": ["GSD-T Unattended", "gsd-t-unattended"],
2507
+ "gsd-t-unattended-platform.cjs": ["GSD-T Unattended", "gsd-t-unattended"],
2508
+ "gsd-t-unattended-safety.cjs": ["GSD-T Unattended", "gsd-t-unattended"],
2509
+ "headless-auto-spawn.cjs": ["GSD-T Headless Auto-Spawn"],
2510
+ "headless-exit-codes.cjs": ["GSD-T headless exit-code contract"],
2511
+ "handoff-lock.cjs": ["GSD-T Handoff Lock — Fail-safe sentinel"],
2512
+ "unattended-watch-format.cjs": ["bin/unattended-watch-format.cjs", "unattended watch-tick activity block"],
2513
+ // M61 D1/D4 — misc retired
2514
+ "log-tail.cjs": ["Log Tail — print the last N lines"], // verbatim shipped comment
2515
+ "event-stream.cjs": ["bin/event-stream.cjs", "unattended supervisor watch-tick"],
2516
+ };
2517
+ const DEPRECATED_BIN_STRAYS = Object.keys(DEPRECATED_BIN_STRAY_SIGNATURES);
2518
+
2519
+ // A stray is swept only if its first 1200 chars contain one of the VERBATIM header
2520
+ // sentinels the tool actually shipped with. "Mentions gsd-t" is NOT enough — that
2521
+ // would risk deleting a user's same-named file (red-team HIGH-1). Returns the matched
2522
+ // sentinel (for logging) or null.
2523
+ function _matchedStraySignature(name, content) {
2524
+ const sigs = DEPRECATED_BIN_STRAY_SIGNATURES[name];
2525
+ if (!sigs) return null;
2526
+ const head = content.slice(0, 1200);
2527
+ for (const s of sigs) if (head.includes(s)) return s;
2528
+ return null;
2529
+ }
2481
2530
 
2482
2531
  function copyBinToolsToProject(projectDir, projectName) {
2483
2532
  const projectBinDir = path.join(projectDir, "bin");
@@ -2537,19 +2586,15 @@ function copyBinToolsToProject(projectDir, projectName) {
2537
2586
  if (!fs.existsSync(strayPath)) continue;
2538
2587
  try {
2539
2588
  const strayContent = fs.readFileSync(strayPath, "utf8");
2540
- const head = strayContent.slice(0, 400);
2541
- // Signature-match any version this installer ever shipped. The marker
2542
- // is unique enough to rule out user-owned files: node shebang + the
2543
- // verbatim JSDoc header "GSD-T CLI Installer". Matches every historical
2544
- // version of bin/gsd-t.js, not just the current one, so older strays
2545
- // (e.g. v3.13.11 left behind on v3.13.12+) are still swept.
2546
- const isOurs =
2547
- head.startsWith("#!/usr/bin/env node") &&
2548
- head.includes("GSD-T CLI Installer");
2549
- if (isOurs) {
2589
+ const matched = _matchedStraySignature(stray, strayContent);
2590
+ if (matched) {
2550
2591
  fs.unlinkSync(strayPath);
2551
2592
  cleaned++;
2593
+ // Red-team fix (HIGH-2): name every deleted file so a destructive sweep
2594
+ // across many projects is reconstructable from scrollback, not a bare count.
2595
+ info(`${projectName} — removed retired bin/${stray} (matched shipped header "${matched.slice(0, 40)}")`);
2552
2596
  }
2597
+ // No signature match → leave it alone (user's own same-named file).
2553
2598
  } catch {
2554
2599
  // leave the file alone on any read error
2555
2600
  }
@@ -4401,6 +4446,43 @@ if (require.main === module) {
4401
4446
  const code = runParallelCli(args.slice(1), process.env);
4402
4447
  process.exit(code);
4403
4448
  }
4449
+ case "workflow-path": {
4450
+ // M69 — print the ABSOLUTE path to a GSD-T workflow script, resolved from
4451
+ // this CLI's own install root. Command files shell out to this instead of
4452
+ // hard-coding a relative `templates/workflows/...` scriptPath, which only
4453
+ // resolves when CWD is the GSD-T source repo — from any consumer project
4454
+ // the relative path is unresolvable and `Workflow({scriptPath})` silently
4455
+ // fails, forcing a hand-driven fallback (the HiloAviation scan incident).
4456
+ //
4457
+ // Usage: gsd-t workflow-path <name> (name with or without the
4458
+ // `gsd-t-` prefix / `.workflow.js` suffix). Exit 0 + path on stdout;
4459
+ // exit 4 + error on stderr if the workflow is unknown.
4460
+ const raw = (args[1] || "").trim();
4461
+ if (!raw) {
4462
+ process.stderr.write("usage: gsd-t workflow-path <name>\n");
4463
+ process.exit(64);
4464
+ }
4465
+ const wfDir = path.join(PKG_ROOT, "templates", "workflows");
4466
+ // Normalize: strip a leading "gsd-t-" and a trailing ".workflow.js"/".js",
4467
+ // then rebuild the canonical filename.
4468
+ const stem = raw
4469
+ .replace(/\.workflow\.js$/, "")
4470
+ .replace(/\.js$/, "")
4471
+ .replace(/^gsd-t-/, "");
4472
+ const file = path.join(wfDir, `gsd-t-${stem}.workflow.js`);
4473
+ if (!fs.existsSync(file)) {
4474
+ const avail = fs.existsSync(wfDir)
4475
+ ? fs.readdirSync(wfDir)
4476
+ .filter((f) => f.endsWith(".workflow.js"))
4477
+ .map((f) => f.replace(/^gsd-t-/, "").replace(/\.workflow\.js$/, ""))
4478
+ .join(", ")
4479
+ : "(workflows dir missing)";
4480
+ process.stderr.write(`gsd-t workflow-path: unknown workflow "${raw}". Available: ${avail}\n`);
4481
+ process.exit(4);
4482
+ }
4483
+ process.stdout.write(file + "\n");
4484
+ process.exit(0);
4485
+ }
4404
4486
  case "preflight": {
4405
4487
  // M55 D5 — `gsd-t preflight` thin dispatcher to bin/cli-preflight.cjs.
4406
4488
  const { spawnSync } = require("child_process");
@@ -22,7 +22,10 @@ Call the `Workflow` tool with:
22
22
 
23
23
  ```js
24
24
  {
25
- scriptPath: "templates/workflows/gsd-t-debug.workflow.js",
25
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path debug` (the
26
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
27
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
28
+ scriptPath: "<absolute path printed by `gsd-t workflow-path debug`>",
26
29
  args: {
27
30
  symptom: "describe the failing test or runtime error in one sentence",
28
31
  projectDir: "."
@@ -18,7 +18,10 @@ Capture the design reference from `$ARGUMENTS` (Figma URL / image path). If Figm
18
18
 
19
19
  ```js
20
20
  {
21
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
21
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
22
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
23
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
24
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
22
25
  args: {
23
26
  phase: "design-decompose",
24
27
  projectDir: ".",
@@ -18,7 +18,10 @@ Read the recent commit range (or `$ARGUMENTS` if a specific scope is given) and
18
18
 
19
19
  ```js
20
20
  {
21
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
21
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
22
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
23
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
24
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
22
25
  args: {
23
26
  phase: "doc-ripple",
24
27
  projectDir: ".",
@@ -22,7 +22,10 @@ Call the `Workflow` tool with:
22
22
 
23
23
  ```js
24
24
  {
25
- scriptPath: "templates/workflows/gsd-t-execute.workflow.js",
25
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path execute` (the
26
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
27
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
28
+ scriptPath: "<absolute path printed by `gsd-t workflow-path execute`>",
26
29
  args: {
27
30
  milestone: "M{NN}",
28
31
  domains: ["m{NN}-d1-...", "m{NN}-d2-...", ...],
@@ -432,6 +432,11 @@ Use these when user asks for help on a specific command:
432
432
  - **Files**: `.gsd-t/backlog-settings.md`
433
433
  - **Use when**: Customizing the classification dimensions for your project
434
434
 
435
+ ### workflow-path (M69)
436
+ - **Summary**: Prints the ABSOLUTE path to a GSD-T workflow script (`gsd-t-<name>.workflow.js`) resolved from the CLI's own install root. Command files shell out to this instead of hard-coding a relative `templates/workflows/...` scriptPath — which only resolves from the GSD-T source repo, so from any consumer project `Workflow({scriptPath})` would silently fail and fall back to a hand-driven scan (the HiloAviation incident).
437
+ - **Auto-invoked**: Yes — by every workflow-backed command (`gsd-t-scan`, `-execute`, `-verify`, `-wave`, `-integrate`, `-debug`, and the `-phase` runner) at Workflow-invocation time.
438
+ - **CLI**: `gsd-t workflow-path <name>` (name with or without the `gsd-t-` prefix / `.workflow.js` suffix). Exit 0 + absolute path on stdout; exit 4 + available list on unknown name; exit 64 on missing arg.
439
+
435
440
  ### preflight (M55)
436
441
  - **Summary**: Deterministic state-precondition check (`bin/cli-preflight.cjs`); 6 built-in checks (branch-guard, contracts-stable, deps-installed, manifest-fresh, ports-free, working-tree-state). Exit 0/4. Pluggable, zero-dep, captureSpawn-exempt.
437
442
  - **Auto-invoked**: Yes — by `gsd-t-execute` Step 1 and `gsd-t verify-gate` Track 1
@@ -18,7 +18,10 @@ Read `.gsd-t/progress.md`, the relevant domain `tasks.md`, and `docs/architectur
18
18
 
19
19
  ```js
20
20
  {
21
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
21
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
22
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
23
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
24
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
22
25
  args: {
23
26
  phase: "impact",
24
27
  milestone: "M{NN}",
@@ -28,7 +28,10 @@ Call the `Workflow` tool with:
28
28
 
29
29
  ```js
30
30
  {
31
- scriptPath: "templates/workflows/gsd-t-integrate.workflow.js",
31
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path integrate` (the
32
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
33
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
34
+ scriptPath: "<absolute path printed by `gsd-t workflow-path integrate`>",
32
35
  args: {
33
36
  milestone: "M{NN}",
34
37
  domains: ["m{NN}-d1-...", "m{NN}-d2-..."], // domains that just completed
@@ -18,7 +18,10 @@ Read `.gsd-t/progress.md` (current version + completed milestones), `docs/requir
18
18
 
19
19
  ```js
20
20
  {
21
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
21
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
22
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
23
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
24
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
22
25
  args: {
23
26
  phase: "milestone",
24
27
  projectDir: ".",
@@ -22,7 +22,10 @@ Call the `Workflow` tool with:
22
22
 
23
23
  ```js
24
24
  {
25
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
25
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
26
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
27
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
28
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
26
29
  args: {
27
30
  phase: "partition",
28
31
  milestone: "M{NN}",
@@ -18,7 +18,10 @@ Read `.gsd-t/progress.md` and each domain's `scope.md`/`constraints.md`. The par
18
18
 
19
19
  ```js
20
20
  {
21
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
21
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
22
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
23
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
24
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
22
25
  args: {
23
26
  phase: "plan",
24
27
  milestone: "M{NN}",
@@ -18,7 +18,10 @@ Read any existing `docs/requirements.md`, `docs/architecture.md`, and `.gsd-t/pr
18
18
 
19
19
  ```js
20
20
  {
21
- scriptPath: "templates/workflows/gsd-t-phase.workflow.js",
21
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path phase` (the
22
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
23
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
24
+ scriptPath: "<absolute path printed by `gsd-t workflow-path phase`>",
22
25
  args: {
23
26
  phase: "prd",
24
27
  projectDir: ".",
@@ -20,13 +20,19 @@ Each stage is a schema-validated `agent()` call (or deterministic CLI). Finders
20
20
 
21
21
  Read `CLAUDE.md`, `.gsd-t/progress.md`, `.gsd-t/contracts/`, and any existing `.gsd-t/techdebt.md` (the Workflow archives and continues from it). This tells the scan what's already known so it dedups rather than re-discovers.
22
22
 
23
- ## Step 2: Invoke the scan Workflow
23
+ ## Step 2: Resolve the workflow path, then invoke
24
24
 
25
- Call the `Workflow` tool with:
25
+ First resolve the ABSOLUTE path to the workflow script (the workflow ships inside the installed `@tekyzinc/gsd-t` package, NOT in the current project — a bare relative `templates/workflows/...` path only resolves when CWD is the GSD-T source repo, so from any other project `Workflow()` cannot find it). Run via Bash:
26
+
27
+ ```bash
28
+ gsd-t workflow-path scan
29
+ ```
30
+
31
+ It prints the absolute path (exit 0). Use that exact string as `scriptPath`. If `gsd-t` is not on PATH, fall back to `npx @tekyzinc/gsd-t workflow-path scan`, or derive it from the package: `node -e "const p=require('child_process').execSync('npm root -g').toString().trim(); console.log(p+'/@tekyzinc/gsd-t/templates/workflows/gsd-t-scan.workflow.js')"`. Do NOT fall back to a relative path or a hand-driven scan — that produces an incomplete result (the original bug). Then call the `Workflow` tool with:
26
32
 
27
33
  ```js
28
34
  {
29
- scriptPath: "templates/workflows/gsd-t-scan.workflow.js",
35
+ scriptPath: "<absolute path printed by `gsd-t workflow-path scan`>",
30
36
  args: {
31
37
  projectDir: ".", // the project to scan
32
38
  scanNumber: 12, // optional — for the register header
@@ -65,6 +71,7 @@ Present a summary: headline volume totals, findings by severity, the top critica
65
71
  The scan Workflow updates ALL of these deterministically (no manual follow-on):
66
72
 
67
73
  - `.gsd-t/techdebt.md` — fresh register (synthesis; prior one archived to `.gsd-t/techdebt_YYYY-MM-DD.md`)
74
+ - `.gsd-t/techdebt_in_plain_english.md` — non-technical companion to the register: every TD item in layman's terms, why it matters, and a real-world analogy (document phase)
68
75
  - `.gsd-t/scan/{architecture,security,quality,business-rules,contract-drift}.md` — dimension analysis files (document phase)
69
76
  - `docs/architecture.md`, `docs/workflows.md`, `docs/infrastructure.md`, `docs/requirements.md`, `README.md` — living docs, **merged not overwritten** (document phase)
70
77
  - HTML scan report via `bin/scan-report.js` (render phase)
@@ -31,7 +31,10 @@ Call the `Workflow` tool with:
31
31
 
32
32
  ```js
33
33
  {
34
- scriptPath: "templates/workflows/gsd-t-verify.workflow.js",
34
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path verify` (the
35
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
36
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
37
+ scriptPath: "<absolute path printed by `gsd-t workflow-path verify`>",
35
38
  args: {
36
39
  milestone: "M{NN}",
37
40
  projectDir: ".",
@@ -26,7 +26,10 @@ Call the `Workflow` tool with:
26
26
 
27
27
  ```js
28
28
  {
29
- scriptPath: "templates/workflows/gsd-t-wave.workflow.js",
29
+ // Resolve the ABSOLUTE path FIRST via Bash: `gsd-t workflow-path wave` (the
30
+ // workflow ships in the installed @tekyzinc/gsd-t package, not this project — a
31
+ // bare relative path only resolves from the GSD-T source repo). Use its stdout here:
32
+ scriptPath: "<absolute path printed by `gsd-t workflow-path wave`>",
30
33
  args: {
31
34
  milestone: "M{NN}",
32
35
  domains: ["m{NN}-d1-...", "m{NN}-d2-...", ...], // domains for this wave only, per integration-points
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "4.0.14",
3
+ "version": "4.0.16",
4
4
  "description": "GSD-T: Contract-Driven Development for Claude Code — 54 slash commands with headless-by-default workflow spawning, unattended supervisor relay with event stream, graph-powered code analysis, real-time agent dashboard, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",
@@ -319,7 +319,7 @@ Routine GSD-T actions (milestone → partition → plan → execute → verify
319
319
 
320
320
  ## GSD-T Workflows (M61 — v4.0.10+)
321
321
 
322
- GSD-T workflows live at `templates/workflows/`. Each workflow is a self-contained native Workflow script that handles one phase of the GSD-T lifecycle. Command files (`commands/gsd-t-*.md`) are thin invokers that call `Workflow({scriptPath, args})`.
322
+ GSD-T workflows live at `templates/workflows/`. Each workflow is a self-contained native Workflow script that handles one phase of the GSD-T lifecycle. Command files (`commands/gsd-t-*.md`) are thin invokers that call `Workflow({scriptPath, args})`. The `scriptPath` MUST be resolved to an absolute path at invoke time via `gsd-t workflow-path <name>` (M69) — the workflow ships inside the installed `@tekyzinc/gsd-t` package, not the consumer project, so a bare relative `templates/workflows/...` path only resolves from the GSD-T source repo and silently breaks `Workflow()` everywhere else.
323
323
 
324
324
  Canonical scripts:
325
325
  - `gsd-t-execute.workflow.js` — preflight → brief → file-disjointness → parallel(domain workers) → integrate → verify-gate
@@ -43,7 +43,7 @@ export const meta = {
43
43
  { title: "Probe", detail: "volume probe → derive per-area slice list", model: "haiku" },
44
44
  { title: "Deep Scan", detail: "pipeline: per-slice deep finder → single verify" },
45
45
  { title: "Synthesis", detail: "dedup / merge / re-rank into techdebt.md", model: "opus" },
46
- { title: "Document", detail: "deep living-doc + dimension-file cross-population (per-doc fan-out)" },
46
+ { title: "Document", detail: "deep living-doc + dimension-file + plain-English cross-population (per-doc fan-out)" },
47
47
  { title: "Render", detail: "schema extraction + diagrams + HTML report" },
48
48
  ],
49
49
  };
@@ -463,6 +463,13 @@ if (!fs.existsSync(registerPath)) {
463
463
  }
464
464
  log(`register written: ${JSON.stringify(synthesis.counts)}`);
465
465
 
466
+ // Read the synthesized register so the plain-English doc can mirror its EXACT
467
+ // TD-NNN ids / order (red-team HIGH-1: raw findings carry no TD ids, so a doc
468
+ // built only from findings would invent divergent numbering and break the
469
+ // cross-reference to techdebt.md). The register exists here (confirmed above).
470
+ let registerText = "";
471
+ try { registerText = fs.readFileSync(registerPath, "utf8"); } catch (_) {}
472
+
466
473
  // ─── Document — deep living-doc + dimension-file cross-population (M67) ───
467
474
  // M66 made the register deep but left doc cross-population as a non-deterministic
468
475
  // "lead agent follow-on" — effectively dropped. M67 fans out one agent PER DOCUMENT,
@@ -577,15 +584,51 @@ const docTargets = [
577
584
  id: "readme", label: "README.md", merge: true,
578
585
  prompt: `Update or create \`README.md\`: project name + description; tech stack + versions discovered; getting-started/setup (from infrastructure findings); brief architecture overview; link to \`docs/\` for detail. If it exists, MERGE — update tech-stack + setup sections but preserve the user's existing structure and custom content.`,
579
586
  },
587
+ {
588
+ id: "techdebt-plain-english", label: ".gsd-t/techdebt_in_plain_english.md",
589
+ needsRegister: true, // red-team HIGH-1: must receive the synthesized register (TD-NNN ids live there, not in findings)
590
+ prompt: `Write \`.gsd-t/techdebt_in_plain_english.md\` — a NON-TECHNICAL companion to the tech-debt register, written for a smart reader who is NOT an engineer (e.g. a founder, PM, or stakeholder). Cover EVERY item in the register (one entry per TD-NNN, in the same severity order), using the EXACT TD-NNN ids from the register provided below. For each item:\n` +
591
+ `- **Heading**: \`### TD-NNN — <the plain-English name of the problem>\` (keep the TD-NNN id so it cross-references the technical register, but rename the title into everyday language — no jargon).\n` +
592
+ `- **What it is** (1-2 sentences): explain the problem with ZERO technical terms. If a technical word is unavoidable, define it in parentheses the way you'd explain it to a friend.\n` +
593
+ `- **Why it matters** (1-2 sentences): the business/user consequence — what could go wrong, who is affected, what it costs.\n` +
594
+ `- **Real-world analogy**: a concrete everyday comparison that makes the risk intuitive (e.g. "This is like leaving the spare house key under the doormat — convenient, but anyone who thinks to look can get in." for a hardcoded secret). The analogy must genuinely map to THIS specific item, not be generic.\n` +
595
+ `- **Severity in plain terms**: translate CRITICAL/HIGH/MEDIUM/LOW into urgency a non-engineer feels ("fix before launch" / "schedule soon" / "clean up eventually").\n` +
596
+ `Open with a 2-3 sentence plain-English summary of the overall health of the codebase and the headline counts. Derive everything from the verified findings — do not invent items or analogies that don't fit. This file is the layman's lens on the same findings as \`.gsd-t/techdebt.md\`.`,
597
+ },
580
598
  ];
581
599
 
582
600
  const docResults = await parallel(
583
601
  docTargets.map((d) => async () => {
584
602
  const isLiving = !!d.merge;
603
+ // red-team HIGH-1: targets that mirror the register (plain-english) get the
604
+ // synthesized register text — the authoritative source of TD-NNN ids/order —
605
+ // not just the raw findings.
606
+ // red-team MEDIUM: do NOT silently truncate the register — a large register
607
+ // (e.g. 119 items ≈ 180KB) sliced to a small cap would drop the entire
608
+ // MEDIUM/LOW tail while the prompt says "cover EVERY item" (silent-cap
609
+ // anti-pattern the workflow forbids elsewhere). Cap generously, and if we DO
610
+ // hit it, tell the agent explicitly + log it so completeness loss is visible.
611
+ const REGISTER_CAP = 400000;
612
+ let registerBlock = "";
613
+ if (d.needsRegister) {
614
+ const truncated = registerText.length > REGISTER_CAP;
615
+ if (truncated) {
616
+ log(`⚠ register (${registerText.length} bytes) exceeds the ${REGISTER_CAP}-byte plain-english injection cap — the tail will be missing from techdebt_in_plain_english.md. Consider splitting the register.`);
617
+ }
618
+ registerBlock = [
619
+ "",
620
+ "Synthesized register (.gsd-t/techdebt.md) — use these EXACT TD-NNN ids/order:",
621
+ truncated ? "⚠ NOTE: the register was truncated to fit; cover every item you CAN see and end with a line noting that items beyond the last shown TD-NNN were omitted due to size." : "",
622
+ "```markdown",
623
+ registerText.slice(0, REGISTER_CAP),
624
+ "```",
625
+ ].join("\n");
626
+ }
585
627
  const prompt = [
586
628
  `You are the documentation agent for ONE document in a GSD-T deep scan.`,
587
629
  ``,
588
630
  baseCtx,
631
+ registerBlock,
589
632
  ``,
590
633
  d.prompt,
591
634
  ``,
@@ -680,7 +723,7 @@ if (render.ok) {
680
723
  // aren't versioned.
681
724
  const commit = spawnSync(
682
725
  "git",
683
- ["add", "-A", ".gsd-t/scan", "docs", "README.md", ":!.gsd-t/scan/.doc-backup"],
726
+ ["add", "-A", ".gsd-t/scan", ".gsd-t/techdebt_in_plain_english.md", "docs", "README.md", ":!.gsd-t/scan/.doc-backup"],
684
727
  { cwd: projectDir, stdio: "pipe" }
685
728
  );
686
729
  if (commit.status === 0) {