@tekyzinc/gsd-t 5.11.10 → 5.11.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,78 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [5.11.12] - 2026-08-09
6
+
7
+ ### Fixed — a retired command stayed typeable forever
8
+
9
+ Installing only ever copied, so a command retired in a past milestone never left
10
+ the machine. Eleven were still typeable long after the code behind them was
11
+ deleted — brainstorm, discuss and prompt (M38), the unattended trio and
12
+ visualize (M61). A command that still answers is one a person will reasonably
13
+ use; this surfaced when `/gsd-t-brainstorm` was treated as live and turned out
14
+ to have no source at all.
15
+
16
+ Install now deletes GSD-T commands the package no longer ships and NAMES each
17
+ one. Only `gsd-t-*.md` is considered, so a command you wrote is never touched.
18
+ An unreadable commands directory stops the install rather than reporting a clean
19
+ pass over a check that never ran.
20
+
21
+ README advertised five commands that do not exist while `help.md` correctly
22
+ called them retired — the two disagreed, and the README is what a reader
23
+ believes.
24
+
25
+ ### Changed — /last30days is the first stop for an outside fact
26
+
27
+ Wired into the external-fact rule, the conversation-scope rule, and the
28
+ architect's research step. It searches where people report what actually
29
+ happened — Reddit, Hacker News, X, YouTube transcripts, GitHub — ranked by what
30
+ they engaged with, which is what those stages are asking for and what no
31
+ training data holds. About 40 seconds; web search remains the follow-up. Not
32
+ installed means SAY so in one line and use web search — never silently research
33
+ a thinner way.
34
+
35
+ Install it with `/plugin marketplace add mvanhorn/last30days-skill` then
36
+ `/plugin install last30days`.
37
+
38
+ - `bin/gsd-t.js`: retired commands are removed and named
39
+ - `README.md`: five dead command rows removed
40
+ - `commands/gsd-t-architect.md`, `templates/CLAUDE-global.md`: the research wiring
41
+ - `test/m112-retired-commands.test.js`: 5 tests, including that the README advertises nothing it does not ship
42
+
43
+ ## [5.11.11] - 2026-08-09
44
+
45
+ ### Fixed — the reply shortener was shortening itself
46
+
47
+ The child Claude was started with the personal settings, which carry the very
48
+ Stop hook that spawned it. It answered in about 4 seconds, its own hook then saw
49
+ an answer over the 60-word threshold and spawned a THIRD Claude, and the outer
50
+ call waited ~46s for work it had caused — past its own 45s limit, so it was
51
+ killed and returned nothing. Every turn, since the day it shipped.
52
+
53
+ `--setting-sources project` starts the child without the personal layer.
54
+ Measured twice each: **54.2s/54.5s before, 7.9s/6.2s after**; through the real
55
+ hook, 8.6s / 10.1s / 10.8s, all producing a rewrite.
56
+
57
+ The trigger was always the child's own REPLY crossing 60 words, never the input
58
+ text — a 63-character prompt that produces a long answer is just as slow.
59
+
60
+ Two flags rejected by measurement and recorded so they are not retried: `--bare`
61
+ skips the keychain and the child answers "Not logged in"; `--settings '{}'`
62
+ cannot remove an inherited hook, because settings layers merge.
63
+
64
+ The `--disallowed-tools` flag from 5.11.10 is removed — its root cause was
65
+ disproved (52.6s with, 52.5s without), and leaving it would enshrine a wrong
66
+ explanation.
67
+
68
+ Separately: the hook captured the rewriter's stderr into a pipe it never read,
69
+ so the loud timeout warning added in 5.11.10 reached nobody. It is inherited
70
+ now — the let-it-through paths are approved passes *because* the reader can see
71
+ them happen.
72
+
73
+ - `bin/gsd-t-concise-rewrite.cjs`: the child no longer inherits the hook that spawned it
74
+ - `scripts/gsd-t-concise-hook.js`: the child's stderr reaches the screen
75
+ - `test/m107-concise-rewrite.test.js`: 3 tests pin the recursion, the two rejected flags, the stderr
76
+
5
77
  ## [5.11.10] - 2026-08-09
