@tekyzinc/gsd-t 5.17.12 → 5.17.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,40 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [5.17.13] - 2026-09-03
6
+
7
+ ### Fixed — the verify gate failed projects for GSD-T's own gaps (TD-395), and a lost finalizer crashed the phase workflow
8
+
9
+ Reported from TimeTracking: verify could not reach Red Team / QA because the gate
10
+ ahead of the triad failed on things the project could not fix. Two of them were ours.
11
+
12
+ - `bin/gsd-t.js`: `gsd-t-logging-envelope-check.cjs` joins `PROJECT_BIN_TOOLS`. The
13
+ verify gate reaches it via `__dirname` inside the project's own `bin/`, so it existed
14
+ on the author's machine and in no project (5th propagation gap of this class).
15
+ - `test/verify-gate-tools-propagated.test.js`: every `__dirname` tool the gate dispatches
16
+ to must be in the propagation set — structural, with a negative case. Closes the class.
17
+ - `bin/gsd-t-graph-use-gate.cjs`: a workflow stamps its WIRED claim under its own name
18
+ (`phase`, `verify`) while its workers' Bash-run queries land under the query CLI's default
19
+ label `cli`, which the gate exempted. TimeTracking's ledger: 302 queries under `cli`,
20
+ gate FAILED as zero. A query from an id with no wiring claim of its own now counts as
21
+ evidence for every claimant whose claim precedes it; a query before the claim is not
22
+ evidence; another claimant's queries are never borrowed. 4 tests.
23
+ - `templates/workflows/gsd-t-verify.workflow.js`: verify stamped its claim at Preflight and
24
+ ran its own gate immediately after — a fresh claim with zero queries, failing by
25
+ construction every run. The stamp now lands after the gate, before the first structural
26
+ query.
27
+ - `templates/workflows/gsd-t-phase.workflow.js`: a finalizer agent lost to an API 529
28
+ resolved to null and the run died with a TypeError at `result.competition = …`. It now
29
+ ends with `status: "failed"` and a resume hint (a halt with a message, not a fallback).
30
+
31
+ Not a GSD-T change: the gate's Playwright step runs `npx playwright test` exactly as the
32
+ project's own `npm test` does; a config that throws without `TEST_DATABASE_URL` must load
33
+ `.env.local` itself.
34
+
35
+ Also in this release: **M115 Test-Plan-First Requirements Interrogation** is DEFINED and
36
+ PARTITIONED (5 domains, 3 risk-first waves) with its A1 blind-replay answer key secured at
37
+ `test/fixtures/m115-blind-replay/`. Nothing of M115 is built yet.
38
+
5
39
  ## [5.17.12] - 2026-09-02
6
40
 
