@tekyzinc/gsd-t 5.17.10 → 5.17.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,63 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [5.17.12] - 2026-09-02
6
+
7
+ ### Fixed — an import written `.js` never resolved to its `.ts` source, so `who-imports` answered "nothing imports this"
8
+
9
+ `who-imports src/content/dom-observer.ts` in binvoice returned 0 importers with
10
+ coverage "complete" while five real importers sat in the edges table. TypeScript
11
+ ESM requires an import to be WRITTEN `./dom-observer.js` even though the file on
12
+ disk is `dom-observer.ts`. The resolver only ever APPENDED extensions
13
+ (`x.js`, `x.js.ts`, …) and never SWAPPED one, so the specifier could not reach
14
+ its source. 817 of binvoice's 2,376 import edges (34%) were unresolvable this way,
15
+ each reading as "safe to delete."
16
+
17
+ - `bin/gsd-t-graph-query-cli.cjs`: after the append pass, try the swap
18
+ (`.js`→`.ts`/`.tsx`, `.mjs`→`.mts`, `.cjs`→`.cts`) on both the relative and
19
+ alias-expanded routes. A real `.js` on disk still wins; a package specifier
20
+ stays as written. `[RULE] query-resolves-js-specifier-to-ts-source`.
21
+ - `test/m114-nested-tsconfig-graph.test.js`: three end-to-end tests that index a
22
+ tiny repo and query it through the real CLI — `.js`→`.ts` resolves, a real
23
+ `.js` beats the swap, an external package is not rewritten.
24
+
25
+ Re-run `gsd-t graph index` is NOT required — resolution happens at query time.
26
+
27
+ ## [5.17.11] - 2026-09-01
28
+
29
+ ### Fixed — every arrow-function export was invisible to the code graph
30
+
31
+ `who-calls logAudit` answered "no callers" for a function called throughout a
32
+ server, while `verifyToken` — three lines away in the same directory — resolved
33
+ fine. The difference was how they were declared:
34
+
35
+ - `export function verifyToken()` → SCIP emits a METHOD descriptor, `verifyToken().`
36
+ - `export const logAudit = async () => {}` → SCIP emits a TERM descriptor, `logAudit.`
37
+
38
+ TypeScript treats an arrow function assigned to a const as a variable, so it gets
39
+ a term. `funcNameFromSymbol` required the `().` shape and discarded everything
40
+ else — on a real server that meant **3,584 term symbols dropped against 1,624
41
+ kept**, more than twice as much data thrown away as used.
42
+
43
+ The references were in the SCIP index the whole time; GSD-T was deleting them on
44
+ read. This was diagnosed in the field as a "scip-typescript coverage limitation" —
45
+ it was not, it was ours.
46
+
47
+ Non-callable terms (`Array.`, imported types) are now admitted and cost nothing:
48
+ a name only resolves when a call site is looking for that exact name, so a type
49
+ reference never matches one. Parameters (`name().(p)`) stay excluded — they end
50
+ in `)`, not `.`.
51
+
52
+ Measured on the same repo, on top of 5.17.10: `server/src/index.ts` went from 30
53
+ to **116** unique resolved symbols, compiler-accurate files 38 → **130**, call
54
+ edges into `server/` 173 → **591**. `logAudit`, `withTransaction` and
55
+ `getAuditContext` all return correct callers, verified against the source.
56
+
57
+ - `bin/gsd-t-scip-reader.cjs`: accept term descriptors alongside method ones
58
+ - `test/m114-nested-tsconfig-graph.test.js`: 4 more tests, mutation-tested
59
+
60
+ **Re-index to pick this up**: `gsd-t graph index`.
61
+
5
62
  ## [5.17.10] - 2026-09-01
6
63
 
7
64
  ### Fixed — the code graph indexed one TypeScript project and called it the whole repo
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v5.17.10** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v5.17.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.
@@ -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
 
@@ -81,15 +81,33 @@ function loadScipProto() {
81
81
  */
82
82
  function funcNameFromSymbol(symbol) {
83
83
  if (!symbol || typeof symbol !== 'string') return null;
84
- // Only function/method occurrences (end with "()."). Parameters are "name().(p)"
85
- // they don't end with "()." so they're excluded.
86
- if (!/\(\)\.$/.test(symbol)) return null;
87
- // The callable name is the last descriptor segment. Top-level functions are
84
+
85
+ // The name is the last descriptor segment. Top-level functions are
88
86
  // ".../`file.ts`/name()."; methods are ".../`file.ts`/Class#method()." — so the
89
87
  // name follows the LAST '/' OR '#', whichever is later (methods key on '#').
90
88
  const cut = Math.max(symbol.lastIndexOf('/'), symbol.lastIndexOf('#'));
91
89
  const descriptor = cut === -1 ? symbol : symbol.slice(cut + 1);
92
- const m = descriptor.match(/^([A-Za-z_$][\w$]*)\(\)\.$/);
90
+
91
+ // TWO callable descriptor shapes, and missing the second one silently halved
92
+ // the graph. [RULE] scip-accepts-term-and-method-descriptors
93
+ //
94
+ // `name().` — a METHOD descriptor: `export function name() {}`
95
+ // `name.` — a TERM descriptor: `export const name = async () => {}`
96
+ //
97
+ // TypeScript treats an arrow function assigned to a const as a VARIABLE, so
98
+ // SCIP emits a term. Requiring "()." therefore discarded every arrow-function
99
+ // export: on a real server that was 3,584 term symbols dropped against 1,624
100
+ // kept, so `who-calls logAudit` answered "no callers" for a function called
101
+ // throughout the codebase — while `verifyToken`, three lines away but written
102
+ // as `export function`, resolved fine.
103
+ //
104
+ // Non-callable terms (`Array.`, an imported type) are admitted here and cost
105
+ // nothing: a name only resolves when a CALL SITE is looking for that exact
106
+ // name, so a type reference never matches one.
107
+ //
108
+ // Parameters (`name().(p)`) stay excluded — they end in `)`, not `.`.
109
+ let m = descriptor.match(/^([A-Za-z_$][\w$]*)\(\)\.$/); // function / method
110
+ if (!m) m = descriptor.match(/^([A-Za-z_$][\w$]*)\.$/); // term (const arrow fn)
93
111
  return m ? m[1] : null;
94
112
  }
95
113
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "5.17.10",
3
+ "version": "5.17.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",