6
78
 
7
79
  ### Fixed — four safety gates were passing without checking anything
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v5.11.10** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v5.11.12** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
4
4
 
5
5
  **Eliminates context rot** — task-level fresh dispatch (one subagent per task, ~10-20% context each) means compaction never triggers.
6
6
  **Compaction-proof debug loops** — `gsd-t headless --debug-loop` runs test-fix-retest cycles as separate `claude -p` sessions. A JSONL debug ledger persists all hypothesis/fix/learning history across fresh sessions. Anti-repetition preamble injection prevents retrying failed hypotheses. Escalation tiers (sonnet → opus → human) and a hard iteration ceiling enforced externally.
@@ -17,7 +17,6 @@
17
17
  **Real-Time Agent Dashboard** — `gsd-t-stream-feed-server.js` serves a streaming UI at `127.0.0.1:7842` that renders all workers' stream-json output as a continuous feed with task/wave banners, duration + usage chips, token corner bar, localStorage filters, and replay via `WS /feed?from=N`. Dashboard auto-starts idempotently on each spawn (`scripts/gsd-t-dashboard-autostart.cjs`). Port is project-scoped via `projectScopedDefaultPort(projectDir)` so multi-project workflows do not clobber each other.
18
18
  **Rigorous User-Journey Coverage + Anti-Drift Test Quality** — `bin/journey-coverage.cjs` regex listener detector + `gsd-t check-coverage` CLI + `scripts/hooks/pre-commit-journey-coverage` commit gate blocks viewer-source commits when uncovered listeners exist. Journey specs in `e2e/journeys/` use functional assertions (zero `toBeVisible`-only tests) per the E2E Test Quality Standard in CLAUDE.md.
19
19
  **Universal Playwright Bootstrap + Deterministic UI Enforcement (M50)** — three executable enforcement layers: (1) `bin/playwright-bootstrap.cjs` + `bin/ui-detection.cjs` - idempotent installer detects package manager, installs `@playwright/test` + chromium, scaffolds `e2e/`; (2) Workflow runtime runs `playwright-bootstrap.cjs::installPlaywright()` before any E2E stage when `hasUI && !hasPlaywright`; install failure halts with `blocked-needs-human`; (3) `scripts/hooks/pre-commit-playwright-gate` (opt-in via `gsd-t doctor --install-hooks`) blocks viewer-source commits when staged files are newer than `.gsd-t/.last-playwright-pass`. The `gsd-t setup-playwright [path]` subcommand handles manual install.
20
- **Visualizer (`/gsd-t-visualize`)** — launches a real-time browser dashboard with dual-pane view: top pane streams the main session, bottom pane streams whichever spawn the user clicks. Left rail shows Live Spawns and Completed (last 100 spawns, status-badged, collapsible). Right rail shows Spawn Plan / Parallelism / Tool Cost. Powered by `gsd-t-stream-feed-server.js` + `gsd-t-dashboard.html`.
21
20
  **Surgical model selection** — models are assigned haiku/sonnet/opus per phase (**Fable removed 2026-07-24**; `opus` = **claude-opus-5**). **Single-source tier policy:** `bin/gsd-t-model-tier-policy.cjs` is the SINGLE source of truth; every high-stakes stage (solution-space probe, partition probe, competition judge, pre-mortem, Red Team, competition producers, debug both cycles) runs Opus 5. Opus 5 shipped at the same price as Opus 4.8 but >2× its coding score, so Fable's cost premium is no longer justified. The M82 judge-blindness invariant is relaxed to "fresh independent context" — producers and judge both run opus. Drift is mechanically enforced by the M71-family lint (`test/m85-workflow-tier-policy-lint.test.js`). **M86 model profiles:** `bin/gsd-t-model-profile.cjs` adds a per-project SECOND dimension — three named profiles (`standard` / `pro` / `premium`) that dial which stages run on Opus vs. Sonnet.
