@tekyzinc/gsd-t 5.11.11 → 5.11.13

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,69 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [5.11.13] - 2026-08-09
6
+
7
+ ### Fixed — the reply shortener discarded 4 of every 6 rewrites
8
+
9
+ A keyword check counted question marks, file paths and numbers, and threw the
10
+ whole rewrite away if a count dropped. Almost every rejection was the same
11
+ thing: the writer had asked *himself* a question ("Now the proof: does it
12
+ fire?"), the rewrite correctly cut it as narration, and the check saw a question
13
+ disappear. So a working shortener never once delivered.
14
+
15
+ Counting punctuation cannot tell an ask from thinking out loud. A reader can.
16
+ The same model now reads its own short version back against two questions — is
17
+ this only what he needs, and is it as short as his rules demand — and **fixes**
18
+ it. The reviewer returns text, never a verdict, so nothing is ever discarded. A
19
+ failed review keeps the first pass's rewrite rather than losing it.
20
+
21
+ Both passes now carry the relevance rule: keep only what changes what he
22
+ decides, does next, or now knows.
23
+
24
+ Measured on the reply that failed 4 of 6 before: **6 of 6 delivered, zero
25
+ discarded, 236 words down to 75-158.** Two Sonnet calls, 12-45s.
26
+
27
+ - `bin/gsd-t-concise-rewrite.cjs`: the check is gone; a review pass replaces it
28
+ - `test/m107-concise-rewrite.test.js`: 6 tests, including that the check cannot come back
29
+
30
+ ## [5.11.12] - 2026-08-09
31
+
32
+ ### Fixed — a retired command stayed typeable forever
33
+
34
+ Installing only ever copied, so a command retired in a past milestone never left
35
+ the machine. Eleven were still typeable long after the code behind them was
36
+ deleted — brainstorm, discuss and prompt (M38), the unattended trio and
37
+ visualize (M61). A command that still answers is one a person will reasonably
38
+ use; this surfaced when `/gsd-t-brainstorm` was treated as live and turned out
39
+ to have no source at all.
40
+
41
+ Install now deletes GSD-T commands the package no longer ships and NAMES each
42
+ one. Only `gsd-t-*.md` is considered, so a command you wrote is never touched.
43
+ An unreadable commands directory stops the install rather than reporting a clean
44
+ pass over a check that never ran.
45
+
46
+ README advertised five commands that do not exist while `help.md` correctly
47
+ called them retired — the two disagreed, and the README is what a reader
48
+ believes.
49
+
50
+ ### Changed — /last30days is the first stop for an outside fact
51
+
52
+ Wired into the external-fact rule, the conversation-scope rule, and the
53
+ architect's research step. It searches where people report what actually
54
+ happened — Reddit, Hacker News, X, YouTube transcripts, GitHub — ranked by what
55
+ they engaged with, which is what those stages are asking for and what no
56
+ training data holds. About 40 seconds; web search remains the follow-up. Not
57
+ installed means SAY so in one line and use web search — never silently research
58
+ a thinner way.
59
+
60
+ Install it with `/plugin marketplace add mvanhorn/last30days-skill` then
61
+ `/plugin install last30days`.
62
+
63
+ - `bin/gsd-t.js`: retired commands are removed and named
64
+ - `README.md`: five dead command rows removed
65
+ - `commands/gsd-t-architect.md`, `templates/CLAUDE-global.md`: the research wiring
66
+ - `test/m112-retired-commands.test.js`: 5 tests, including that the README advertises nothing it does not ship
67
+
5
68
  ## [5.11.11] - 2026-08-09
6
69
 
7
70
  ### Fixed — the reply shortener was shortening itself
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v5.11.11** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v5.11.13** - 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
 
@@ -59,16 +59,24 @@ Rewrite the reply below following these rules exactly:
59
59
  answering a direct question about that. He asks when he wants it.
60
60
  4. NO JARGON. Plain words. If a technical term is genuinely needed, put the
61
61
  plain meaning first and the term in brackets after it.
62
- 5. CUT ANYTHING NOT ASKED FOR.
62
+ 5. KEEP ONLY WHAT IS RELEVANT TO HIM. Ask of every sentence: does this change
63
+ what he decides, what he does next, or what he now knows? If not, cut it.
64
+ Work the writer did, steps taken, what was checked, what was ruled out — all
65
+ of that is the writer's business, not his, unless he asked.
63
66
  6. Prefer a short list or a small table over a paragraph.
64
67
 
65
68
  KEEP THESE. They are not optional, and dropping any one of them means the
66
69
  rewrite is rejected and thrown away:
67
70
 
68
71
  - The first line, if it is a dated status banner.
69
- - EVERY question being asked of the reader. If the reply ends by asking him
70
- something, that question MUST appear in your rewrite, as its own line, at
71
- the end. This is the single most common way a rewrite is rejected.
72
+ - EVERY question being asked OF THE READER one he is meant to answer. If the
73
+ reply ends by asking him something, that question MUST appear in your rewrite,
74
+ as its own line, at the end. This is the single most common way a rewrite is
75
+ rejected.
76
+ A question the writer asks HIMSELF is not one of these. "Is that the cause?",
77
+ "Now the proof: does the hook fire?", "So what is slow here?" are thinking out
78
+ loud — cut them like any other narration. The test is simple: would he type an
79
+ answer to it? If not, it is not a question.
72
80
  - Any warning, failure, or thing that went wrong.
73
81
  - File paths and links, exactly as written.
74
82
  - Code blocks, exactly as written.
@@ -99,46 +107,46 @@ function wordCount(s) {
99
107
  }
100
108
 
101
109
  /**
102
- * Facts that must survive the rewrite. If any disappears, the rewrite is
103
- * rejected and the original is returned — a rewrite that drops a warning or a
104
- * question is worse than a long reply.
110
+ * The second pass the rewrite reviewed before it is delivered.
111
+ *
112
+ * A keyword check used to sit here: it counted question marks, file paths and
113
+ * numbers, and threw the whole rewrite away if a count dropped. It discarded
114
+ * 4 of every 6 rewrites, almost always because the writer had asked HIMSELF a
115
+ * question ("Now the proof: does it fire?") which the rewrite correctly cut as
116
+ * narration. Counting punctuation cannot tell an ask from thinking out loud.
117
+ *
118
+ * A reader can. So the same model that wrote the short version now reads it
119
+ * back against one question — is this what David needs, and is it as short as
120
+ * his rules demand — and fixes it. The reviewer returns text, never a verdict,
121
+ * so there is no path on which the work is discarded.
105
122
  */
106
- function extractInvariants(text) {
107
- return {
108
- questions: (text.match(/[^.!?\n]*\?/g) || []).map((q) => q.trim()).filter((q) => q.length > 10),
109
- numbers: text.match(/\b\d[\d,._]*\b/g) || [],
110
- paths: text.match(/[\w./-]+\.(?:js|cjs|mjs|ts|tsx|json|md|py|sh)\b/g) || [],
111
- codeBlocks: (text.match(/```/g) || []).length / 2,
112
- };
113
- }
123
+ const REVIEW = `You are checking a shortened reply before it reaches David.
114
124
 
115
- function checkInvariants(original, rewritten) {
116
- const a = extractInvariants(original);
117
- const b = extractInvariants(rewritten);
118
- const lost = [];
125
+ He is a slow reader. Every extra line costs him real time.
119
126
 
120
- if (a.questions.length > 0 && b.questions.length === 0) {
121
- lost.push("a question to the reader was dropped");
122
- }
123
- const lostPaths = a.paths.filter((p) => !rewritten.includes(p));
124
- if (lostPaths.length > 0 && lostPaths.length === a.paths.length && a.paths.length > 0) {
125
- lost.push("every file path was dropped");
126
- }
127
- if (a.codeBlocks > 0 && b.codeBlocks < a.codeBlocks) {
128
- lost.push("a code block was dropped");
129
- }
130
- // A number appearing in the rewrite that was never in the original means
131
- // something was invented.
132
- const invented = b.numbers.filter((n) => n.length > 2 && !a.numbers.includes(n));
133
- if (invented.length > 0) {
134
- lost.push(`a number appeared that was not in the original: ${invented[0]}`);
135
- }
136
- return lost;
137
- }
127
+ Two questions, both about the SHORT version:
138
128
 
139
- /** Ask a fresh Claude to do the rewrite. */
140
- function rewrite(text, cfg) {
141
- const prompt = `${RULES}\n\n--- REPLY TO REWRITE ---\n${text}`;
129
+ 1. Is this ONLY what he needs? Cut anything that does not change what he
130
+ decides, what he does next, or what he now knows. The work someone did,
131
+ steps taken, what was checked, what was ruled out — his business only if he
132
+ asked.
133
+
134
+ 2. Is it truly concise by his rules? Answer first, nothing before it. No
135
+ preamble, no backstory, no jargon standing in for a plain word. Lists and
136
+ small tables over paragraphs.
137
+
138
+ Then check nothing was lost that he needs:
139
+ - a question he is meant to ANSWER must still be there, as its own line at the
140
+ end. A question the writer asked himself is narration — it should be gone.
141
+ - warnings, failures, and things that went wrong stay.
142
+ - file paths, links, code blocks and specific numbers stay exactly as written.
143
+ - no fact, number or name may change, and nothing may be added.
144
+
145
+ Return the final reply and nothing else. If it is already right, return it
146
+ unchanged. Never return commentary, never return an empty response.`;
147
+
148
+ /** One call to a fresh Claude. Used by both passes. */
149
+ function askClaude(prompt, cfg) {
142
150
  // `--setting-sources project` is what stops the shortener shortening itself.
143
151
  //
144
152
  // A child started with the personal settings inherits the very Stop hook that
@@ -181,6 +189,25 @@ function rewrite(text, cfg) {
181
189
  return { ok: true, text: out };
182
190
  }
183
191
 
192
+ /** Pass 1 — shorten it. */
193
+ function rewrite(text, cfg) {
194
+ return askClaude(`${RULES}\n\n--- REPLY TO REWRITE ---\n${text}`, cfg);
195
+ }
196
+
197
+ /**
198
+ * Pass 2 — read the short version back and fix what pass 1 got wrong.
199
+ *
200
+ * Returns text, never a verdict, so the work is never discarded. If the review
201
+ * itself fails, pass 1's rewrite stands: it was already an improvement, and
202
+ * losing it because a second opinion did not arrive would be the old bug in a
203
+ * new place.
204
+ */
205
+ function review(original, shortened, cfg) {
206
+ const prompt = `${REVIEW}\n\n--- WHAT HE ORIGINALLY WROTE (for reference only) ---\n${original}\n\n--- THE SHORT VERSION TO CHECK AND RETURN ---\n${shortened}`;
207
+ const r = askClaude(prompt, cfg);
208
+ return r.ok ? r.text : shortened;
209
+ }
210
+
184
211
  function parseArgs(argv) {
185
212
  const args = { project: process.cwd() };
186
213
  for (let i = 2; i < argv.length; i++) {
@@ -231,19 +258,14 @@ function main() {
231
258
  }, args.json);
232
259
  }
233
260
 
234
- const lost = checkInvariants(text, r.text);
235
- if (lost.length > 0) {
236
- emit({
237
- ok: false, exitCode: EXIT_FAILED, text,
238
- error: `the rewrite lost something: ${lost.join("; ")}`,
239
- note: "Rewrite rejected — this is the original, unchanged.",
240
- words: before,
241
- }, args.json);
242
- }
261
+ // Second pass: the same model reads its own short version back, against the
262
+ // only two questions that matter — is this what David needs, and is it as
263
+ // short as his rules demand. It returns text, so nothing is ever discarded.
264
+ const finalText = review(text, r.text, cfg);
243
265
 
244
- const after = wordCount(r.text);
266
+ const after = wordCount(finalText);
245
267
  emit({
246
- ok: true, exitCode: EXIT_OK, text: r.text,
268
+ ok: true, exitCode: EXIT_OK, text: finalText,
247
269
  words: before, wordsAfter: after,
248
270
  saved: before - after,
249
271
  }, args.json);
@@ -251,4 +273,4 @@ function main() {
251
273
 
252
274
  if (require.main === module) main();
253
275
 
254
- module.exports = { wordCount, extractInvariants, checkInvariants, readConfig, RULES };
276
+ module.exports = { wordCount, readConfig, rewrite, review, askClaude, RULES, REVIEW };
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.11",
3
+ "version": "5.11.13",
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",
@@ -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)