7
41
  ### Fixed — an import written `.js` never resolved to its `.ts` source, so `who-imports` answered "nothing imports this"
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v5.17.12** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v5.17.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.
@@ -94,7 +94,7 @@ function readLedger(files, sinceTs) {
94
94
 
95
95
  const ensure = (id) => {
96
96
  if (!consumers[id]) {
97
- consumers[id] = { consumer: id, queryCount: 0, wiringModes: [], firstWiringTs: null };
97
+ consumers[id] = { consumer: id, queryCount: 0, queryTs: [], wiringModes: [], firstWiringTs: null };
98
98
  }
99
99
  return consumers[id];
100
100
  };
@@ -122,7 +122,9 @@ function readLedger(files, sinceTs) {
122
122
  const kind = String(ev.kind || '');
123
123
 
124
124
  if (kind === EVIDENCE_KIND) {
125
- ensure(id).queryCount++;
125
+ const c = ensure(id);
126
+ c.queryCount++;
127
+ c.queryTs.push(typeof ev.ts === 'string' ? ev.ts : '');
126
128
  } else if (kind === WIRING_KIND) {
127
129
  const c = ensure(id);
128
130
  c.wiringModes.push(String(ev.graphWiringMode || ''));
@@ -143,24 +145,45 @@ function evaluate(consumers) {
143
145
  const violations = [];
144
146
  const checked = [];
145
147
 
148
+ // [RULE] graph-use-attributes-unlabelled-queries-by-time
149
+ // A workflow stamps its WIRED claim under its own name ("phase", "verify", …),
150
+ // but the graph queries its workers run through Bash carry the query CLI's
151
+ // default label ("cli") — nothing in the worker's shell exports
152
+ // GSDT_GRAPH_CONSUMER. TimeTracking (2026-09-03, TD-395): 302 queries under
153
+ // "cli", the three WIRED claims under "phase"/"verify", and the gate FAILED a
154
+ // run that had consulted the graph 302 times — attribution, not absence.
155
+ // So a query logged by an id that made NO wiring claim of its own (cli, a hook)
156
+ // counts as evidence for every claimant whose WIRED claim PRECEDES it. A query
157
+ // before the claim is not evidence: nothing had claimed anything yet.
158
+ const unlabelledQueryTs = [];
159
+ for (const id of Object.keys(consumers)) {
160
+ const c = consumers[id];
161
+ if (c.wiringModes.length === 0) unlabelledQueryTs.push(...(c.queryTs || []));
162
+ }
163
+
146
164
  for (const id of Object.keys(consumers)) {
147
165
  if (NON_CONSUMER_IDS.has(id)) continue;
148
166
  const c = consumers[id];
149
167
  if (c.wiringModes.length === 0) continue; // never declared; nothing claimed, nothing to prove
150
168
 
151
169
  const claimedWired = c.wiringModes.some((m) => m.toLowerCase() === 'wired');
152
- checked.push({ consumer: id, wiringModes: c.wiringModes, queryCount: c.queryCount });
170
+ const since = c.firstWiringTs || '';
171
+ const attributed = unlabelledQueryTs.filter((ts) => ts && ts >= since).length;
172
+ const evidenceCount = c.queryCount + attributed;
173
+ checked.push({ consumer: id, wiringModes: c.wiringModes, queryCount: c.queryCount, attributedQueryCount: attributed });
153
174
 
154
- if (claimedWired && c.queryCount === 0) {
175
+ if (claimedWired && evidenceCount === 0) {
155
176
  violations.push({
156
177
  consumer: id,
157
178
  wiringMode: 'WIRED',
158
179
  queryCount: 0,
180
+ attributedQueryCount: 0,
159
181
  firstWiringTs: c.firstWiringTs,
160
182
  evidence:
161
183
  `consumer "${id}" logged graphWiringMode=WIRED but issued 0 graph queries ` +
162
- `(kind:"query") in this window a WIRED claim with no query evidence means ` +
163
- `the structural question was answered some other way.`,
184
+ `(kind:"query") in this window, and no unlabelled query (cli / hook) was logged after ` +
185
+ `the claim a WIRED claim with no query evidence means the structural question ` +
186
+ `was answered some other way.`,
164
187
  });
165
188
  }
166
189
  }
package/bin/gsd-t.js CHANGED
@@ -3467,6 +3467,11 @@ const PROJECT_BIN_TOOLS = [
3467
3467
  "cli-preflight.cjs", "parallel-cli.cjs", "parallel-cli-tee.cjs",
3468
3468
  "gsd-t-context-brief.cjs",
3469
3469
  "gsd-t-verify-gate.cjs", "gsd-t-verify-gate-judge.cjs",
3470
+ // M100 D3 — trace+audit envelope gate. verify-gate dispatches to it via __dirname,
3471
+ // so a project with the gate but not this file fails `logging-envelope` on every
3472
+ // verify (TimeTracking TD-395, 2026-09-03 — the 5th propagation gap of this class;
3473
+ // test/verify-gate-tools-propagated.test.js now asserts the whole set structurally).
3474
+ "gsd-t-logging-envelope-check.cjs",
3470
3475
  // v5.4.10 — integer-identity primary-key gate. gsd-t-verify-gate.cjs dispatches to
3471
3476
  // it via an absolute path in the Track 2 plan, so a project that has the verify gate
3472
3477
  // but NOT this file gets an ENOENT on every verify. Ships alongside the gate itself.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "5.17.12",
3
+ "version": "5.17.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",
@@ -1320,6 +1320,13 @@ if (!competitionOn) {
1320
1320
  ].filter(Boolean).join("\n"),
1321
1321
  { label: `${phaseName}:finalize`, phase: "Finalize", schema: FINALIZE_SCHEMA, model: "opus" }
1322
1322
  ).catch((e) => ({ status: "failed", artifacts: [], summary: `finalizer error: ${e && e.message}` }));
1323
+ // A finalizer that RESOLVES to nothing (API 529 overload observed 2026-09-02, run
1324
+ // wf_66339f4d-545) used to crash the whole run with a TypeError at
1325
+ // `result.competition = ...` — a stack trace instead of a status. This is a HALT,
1326
+ // not a fallback: the run still ends failed, it just says so in the envelope.
1327
+ if (!result || typeof result !== "object") {
1328
+ result = { status: "failed", artifacts: [], summary: "finalizer returned no result (transient API error or empty agent return) — resume the run with resumeFromRunId; cached stages replay, only finalize re-runs" };
1329
+ }
1323
1330
 
1324
1331
  // Re-validate the FINALIZED partition (Invariant 4). If salvage reintroduced an
1325
1332
  // overlap, the finalized graft is invalid → block completion with a clear reason.
@@ -301,8 +301,6 @@ if (!pre.ok) {
301
301
  return { status: "failed", reason: "preflight-failed", preflight: pre.envelope };
302
302
  }
303
303
  const brief = await generateBrief(projectDir, { kind: "verify", milestone, id: `verify-${(milestone || "m").toLowerCase()}` });
304
- // M99 D2: persist graphWiringMode for the verify consumer. [RULE] wiring-mode-three-states
305
- await persistWiringMode("Preflight");
306
304
 
307
305
  phase("Verify-Gate");
308
306
  const vg = await runVerifyGate(projectDir);
@@ -316,6 +314,14 @@ if (!vg.ok) {
316
314
  }
317
315
  log(`verify-gate green`);
318
316
 
317
+ // M99 D2: persist graphWiringMode for the verify consumer. [RULE] wiring-mode-three-states
318
+ // Stamped AFTER the verify-gate, not before it (TimeTracking TD-395, 2026-09-03): the
319
+ // gate's graph-use check judges every WIRED claim on the queries that FOLLOW it, and
320
+ // verify's first graph query (dead-code, just below) comes after the gate. Stamping at
321
+ // Preflight made every verify run fail its own gate — a fresh claim, zero queries, by
322
+ // construction. Now the claim precedes the structural queries and the NEXT run judges it.
323
+ await persistWiringMode("Verify-Gate");
324
+
319
325
  // ─── M94-D10-T5: Graph Structural Slice — dead-code + dangling (ADDITIVE, announced-degradation) ──
320
326
  // [RULE] qa-verify-use-orphan-dangling-verbs — query dead-code + dangling structurally.
321
327
  // [RULE] verify-integrate-graph-additive-announced-not-hard-fail — PRE-MORTEM Finding 3