22
21
  **Token Telemetry** — `gsd-t-calibration-hook.js` records token usage per spawn to `.gsd-t/token-metrics.jsonl` (18-field rows). `gsd-t-token-aggregator.js` aggregates across tasks for the `/gsd-t-metrics` view. Use the native Claude Code `/context` command for live in-session context percentage.
23
22
  **Quality North Star** — projects define a `## Quality North Star` section in CLAUDE.md (1–3 sentences, e.g., "This is a published npm library. Every public API must be intuitive and backward-compatible."). `gsd-t-init` auto-detects preset (library/web-app/cli) from package.json signals; `gsd-t-setup` configures it for existing projects. Subagents read it as a quality lens; absent = silent skip (backward compatible).
@@ -135,7 +134,7 @@ gsd-t model-profile resolve --profile <p> [stage] [--json] # Resolve a profile i
135
134
 
136
135
  **Plan Hardening (M83).** The `plan` phase now runs two blocking gates before execute, so a plan can't ship a dead deliverable: a deterministic **acceptance-traceability gate** (`gsd-t traceability-gate` — every AC must bind to a code path + a killing test; the headline capability needs both impl and test) and an adversarial **pre-mortem** agent (opus, fresh-context, predicts edge-case/NFR/dead-deliverable failures and requires a test for each). The temporal dual of the Red Team — attack the design at plan, not just the code at verify. Origin: a build where the headline capability shipped as dead code and burned 4 verify cycles. See `.gsd-t/contracts/plan-hardening-contract.md`.
137
136
 
138
- **Competition Mode (M82 · automatic since M84).** On upstream, pre-contract phases (`/gsd-t-partition`, `/gsd-t-milestone`, `/gsd-t-discuss`, `/gsd-t-design-decompose`) the workflow **automatically decides** whether to compete: an Opus solution-space probe runs at phase start and, if it finds ≥2 genuinely different viable approaches, fans out 3 parallel candidate producers + a judge to pick the winner — the generative dual of the orthogonal validation triad. No flag needed (the probe is biased toward competing, since a better upstream artifact lowers total downstream cost). Partition's judge is an *objective* file-disjointness oracle; subjective phases use a blind + different-model + rubric judge. Override with `--no-competition` or `--competition N` only on explicit request. See `.gsd-t/contracts/competition-mode-contract.md`.
137
+ **Competition Mode (M82 · automatic since M84).** On upstream, pre-contract phases (`/gsd-t-partition`, `/gsd-t-milestone`, `/gsd-t-design-decompose`) the workflow **automatically decides** whether to compete: an Opus solution-space probe runs at phase start and, if it finds ≥2 genuinely different viable approaches, fans out 3 parallel candidate producers + a judge to pick the winner — the generative dual of the orthogonal validation triad. No flag needed (the probe is biased toward competing, since a better upstream artifact lowers total downstream cost). Partition's judge is an *objective* file-disjointness oracle; subjective phases use a blind + different-model + rubric judge. Override with `--no-competition` or `--competition N` only on explicit request. See `.gsd-t/contracts/competition-mode-contract.md`.
139
138
 
140
139
  `gsd-t parallel` consumes the M44 task-graph (D1) and applies three pre-spawn gates (D4 depgraph validation → D5 file-disjointness → D6 economics) followed by mode-aware headroom/split math. Extends — does not replace — the M40 orchestrator. Contract: `.gsd-t/contracts/wave-join-contract.md` v1.1.0.
141
140
 
@@ -171,8 +170,6 @@ This will replace changed command files, back up your CLAUDE.md if customized, a
171
170
  |---------|---------|------|
172
171
  | `/gsd-t-help` | List all commands with descriptions | Manual |
