@tekyzinc/gsd-t 5.17.11 → 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 +56 -0
- package/README.md +1 -1
- package/bin/gsd-t-graph-query-cli.cjs +28 -0
- package/bin/gsd-t-graph-use-gate.cjs +29 -6
- package/bin/gsd-t.js +5 -0
- package/package.json +1 -1
- package/templates/workflows/gsd-t-phase.workflow.js +7 -0
- package/templates/workflows/gsd-t-verify.workflow.js +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,62 @@
|
|
|
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
|
+
|
|
39
|
+
## [5.17.12] - 2026-09-02
|
|
40
|
+
|
|
41
|
+
### Fixed — an import written `.js` never resolved to its `.ts` source, so `who-imports` answered "nothing imports this"
|
|
42
|
+
|
|
43
|
+
`who-imports src/content/dom-observer.ts` in binvoice returned 0 importers with
|
|
44
|
+
coverage "complete" while five real importers sat in the edges table. TypeScript
|
|
45
|
+
ESM requires an import to be WRITTEN `./dom-observer.js` even though the file on
|
|
46
|
+
disk is `dom-observer.ts`. The resolver only ever APPENDED extensions
|
|
47
|
+
(`x.js`, `x.js.ts`, …) and never SWAPPED one, so the specifier could not reach
|
|
48
|
+
its source. 817 of binvoice's 2,376 import edges (34%) were unresolvable this way,
|
|
49
|
+
each reading as "safe to delete."
|
|
50
|
+
|
|
51
|
+
- `bin/gsd-t-graph-query-cli.cjs`: after the append pass, try the swap
|
|
52
|
+
(`.js`→`.ts`/`.tsx`, `.mjs`→`.mts`, `.cjs`→`.cts`) on both the relative and
|
|
53
|
+
alias-expanded routes. A real `.js` on disk still wins; a package specifier
|
|
54
|
+
stays as written. `[RULE] query-resolves-js-specifier-to-ts-source`.
|
|
55
|
+
- `test/m114-nested-tsconfig-graph.test.js`: three end-to-end tests that index a
|
|
56
|
+
tiny repo and query it through the real CLI — `.js`→`.ts` resolves, a real
|
|
57
|
+
`.js` beats the swap, an external package is not rewritten.
|
|
58
|
+
|
|
59
|
+
Re-run `gsd-t graph index` is NOT required — resolution happens at query time.
|
|
60
|
+
|
|
5
61
|
## [5.17.11] - 2026-09-01
|
|
6
62
|
|
|
7
63
|
### Fixed — every arrow-function export was invisible to the code graph
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GSD-T: Contract-Driven Development for Claude Code
|
|
2
2
|
|
|
3
|
-
**v5.17.
|
|
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.
|
|
@@ -525,6 +525,25 @@ function loadSqliteStore(dbPath) {
|
|
|
525
525
|
// expanded alias is ALREADY project-relative and must not be — joining it to
|
|
526
526
|
// the importer's directory would produce `src/app/src/lib/db`. So the two
|
|
527
527
|
// take different routes to the same place: add the extension either way.
|
|
528
|
+
// [RULE] query-resolves-js-specifier-to-ts-source
|
|
529
|
+
//
|
|
530
|
+
// binvoice, 2026-09-02: `who-imports src/content/dom-observer.ts` returned 0
|
|
531
|
+
// importers with coverage "complete" while five real importers sat in the
|
|
532
|
+
// edges table. TypeScript ESM requires an import to be WRITTEN `.js` even
|
|
533
|
+
// though the file on disk is `.ts` — so the edge says `./dom-observer.js`
|
|
534
|
+
// and no amount of appending extensions reaches `dom-observer.ts`. It has to
|
|
535
|
+
// SWAP the extension, not append to it. 817 of binvoice's 2,376 import edges
|
|
536
|
+
// (34%) were unresolvable this way, each answering "nothing imports this" —
|
|
537
|
+
// which reads as safe to delete.
|
|
538
|
+
const jsToTsCandidates = (p) => {
|
|
539
|
+
const m = /\.(js|jsx|mjs|cjs)$/.exec(p);
|
|
540
|
+
if (!m) return [];
|
|
541
|
+
const stem = p.slice(0, -m[0].length);
|
|
542
|
+
// .js->.ts/.tsx, .jsx->.tsx, .mjs->.mts, .cjs->.cts — the source files a
|
|
543
|
+
// bundler would have compiled INTO the specifier that was written.
|
|
544
|
+
return [stem + ".ts", stem + ".tsx", stem + ".mts", stem + ".cts"];
|
|
545
|
+
};
|
|
546
|
+
|
|
528
547
|
const resolveDst = (srcFile, dst) => {
|
|
529
548
|
if (typeof dst !== "string" || !dst) return dst;
|
|
530
549
|
|
|
@@ -536,6 +555,10 @@ function loadSqliteStore(dbPath) {
|
|
|
536
555
|
for (const ext of EXTS) {
|
|
537
556
|
if (fileIds.has(base + ext)) return base + ext;
|
|
538
557
|
}
|
|
558
|
+
// An alias-expanded path can carry the same written-.js convention.
|
|
559
|
+
for (const cand of jsToTsCandidates(base)) {
|
|
560
|
+
if (fileIds.has(cand)) return cand;
|
|
561
|
+
}
|
|
539
562
|
return dst; // genuinely external — keep it exactly as written
|
|
540
563
|
}
|
|
541
564
|
|
|
@@ -544,6 +567,11 @@ function loadSqliteStore(dbPath) {
|
|
|
544
567
|
for (const ext of EXTS) {
|
|
545
568
|
if (fileIds.has(base + ext)) return base + ext;
|
|
546
569
|
}
|
|
570
|
+
// TypeScript ESM: the import is written `.js`, the source is `.ts`. Swap,
|
|
571
|
+
// don't append. [RULE] query-resolves-js-specifier-to-ts-source
|
|
572
|
+
for (const cand of jsToTsCandidates(base)) {
|
|
573
|
+
if (fileIds.has(cand)) return cand;
|
|
574
|
+
}
|
|
547
575
|
return base; // no indexed match (external/missing) — keep the resolved path
|
|
548
576
|
};
|
|
549
577
|
|
|
@@ -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)
|
|
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
|
-
|
|
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 &&
|
|
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
|
|
163
|
-
`the
|
|
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.
|
|
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
|