@tekyzinc/gsd-t 4.13.10 → 4.13.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 +22 -0
- package/README.md +1 -1
- package/bin/gsd-t.js +2 -1
- package/package.json +1 -1
- package/templates/workflows/gsd-t-scan.workflow.js +47 -23
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [4.13.12] - 2026-06-30
|
|
6
|
+
|
|
7
|
+
### Fixed — scan graph probe silently fell back to grep-mode despite a LIVE graph
|
|
8
|
+
|
|
9
|
+
A `/gsd-t-scan` on NiceNote announced `GRAPH-FALLBACK — graph index not available` and ran in grep-mode, even though the dependency graph was live (156 files, compiler-accurate, all verbs + freshness verified working). Root cause, proven by reproducing the probe through a real haiku agent: the scan's `runCli` told a **haiku** agent to "return ONLY the raw JSON line" and then `JSON.parse`'d the free-text reply — haiku wrapped the JSON in a ```` ```json ```` fence, `JSON.parse` threw, the catch returned `graph-unavailable`, and the scan demoted to grep-mode. The graph, CLI, cwd, and bin-presence were all fine. This is the deterministic-orchestration anti-pattern (a reliability-critical gate routed through an LLM's free text).
|
|
10
|
+
|
|
11
|
+
- `templates/workflows/gsd-t-scan.workflow.js`: `runCli` now passes a `schema` (StructuredOutput) so the probe returns structured JSON via the tool layer, never fence-vulnerable prose; resolves project-local bin → global `gsd-t graph` fallback; drops `2>/dev/null` and surfaces `reason`/`via` in the fallback log (parse-fail vs cli-not-found vs cli-error). Mirrors the proven `gsd-t-verify.workflow.js` runCli.
|
|
12
|
+
- `test/m94-d6-scan-consumer.test.js`: source-structural regression test — scan `runCli` MUST use `schema:`, MUST NOT `JSON.parse(result…)`, MUST have a global-bin fallback. (The prior test only simulated recorded envelopes; it never exercised the parsing layer where the bug lived.)
|
|
13
|
+
|
|
14
|
+
The probe stays `model: "haiku"` (a mechanical CLI call) — the schema, not the model tier, is the fix. Suite: 2542/2546 pass; M71 sandbox + M85 tier lints green.
|
|
15
|
+
|
|
16
|
+
## [4.13.11] - 2026-06-29
|
|
17
|
+
|
|
18
|
+
### Fixed — `gsd-t graph body` reachable from the front door (M98 follow-up)
|
|
19
|
+
|
|
20
|
+
M98 shipped the `body` slice logic in the query CLI and wired the Read-intercept hook, but the top-level `gsd-t graph` router in `bin/gsd-t.js` had no `case "body"` — so `gsd-t graph body <fn>` fell through to "Unknown graph subcommand". The headline M98 feature worked via the internal CLI and the hook, but was unreachable from the user-facing `gsd-t graph` command (the M98 test exercised the CLI directly, never the front door).
|
|
21
|
+
|
|
22
|
+
- **`bin/gsd-t.js`** — added `case "body"` to the graph subcommand router (delegates to the D5 query CLI, mirrors `who-calls`/`blast-radius`); added `body` to the usage string.
|
|
23
|
+
- **`test/m94-d5-graph-dispatch.test.js`** — new front-door regression test: `gsd-t graph body` must route to the CLI and emit a `{ ok, verb:"body" }` envelope, never "Unknown graph subcommand".
|
|
24
|
+
|
|
25
|
+
Verified on real binvoice: `gsd-t graph body selectCommentId` now returns the live 43-line slice (compiler-accurate, imports + callers) through the front door. Suite: 2541/2545 pass.
|
|
26
|
+
|
|
5
27
|
## [4.13.10] - 2026-06-29
|
|
6
28
|
|
|
7
29
|
### Added — The graph serves code (function-level slices) + Read-intercept (M98)
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GSD-T: Contract-Driven Development for Claude Code
|
|
2
2
|
|
|
3
|
-
**v4.13.
|
|
3
|
+
**v4.13.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.
|
package/bin/gsd-t.js
CHANGED
|
@@ -3880,10 +3880,11 @@ function doGraph(args) {
|
|
|
3880
3880
|
case "who-imports": { const e = _graphQueryCli(["who-imports", args[1] || ""]); log(JSON.stringify(e, null, 2)); break; }
|
|
3881
3881
|
case "who-calls": { const e = _graphQueryCli(["who-calls", args[1] || ""]); log(JSON.stringify(e, null, 2)); break; }
|
|
3882
3882
|
case "blast-radius": { const e = _graphQueryCli(["blast-radius", args[1] || ""]); log(JSON.stringify(e, null, 2)); break; }
|
|
3883
|
+
case "body": { const e = _graphQueryCli(["body", args[1] || ""]); log(JSON.stringify(e, null, 2)); break; }
|
|
3883
3884
|
case "tasks": doGraphTaskOutput(args[1] || "table"); break;
|
|
3884
3885
|
default:
|
|
3885
3886
|
error(`Unknown graph subcommand: ${sub}`);
|
|
3886
|
-
info("Usage: gsd-t graph [index|status|query|who-imports|who-calls|blast-radius|tasks]");
|
|
3887
|
+
info("Usage: gsd-t graph [index|status|query|who-imports|who-calls|blast-radius|body|tasks]");
|
|
3887
3888
|
info(" gsd-t graph --output json|table (task DAG)");
|
|
3888
3889
|
}
|
|
3889
3890
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "4.13.
|
|
3
|
+
"version": "4.13.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",
|
|
@@ -238,29 +238,53 @@ const GRAPH_SLICE_SCHEMA = {
|
|
|
238
238
|
let structuralSlice = null; // { deadCode, dangling, clusters, coverage, tier } | null
|
|
239
239
|
let graphWiringMode = "pending"; // "wired" | "fallback-announced" | "disabled"
|
|
240
240
|
|
|
241
|
-
// M94-D6: runCli — inline async helper that delegates CLI
|
|
242
|
-
// M81 invariant: NO require/fs/child_process in the orchestrator body
|
|
243
|
-
//
|
|
244
|
-
//
|
|
241
|
+
// M94-D6: runCli — inline async helper that delegates the D5 graph-query CLI to an
|
|
242
|
+
// agent() Bash. M81 invariant: NO require/fs/child_process in the orchestrator body —
|
|
243
|
+
// the agent runs the command; we read back a SCHEMA-VALIDATED envelope.
|
|
244
|
+
//
|
|
245
|
+
// v4.13.12 HARDENING (root cause of the NiceNote 2026-06-29 silent grep-fallback):
|
|
246
|
+
// the old version told a HAIKU agent to "return ONLY the raw JSON line" and then
|
|
247
|
+
// JSON.parse()'d its free-text reply. Haiku wrapped the JSON in a ```json fence →
|
|
248
|
+
// JSON.parse threw → caught → graph-unavailable → grep-mode, even though the graph
|
|
249
|
+
// was live (status returned ok, 156 files, compiler-accurate). Three fixes, mirroring
|
|
250
|
+
// the proven gsd-t-verify.workflow.js runCli:
|
|
251
|
+
// 1. SCHEMA-validated agent output (StructuredOutput) — the model returns structured
|
|
252
|
+
// JSON via the tool layer, never fenced text; no brittle JSON.parse of prose.
|
|
253
|
+
// 2. project-local bin → GLOBAL `gsd-t` fallback (a project without a local bin copy
|
|
254
|
+
// no longer fails the probe — it was hardcoded to `node bin/...cjs`).
|
|
255
|
+
// 3. stderr captured (dropped `2>/dev/null`) and surfaced in `reason` so the fallback
|
|
256
|
+
// log can say WHY (parse-fail vs not-found vs CLI-error), never a bare "unavailable".
|
|
257
|
+
// [RULE] no-graph-baseline-proven-graph-free — called ONLY when graphMode==="wired".
|
|
258
|
+
// [RULE] graph-probe-schema-validated-never-fence-parsed
|
|
259
|
+
const _GRAPH_CLI_ENVELOPE_SCHEMA = {
|
|
260
|
+
type: "object",
|
|
261
|
+
required: ["ok"],
|
|
262
|
+
additionalProperties: true,
|
|
263
|
+
properties: {
|
|
264
|
+
ok: { type: "boolean", description: "true iff the CLI printed a JSON envelope with ok:true" },
|
|
265
|
+
reason: { type: "string", description: "on failure: graph-unavailable / cli-not-found / cli-error / non-json-output, plus any stderr" },
|
|
266
|
+
via: { type: "string", description: "local | global | error" },
|
|
267
|
+
results: { type: "array", items: {}, description: "the verb's results array (dead-code/dangling/cluster/etc.), [] if none" },
|
|
268
|
+
tier: { type: "string", description: "compiler-accurate | tree-sitter-floor | ... when present" },
|
|
269
|
+
coverage: { description: "coverage envelope when the verb returns one" },
|
|
270
|
+
},
|
|
271
|
+
};
|
|
245
272
|
async function runCli(verb, target, label) {
|
|
246
|
-
const targetArg = target ? ` ${
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
} catch (_) {
|
|
262
|
-
return { ok: false, reason: "graph-unavailable" };
|
|
263
|
-
}
|
|
273
|
+
const targetArg = target ? ` '${String(target).replace(/'/g, "'\\''")}'` : "";
|
|
274
|
+
const prompt = [
|
|
275
|
+
`Run the GSD-T graph-query CLI for the project at \`${projectDir}\` and report its result. Steps:`,
|
|
276
|
+
`1. If \`${projectDir}/bin/gsd-t-graph-query-cli.cjs\` exists, run: \`node ${projectDir}/bin/gsd-t-graph-query-cli.cjs ${verb}${targetArg}\` (set via="local"). Otherwise run: \`gsd-t graph ${verb}${targetArg}\` (set via="global"). Use cwd \`${projectDir}\`. Do NOT redirect stderr — capture it.`,
|
|
277
|
+
`2. The command prints ONE JSON envelope to stdout. Parse it. Set ok = (the parsed envelope's "ok" field === true). Copy its "results", "tier", and "coverage" fields through if present.`,
|
|
278
|
+
`3. If the command exits non-zero, prints no JSON, or stdout is not valid JSON: set ok=false and put a short reason in "reason" — "cli-not-found" if the file/binary was missing, else "cli-error", else "non-json-output" — and append the first ~200 chars of stderr.`,
|
|
279
|
+
`Do NOT do any other work. ONLY run this one command and report the structured result.`,
|
|
280
|
+
].join("\n");
|
|
281
|
+
const r = await agent(prompt, {
|
|
282
|
+
label: `graph:${label || verb}`,
|
|
283
|
+
phase: "Graph-Wiring",
|
|
284
|
+
model: "haiku",
|
|
285
|
+
schema: _GRAPH_CLI_ENVELOPE_SCHEMA,
|
|
286
|
+
}).catch((e) => ({ ok: false, reason: `agent-error: ${e && e.message}`, via: "error" }));
|
|
287
|
+
return r || { ok: false, reason: "graph-unavailable", via: "error" };
|
|
264
288
|
}
|
|
265
289
|
|
|
266
290
|
// Preflight: an agent checks branch + whether a prior register exists, via Bash.
|
|
@@ -339,7 +363,7 @@ if (graphMode === "disabled") {
|
|
|
339
363
|
// Graph unavailable — announce fallback, continue with intact grep-mode scan.
|
|
340
364
|
// [RULE] parser-fail-disables-loud-never-silent (from graph-query-cli-contract)
|
|
341
365
|
graphWiringMode = "fallback-announced";
|
|
342
|
-
log(`⚠ GRAPH-FALLBACK (ANNOUNCED): graph
|
|
366
|
+
log(`⚠ GRAPH-FALLBACK (ANNOUNCED): graph status probe returned not-ok [reason=${(statusResult && statusResult.reason) || "graph-unavailable"}, via=${(statusResult && statusResult.via) || "?"}] — scan continues in full grep-mode (today's architecture, intact). Structural findings from LLM reconstruction only. Build the index (gsd-t graph build) to enable graph-wired accuracy.`);
|
|
343
367
|
} else {
|
|
344
368
|
// Step 2: query the structural slice (dead-code + dangling + clusters).
|
|
345
369
|
// These are the findings the deep-finders currently reconstruct by reading files (error-prone);
|