173
172
  | `/gsd-t-help {cmd}` | Detailed help for specific command | Manual |
174
- | `/gsd-t-prompt` | Help formulate your idea before committing | Manual |
175
- | `/gsd-t-brainstorm` | Creative exploration and idea generation | Manual |
176
173
  | `/gsd-t-prd` | Generate a GSD-T-optimized Product Requirements Document | Manual |
177
174
 
178
175
  ### Project Initialization
@@ -218,7 +215,6 @@ This will replace changed command files, back up your CLAUDE.md if customized, a
218
215
  | `/gsd-t-status` | Cross-domain progress view with token breakdown by domain/task/phase | Manual |
219
216
  | `/gsd-t-resume` | Restore context, continue | Manual |
220
217
  | `/gsd-t-quick` | Fast task with GSD-T guarantees | Manual |
221
- | `/gsd-t-visualize` | Launch browser dashboard — SSE server + React Flow agent visualization | Manual |
222
218
  | `/gsd-t-debug` | Systematic debugging with state | Manual |
223
219
  | `/gsd-t-metrics` | View task telemetry, process ELO, signal distribution, domain health, and cross-project comparison (`--cross-project`) | Manual |
224
220
  | `/gsd-t-health` | Validate .gsd-t/ structure, optionally repair | Manual |
@@ -395,7 +391,7 @@ The session default model (`/model`) is unaffected — profiles govern workflow
395
391
 
396
392
  ## Unattended / Background Runs
397
393
 
398
- For zero-touch overnight or multi-hour runs, use the `/loop` skill with a GSD-T command, or the `/gsd-t-unattended` skill (via the Smart Router). State is written atomically to `.gsd-t/.unattended/state.json` between worker iterations.
394
+ For zero-touch overnight or multi-hour runs, use the `/loop` skill with a GSD-T command. (The `/gsd-t-unattended` relay was retired in M61.)
399
395
 
400
396
  The supervisor halts automatically when: the milestone reaches COMPLETED status, the wall-clock cap expires, `--max-iterations` is reached, safety rails detect a stall or unrecoverable error, or the stop sentinel is touched.
401
397
 
@@ -136,23 +136,29 @@ function checkInvariants(original, rewritten) {
136
136
  return lost;
137
137
  }
138
138
 
139
- // Shortening prose needs no tools. Left able to use them, the rewriter read the
140
- // file paths and commands INSIDE the reply as work to do and went off running
141
- // them — 41 seconds, killed on timeout, empty output and empty stderr, on every
142
- // turn for two days. Forbidding tools returns the same rewrite in about 7
143
- // seconds. The list is explicit rather than a mode flag so a newly added tool
144
- // cannot quietly re-open the same hole.
145
- const NO_TOOLS = [
146
- "Bash", "Read", "Write", "Edit", "NotebookEdit", "Glob", "Grep",
147
- "Task", "Agent", "WebFetch", "WebSearch", "TodoWrite",
148
- ].join(",");
149
-
150
139
  /** Ask a fresh Claude to do the rewrite. */
151
140
  function rewrite(text, cfg) {
152
141
  const prompt = `${RULES}\n\n--- REPLY TO REWRITE ---\n${text}`;
142
+ // `--setting-sources project` is what stops the shortener shortening itself.
143
+ //
144
+ // A child started with the personal settings inherits the very Stop hook that
145
+ // spawned it: it answers in about 4 seconds, its own hook then sees an answer
146
+ // over the 60-word threshold and spawns a THIRD Claude, and the outer call
147
+ // waits ~46s for work it caused — past the 45s limit, so it was killed and
148
+ // returned nothing, every turn since it shipped. Measured: 54.2s/54.5s with
149
+ // the personal settings, 7.9s/6.2s with only the project's.
150
+ //
151
+ // The trigger was always the CHILD'S OWN REPLY crossing 60 words, never the
152
+ // input: a 63-character prompt that produces a long answer is just as slow
153
+ // (57.2s on, 11.7s off).
154
+ //
155
+ // Not `--bare`, the documented skip-hooks flag: it also skips the keychain, so
156
+ // the child returns "Not logged in" in 0.7s. Not `--settings '{}'` either —
157
+ // settings layers merge, so a lower layer cannot remove a higher layer's hook
158
+ // (54.5s/56.1s, unchanged).
153
159
  const run = spawnSync("claude",
154
160
  ["-p", prompt, "--model", cfg.model, "--dangerously-skip-permissions",
155
- "--disallowed-tools", NO_TOOLS],
161
+ "--setting-sources", "project"],
156
162
  { encoding: "utf8", timeout: cfg.timeoutMs, maxBuffer: 8 * 1024 * 1024 });
157
163
 
158
164
  if (run.error) {
package/bin/gsd-t.js CHANGED
@@ -2092,9 +2092,45 @@ function installCommands(isUpdate) {
2092
2092
 
2093
2093
  if (skipped > 0) info(`${skipped} commands unchanged`);
2094
2094
  success(`${gsdtCommands.length} GSD-T commands + ${utilityCommands.length} utilities ${isUpdate ? "updated" : "installed"} → ~/.claude/commands/`);
2095
+
2096
+ removeRetiredCommands(commandFiles);
2097
+
2095
2098
  return { gsdtCommands, utilityCommands };
2096
2099
  }
2097
2100
 
2101
+ /**
2102
+ * Delete GSD-T commands the package no longer ships.
2103
+ *
2104
+ * Installing only ever copied, so a command retired in a past milestone stayed
2105
+ * on disk forever: eleven were still typeable long after the code behind them
2106
+ * was deleted — brainstorm, discuss and prompt retired in M38, the unattended
2107
+ * trio and visualize in M61. A command that still answers is one a person will
2108
+ * reasonably use, and it then fails in confusing ways.
2109
+ *
2110
+ * Only `gsd-t-*.md` files are considered, so a command the user wrote is never
2111
+ * touched. Every removal is NAMED, and anything that cannot be read or deleted
2112
+ * STOPS the install: a leftover command is exactly the failure being fixed, so
2113
+ * reporting a clean install while one remains would restate the bug.
2114
+ */
2115
+ function removeRetiredCommands(shipped) {
2116
+ const shippedSet = new Set(shipped);
2117
+ // No try/catch: an unreadable commands directory means the check cannot run,
2118
+ // and an install that skipped it must not report success.
2119
+ const present = fs.readdirSync(COMMANDS_DIR);
2120
+
2121
+ const retired = present.filter(
2122
+ (f) => f.startsWith("gsd-t-") && f.endsWith(".md") && !shippedSet.has(f)
2123
+ );
2124
+ if (retired.length === 0) return;
2125
+
2126
+ for (const file of retired) {
2127
+ fs.unlinkSync(path.join(COMMANDS_DIR, file));
2128
+ }
2129
+
2130
+ info(`Removed ${retired.length} retired command(s) no longer shipped:`);
2131
+ for (const f of retired) info(` ${f.replace(/\.md$/, "")}`);
2132
+ }
2133
+
2098
2134
  const GSDT_START = "<!-- GSD-T:START";
2099
2135
  const GSDT_END = "<!-- GSD-T:END";
2100
2136
 
@@ -184,6 +184,14 @@ platform behavior, known-good patterns, known failure modes, anything time-varyi
184
184
  assert from memory. Cite what you find (URL + date) per the auto-research rule; a time-varying
185
185
  external fact stated without a source is a guess.
186
186
 
187
+ **Reach for `/last30days <topic>` FIRST, before a plain web search.** It searches where people
188
+ actually report what happened — Reddit, Hacker News, X, YouTube transcripts, GitHub — and ranks by
189
+ what they engaged with, so it surfaces the known failure modes and "we tried this and regretted it"
190
+ threads a web search buries. That is exactly what this stage is asking for, and none of it is in
191
+ the model's training data. It takes about 40 seconds; a plain web search remains the follow-up when
192
+ the answer is a single settled fact it did not return. If the command is not installed, say so in
193
+ one line and fall back to web search — do NOT silently research a thinner way.
194
+
187
195
  **When research contradicts a standing rule (e.g. the common solution uses a fallback, the project
188
196
  bans fallbacks): the user's rule wins, and you name the conflict in ONE line.** Not a debate:
189
197
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "5.11.10",
3
+ "version": "5.11.12",
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",
@@ -214,9 +214,15 @@ function main() {
214
214
  const rewriter = findRewriter(cwd);
215
215
  if (!rewriter) return allow();
216
216
 
217
+ // The rewriter's own warnings go to stderr. Captured into a pipe and never
218
+ // read, they reach nobody — which is why the timeouts stayed invisible even
219
+ // after a loud message was added for them. Letting the child write straight
220
+ // to this process's stderr is what makes a give-up path visible; these paths
221
+ // are approved passes precisely BECAUSE the reader can see them happen.
217
222
  const run = spawnSync(process.execPath,
218
223
  [rewriter, "--text", last.text, "--project", cwd, "--json"],
219
- { encoding: "utf8", timeout: 60000, maxBuffer: 8 * 1024 * 1024 });
224
+ { encoding: "utf8", timeout: 60000, maxBuffer: 8 * 1024 * 1024,
225
+ stdio: ["ignore", "pipe", "inherit"] });
220
226
 
221
227
  if (run.error || !run.stdout) return allow();
222
228
 
@@ -429,7 +429,7 @@ For every load-bearing claim, tag it:
429
429
  - **`[GUESSED:stale]`** — external/time-varying fact that may have changed.
430
430
 
431
431
  A `[GUESSED:*]` claim is then CLASSIFIED — mechanical string-fact filter, three classes:
432
- - **`class: external`** → research agent (`model: "opus"`) writes a `## Verified Facts (auto-research)` block (URL + fetch date); ENFORCE marker `<!-- auto-research-claim: class=external key=<key> status=uncited -->` is written; verify FAILs if it stays `status=uncited` (R-FAIL-1).
432
+ - **`class: external`** → research agent (`model: "opus"`) writes a `## Verified Facts (auto-research)` block (URL + fetch date); ENFORCE marker `<!-- auto-research-claim: class=external key=<key> status=uncited -->` is written; verify FAILs if it stays `status=uncited` (R-FAIL-1). **Try `/last30days <topic>` FIRST, then web search.** It searches where people report what actually happened — Reddit, Hacker News, X, YouTube transcripts, GitHub — ranked by what they engaged with, so it surfaces current behavior, gotchas and failure modes that a web search buries and that no model's training data holds. ~40 seconds. Cite what it returns the same way (URL + date). If it is not installed, SAY so in one line and use web search — never silently research a thinner way.
433
433
  - **`class: internal`** → grep/Read only; escalate to external if grep empty.
434
434
  - **`class: ambiguous`** → LLM judge (`model: "opus"`) decides; uncertain → research (never guess-internal).
435
435
 
@@ -449,6 +449,8 @@ Debug workflow calls `append-cycle` each iteration. When the SAME computed sympt
449
449
  (API behavior, library version, pricing, rate limits, current best-practice), verify-or-flag before
450
450
  asserting. If you lack a fresh source, say so explicitly: *"I believe X, but I do not have a current
451
451
  source — please verify."* Do NOT state an external/time-varying fact as known when it is a guess.
452
+ **`/last30days <topic>` is the first place to look** — it reports what people have actually hit
453
+ recently rather than what was written up, which is usually what the question is really asking.
452
454
  See memory pointer: `feedback_auto_research_external_gaps`.
453
455
 
454
456
  ### Architect's Oversight Doctrine (M101 — governed, enforced)