@tekyzinc/gsd-t 5.11.28 → 5.11.30
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 +78 -0
- package/README.md +1 -1
- package/bin/gsd-t.js +180 -0
- package/package.json +2 -2
- package/templates/CLAUDE-global.md +19 -0
- package/templates/workflows/gsd-t-scan.workflow.js +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [5.11.30] - 2026-08-11
|
|
6
|
+
|
|
7
|
+
### Fixed — the scan crashed before any finder ran: `slices is not defined`
|
|
8
|
+
|
|
9
|
+
The Atos scan died after 4 agents (preflight, probe, graph-wiring) with a
|
|
10
|
+
JavaScript reference error. Nothing was written; no finder ever started.
|
|
11
|
+
|
|
12
|
+
618: slices = budgetPlan.slices; // never declared at this scope
|
|
13
|
+
|
|
14
|
+
v5.11.26 added that assignment to a bare name. v5.11.27 then added a
|
|
15
|
+
`const slices` INSIDE a helper function — a different scope entirely, which made
|
|
16
|
+
the name look declared to anyone skimming the file. The workflow sandbox runs in
|
|
17
|
+
strict mode, where assigning to an undeclared name throws.
|
|
18
|
+
|
|
19
|
+
`slices` is now declared where the code that uses it runs, starting as the
|
|
20
|
+
probe's own carve so the budget-failed branch needs no assignment at all.
|
|
21
|
+
|
|
22
|
+
**Nothing caught this, which is the more important half.** `node --check` parses
|
|
23
|
+
an undeclared assignment happily — it is legal syntax, and only strict mode makes
|
|
24
|
+
it an error, at runtime. The sandbox lint checks banned requires and `args`
|
|
25
|
+
handling, not scope. No test executes this path, because the workflow only runs
|
|
26
|
+
against a real project.
|
|
27
|
+
|
|
28
|
+
- `templates/workflows/gsd-t-scan.workflow.js`: `let slices = rawSlices` at the
|
|
29
|
+
scope that runs them.
|
|
30
|
+
- `test/m112-workflow-undeclared-assignment.test.js`: a static check over every
|
|
31
|
+
workflow for an assignment to a name its scope never declares, with a
|
|
32
|
+
function-body map so an `if`/`else` block is not mistaken for a nested scope.
|
|
33
|
+
|
|
34
|
+
The check was itself wrong twice before it worked, and the meta-test is what
|
|
35
|
+
caught it: the first version tested a hand-written sample with the offending line
|
|
36
|
+
at column zero and passed while missing the real bug, which is indented two
|
|
37
|
+
spaces inside an `if`. Verified against the actual shipped file — it reports
|
|
38
|
+
line 618 there and passes the fixed one.
|
|
39
|
+
|
|
40
|
+
## [5.11.29] - 2026-08-11
|
|
41
|
+
|
|
42
|
+
### Fixed — 20 of 27 projects had no usable code graph, and nothing said so
|
|
43
|
+
|
|
44
|
+
A binvoice session reached for the graph, found none, and read an 827-file
|
|
45
|
+
project by grep. `update-all` had reported that project as current for months,
|
|
46
|
+
because it was: every file GSD-T ships was in place. The graph is not a shipped
|
|
47
|
+
file — it is built state, created only when someone runs `gsd-t graph index` by
|
|
48
|
+
hand, and no propagation step creates it.
|
|
49
|
+
|
|
50
|
+
Checking for it exposed a second, larger failure. M99 moved the store from
|
|
51
|
+
`.gsd-t/graph.db` to `.gsd-t/graphDB/graph.db` — it changed where the code LOOKS
|
|
52
|
+
without moving what was already there. 18 projects still held a real, populated
|
|
53
|
+
index at the old path that every tool walked straight past.
|
|
54
|
+
|
|
55
|
+
never built 2 (binvoice, newman)
|
|
56
|
+
at the old path 18 — a full index, invisible to the tooling
|
|
57
|
+
working 7
|
|
58
|
+
|
|
59
|
+
**Absence is now repaired, not reported.** Per David's rule: a missing graph is
|
|
60
|
+
BUILT, a stale one is UPDATED, a misplaced one is MOVED, and grep is reserved
|
|
61
|
+
for content that cannot be indexed at all (`.md`, `.sql`, `.json`, config,
|
|
62
|
+
prose). The prior contract said HALT on an absent graph — correct 20 times here,
|
|
63
|
+
and it would have repaired nothing.
|
|
64
|
+
|
|
65
|
+
The rule now also governs plain conversational sessions. The binvoice failure
|
|
66
|
+
was not a wired command; it was ordinary work, and the contract only ever
|
|
67
|
+
covered `/gsd-t-*` commands.
|
|
68
|
+
|
|
69
|
+
- `bin/gsd-t.js`: `graphState()` tells the two faults apart; `migrateLegacyGraph()`
|
|
70
|
+
moves a pre-M99 store (the resolver's own migration, already written for M99
|
|
71
|
+
and never called on existing projects); `buildGraph()` indexes from scratch and
|
|
72
|
+
verifies a store actually landed rather than trusting the indexer's exit code.
|
|
73
|
+
A failed repair is reported per project and never counted as fixed.
|
|
74
|
+
- `.gsd-t/contracts/graph-consumer-wiring-contract.md`: FAIL-LOUD now repairs
|
|
75
|
+
before halting.
|
|
76
|
+
- `~/.claude/CLAUDE.md` + `templates/CLAUDE-global.md`: the rule reaches every
|
|
77
|
+
session, not only wired commands.
|
|
78
|
+
- `test/m112-graph-health-check.test.js`: 11 regressions.
|
|
79
|
+
|
|
80
|
+
Run once here: 18 stores moved, 2 graphs built (binvoice 639 files/56,822 edges,
|
|
81
|
+
newman 610 files/27,582 edges), all verified answering.
|
|
82
|
+
|
|
5
83
|
## [5.11.28] - 2026-08-11
|
|
6
84
|
|
|
7
85
|
### Fixed — the graph stored the alias edges, then could not find them (two bugs)
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GSD-T: Contract-Driven Development for Claude Code
|
|
2
2
|
|
|
3
|
-
**v5.11.
|
|
3
|
+
**v5.11.30** - 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
|
@@ -2917,10 +2917,129 @@ function createProjectChangelog(projectDir, projectName) {
|
|
|
2917
2917
|
}
|
|
2918
2918
|
}
|
|
2919
2919
|
|
|
2920
|
+
/**
|
|
2921
|
+
* Does this project have a built code graph, and does it have code worth one?
|
|
2922
|
+
*
|
|
2923
|
+
* [RULE] health-reports-missing-graph-never-assumes-built
|
|
2924
|
+
*
|
|
2925
|
+
* binvoice, 2026-08-11: a session reached for the graph, found nothing, and fell
|
|
2926
|
+
* back to grep — in an 827-file project. The tooling was installed and
|
|
2927
|
+
* propagated like everywhere else; the index had simply never been built.
|
|
2928
|
+
* Nothing builds it automatically, so a project has a graph only if someone once
|
|
2929
|
+
* ran `gsd-t graph index` there by hand.
|
|
2930
|
+
*
|
|
2931
|
+
* Nothing ever said so. `update-all` reported the project as current, because it
|
|
2932
|
+
* was — every file it ships was in place. The gap lived in state no propagation
|
|
2933
|
+
* step creates, and stayed invisible until a session hit it mid-task.
|
|
2934
|
+
*
|
|
2935
|
+
* Reported, never auto-built: indexing a large repo is slow, and doing it to 33
|
|
2936
|
+
* of them inside an update would be a surprise nobody asked for.
|
|
2937
|
+
*/
|
|
2938
|
+
function graphState(projectDir) {
|
|
2939
|
+
// Where the store lives is the resolver's answer alone. If it cannot answer,
|
|
2940
|
+
// this check HALTS the caller rather than reporting a project as healthy — a
|
|
2941
|
+
// silent "graph fine" here is exactly the blindness being fixed.
|
|
2942
|
+
const resolver = require("./gsd-t-graph-store-resolver.cjs");
|
|
2943
|
+
const storePath = resolver.resolveStorePath(projectDir);
|
|
2944
|
+
if (storePath && fs.existsSync(storePath)) return { missing: false, files: 0 };
|
|
2945
|
+
|
|
2946
|
+
// A graph at the pre-M99 location (.gsd-t/graph.db) EXISTS — it is just where
|
|
2947
|
+
// the resolver no longer looks. Telling the user to build one would be wrong
|
|
2948
|
+
// twice over: the work is already done, and the real problem (a store the
|
|
2949
|
+
// tooling cannot find) would go unnamed.
|
|
2950
|
+
const legacyPath = resolver.resolveLegacyStorePath(projectDir);
|
|
2951
|
+
if (legacyPath && fs.existsSync(legacyPath)) return { missing: false, files: 0, legacy: true };
|
|
2952
|
+
|
|
2953
|
+
let n = 0;
|
|
2954
|
+
const SKIP = new Set(["node_modules", ".git", ".next", "dist", "build", ".venv", "venv", "out", "coverage"]);
|
|
2955
|
+
const EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
2956
|
+
const walk = (dir, depth) => {
|
|
2957
|
+
if (depth > 6) return;
|
|
2958
|
+
if (n > 400) return; // enough to answer "is this a real codebase?"
|
|
2959
|
+
let entries;
|
|
2960
|
+
try {
|
|
2961
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
2962
|
+
} catch (_e) {
|
|
2963
|
+
// An unreadable subdirectory makes the count a floor, not a lie: the
|
|
2964
|
+
// result is only ever compared against a low threshold, and a miscount
|
|
2965
|
+
// downward can only omit a project from a report, never invent one.
|
|
2966
|
+
return;
|
|
2967
|
+
}
|
|
2968
|
+
for (const e of entries) {
|
|
2969
|
+
if (e.isDirectory()) {
|
|
2970
|
+
if (SKIP.has(e.name)) continue;
|
|
2971
|
+
if (e.name.startsWith(".")) continue;
|
|
2972
|
+
walk(path.join(dir, e.name), depth + 1);
|
|
2973
|
+
continue;
|
|
2974
|
+
}
|
|
2975
|
+
if (EXT.has(path.extname(e.name))) n++;
|
|
2976
|
+
}
|
|
2977
|
+
};
|
|
2978
|
+
walk(projectDir, 0);
|
|
2979
|
+
|
|
2980
|
+
// A project with almost no source has nothing for a graph to map; calling that
|
|
2981
|
+
// "missing" would be noise on every docs-only or config-only repo.
|
|
2982
|
+
return { missing: n >= 25, files: n };
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
/**
|
|
2986
|
+
* Move a graph that sits at the pre-M99 path into the one the tooling reads.
|
|
2987
|
+
*
|
|
2988
|
+
* The store already holds a full index — M99 changed where every tool LOOKS
|
|
2989
|
+
* without moving what was there, so the graph was present and unreachable. The
|
|
2990
|
+
* resolver's own migration does the move, checkpoints the write-ahead log, and
|
|
2991
|
+
* verifies the result is readable.
|
|
2992
|
+
*/
|
|
2993
|
+
function migrateLegacyGraph(projectDir) {
|
|
2994
|
+
try {
|
|
2995
|
+
const r = require("./gsd-t-graph-store-resolver.cjs").migrateGraphStore(projectDir);
|
|
2996
|
+
if (r && r.migrated) return { ok: true };
|
|
2997
|
+
return { ok: false, err: (r && r.reason) || "migration reported no result" };
|
|
2998
|
+
} catch (e) {
|
|
2999
|
+
return { ok: false, err: e.message || String(e) };
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
/**
|
|
3004
|
+
* Build a project's code graph from scratch.
|
|
3005
|
+
*
|
|
3006
|
+
* Slow on a large repo, so the caller announces it before this runs. A failure
|
|
3007
|
+
* is returned, never swallowed: a project left without a graph must say so, so
|
|
3008
|
+
* the next session halts instead of quietly grepping.
|
|
3009
|
+
*/
|
|
3010
|
+
function buildGraph(projectDir) {
|
|
3011
|
+
try {
|
|
3012
|
+
const idx = path.join(__dirname, "gsd-t-graph-index.cjs");
|
|
3013
|
+
const r = require("child_process").spawnSync(process.execPath, [idx], {
|
|
3014
|
+
cwd: projectDir,
|
|
3015
|
+
encoding: "utf8",
|
|
3016
|
+
timeout: 15 * 60 * 1000,
|
|
3017
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3018
|
+
});
|
|
3019
|
+
if (r.error) return { ok: false, err: r.error.message };
|
|
3020
|
+
if (r.status !== 0) {
|
|
3021
|
+
const tail = String(r.stderr || r.stdout || "").trim().split("\n").slice(-2).join(" ");
|
|
3022
|
+
return { ok: false, err: `exit ${r.status}${tail ? ` — ${tail}` : ""}` };
|
|
3023
|
+
}
|
|
3024
|
+
// The indexer reporting success is not proof a store landed. Verify the file
|
|
3025
|
+
// the tooling will actually read.
|
|
3026
|
+
const storePath = require("./gsd-t-graph-store-resolver.cjs").resolveStorePath(projectDir);
|
|
3027
|
+
if (!fs.existsSync(storePath)) return { ok: false, err: "indexer reported success but no store was written" };
|
|
3028
|
+
return { ok: true };
|
|
3029
|
+
} catch (e) {
|
|
3030
|
+
return { ok: false, err: e.message || String(e) };
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
|
|
2920
3034
|
async function checkProjectHealth(projects) {
|
|
2921
3035
|
heading("Project Health");
|
|
2922
3036
|
const playwrightMissing = [];
|
|
2923
3037
|
const swaggerMissing = [];
|
|
3038
|
+
const graphMissing = [];
|
|
3039
|
+
const graphLegacy = [];
|
|
3040
|
+
const graphMigrated = [];
|
|
3041
|
+
const graphBuilt = [];
|
|
3042
|
+
const graphRepairFailed = [];
|
|
2924
3043
|
const playwrightAutoInstalled = [];
|
|
2925
3044
|
const playwrightInstallFailed = [];
|
|
2926
3045
|
|
|
@@ -2929,6 +3048,42 @@ async function checkProjectHealth(projects) {
|
|
|
2929
3048
|
const name = path.basename(projectDir);
|
|
2930
3049
|
if (!hasPlaywright(projectDir)) playwrightMissing.push(name);
|
|
2931
3050
|
if (hasApi(projectDir) && !hasSwagger(projectDir)) swaggerMissing.push(name);
|
|
3051
|
+
const g = graphState(projectDir);
|
|
3052
|
+
if (g.missing) graphMissing.push({ name, dir: projectDir, files: g.files });
|
|
3053
|
+
if (g.legacy) graphLegacy.push({ name, dir: projectDir });
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
// [RULE] graph-missing-is-built-not-reported
|
|
3057
|
+
//
|
|
3058
|
+
// A missing graph is not a status to report — it is work to do. Every session
|
|
3059
|
+
// in a project without one silently falls back to grep, which reads a fraction
|
|
3060
|
+
// of what the graph knows and answers a different question. Reporting it and
|
|
3061
|
+
// moving on leaves that in place until a human notices, which for binvoice
|
|
3062
|
+
// (827 files) meant months.
|
|
3063
|
+
//
|
|
3064
|
+
// Two different faults, two different repairs:
|
|
3065
|
+
//
|
|
3066
|
+
// · at the old path — the store EXISTS and holds a full index. M99 changed
|
|
3067
|
+
// where the tooling looks without moving what was there, so 18 projects
|
|
3068
|
+
// were reading past a perfectly good graph. This is a file move plus a
|
|
3069
|
+
// write-ahead-log checkpoint, and takes no time at all.
|
|
3070
|
+
// · never built — there is nothing to move. Indexing is genuinely slow
|
|
3071
|
+
// on a large repo, so this is announced before it runs rather than
|
|
3072
|
+
// appearing as an unexplained pause.
|
|
3073
|
+
//
|
|
3074
|
+
// A repair that fails is REPORTED and the project is left as it was. It is not
|
|
3075
|
+
// retried differently and never half-applied: a graph that came up short would
|
|
3076
|
+
// answer confidently with partial data, which is worse than not having one.
|
|
3077
|
+
for (const { name, dir } of graphLegacy) {
|
|
3078
|
+
const r = migrateLegacyGraph(dir);
|
|
3079
|
+
if (r.ok) graphMigrated.push(name);
|
|
3080
|
+
else graphRepairFailed.push({ name, what: "move", err: r.err });
|
|
3081
|
+
}
|
|
3082
|
+
for (const { name, dir, files } of graphMissing) {
|
|
3083
|
+
log(` building code graph for ${name} (${files}+ source files) — first build, this takes a while`);
|
|
3084
|
+
const r = buildGraph(dir);
|
|
3085
|
+
if (r.ok) graphBuilt.push(name);
|
|
3086
|
+
else graphRepairFailed.push({ name, what: "build", err: r.err });
|
|
2932
3087
|
}
|
|
2933
3088
|
|
|
2934
3089
|
// M50 D1: auto-install Playwright for any UI project that's missing it.
|
|
@@ -2947,6 +3102,19 @@ async function checkProjectHealth(projects) {
|
|
|
2947
3102
|
}
|
|
2948
3103
|
}
|
|
2949
3104
|
|
|
3105
|
+
if (graphMigrated.length > 0) {
|
|
3106
|
+
success(`Code graph moved to where the tooling reads it: ${graphMigrated.join(", ")}`);
|
|
3107
|
+
}
|
|
3108
|
+
if (graphBuilt.length > 0) {
|
|
3109
|
+
success(`Code graph built: ${graphBuilt.join(", ")}`);
|
|
3110
|
+
}
|
|
3111
|
+
if (graphRepairFailed.length > 0) {
|
|
3112
|
+
for (const f of graphRepairFailed) {
|
|
3113
|
+
warn(` ${f.name} — graph ${f.what} FAILED: ${f.err}`);
|
|
3114
|
+
}
|
|
3115
|
+
info("Those projects have no usable graph. Fix before working in them — a session there cannot answer structural questions.");
|
|
3116
|
+
}
|
|
3117
|
+
|
|
2950
3118
|
if (playwrightMissing.length === 0 && swaggerMissing.length === 0) {
|
|
2951
3119
|
success("All projects have Playwright and Swagger configured");
|
|
2952
3120
|
} else {
|
|
@@ -2978,6 +3146,11 @@ async function checkProjectHealth(projects) {
|
|
|
2978
3146
|
return {
|
|
2979
3147
|
playwrightMissing,
|
|
2980
3148
|
swaggerMissing,
|
|
3149
|
+
graphMissing,
|
|
3150
|
+
graphLegacy,
|
|
3151
|
+
graphMigrated,
|
|
3152
|
+
graphBuilt,
|
|
3153
|
+
graphRepairFailed,
|
|
2981
3154
|
playwrightAutoInstalled,
|
|
2982
3155
|
playwrightInstallFailed,
|
|
2983
3156
|
};
|
|
@@ -3155,6 +3328,7 @@ async function doUpdateAll() {
|
|
|
3155
3328
|
playwrightMissing,
|
|
3156
3329
|
swaggerMissing,
|
|
3157
3330
|
playwrightAutoInstalled,
|
|
3331
|
+
graphMissing,
|
|
3158
3332
|
} = await checkProjectHealth(projects);
|
|
3159
3333
|
showUpdateAllSummary(
|
|
3160
3334
|
projects.length,
|
|
@@ -3163,6 +3337,7 @@ async function doUpdateAll() {
|
|
|
3163
3337
|
swaggerMissing,
|
|
3164
3338
|
syncCount,
|
|
3165
3339
|
playwrightAutoInstalled,
|
|
3340
|
+
graphMissing,
|
|
3166
3341
|
);
|
|
3167
3342
|
}
|
|
3168
3343
|
|
|
@@ -3693,6 +3868,7 @@ function showUpdateAllSummary(
|
|
|
3693
3868
|
swaggerMissing,
|
|
3694
3869
|
syncCount,
|
|
3695
3870
|
playwrightAutoInstalled,
|
|
3871
|
+
graphMissing,
|
|
3696
3872
|
) {
|
|
3697
3873
|
log("");
|
|
3698
3874
|
heading("Update All Complete");
|
|
@@ -3706,6 +3882,9 @@ function showUpdateAllSummary(
|
|
|
3706
3882
|
log(` Auto-installed Playwright in: ${playwrightAutoInstalled.length} project(s)`);
|
|
3707
3883
|
}
|
|
3708
3884
|
if (swaggerMissing.length > 0) log(` Missing Swagger: ${swaggerMissing.length}`);
|
|
3885
|
+
if (Array.isArray(graphMissing) && graphMissing.length > 0) {
|
|
3886
|
+
log(` No code graph: ${graphMissing.length}`);
|
|
3887
|
+
}
|
|
3709
3888
|
if (syncCount > 0) log(` Global rules synced: ${syncCount}`);
|
|
3710
3889
|
log("");
|
|
3711
3890
|
}
|
|
@@ -5336,6 +5515,7 @@ function showHelp() {
|
|
|
5336
5515
|
// ─── Exports (for testing) ───────────────────────────────────────────────────
|
|
5337
5516
|
|
|
5338
5517
|
module.exports = {
|
|
5518
|
+
graphState,
|
|
5339
5519
|
validateProjectName,
|
|
5340
5520
|
applyTokens,
|
|
5341
5521
|
normalizeEol,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "5.11.
|
|
4
|
-
"description": "GSD-T: Contract-Driven Development for Claude Code
|
|
3
|
+
"version": "5.11.30",
|
|
4
|
+
"description": "GSD-T: Contract-Driven Development for Claude Code \u2014 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",
|
|
7
7
|
"repository": {
|
|
@@ -310,6 +310,25 @@ When any GSD-T command creates or modifies an API endpoint:
|
|
|
310
310
|
|
|
311
311
|
This applies during: `gsd-t-execute`, `gsd-t-quick`, `gsd-t-integrate`, `gsd-t-wave`, and any command that touches API code.
|
|
312
312
|
|
|
313
|
+
## Code Graph — build it, never grep around it (MANDATORY)
|
|
314
|
+
|
|
315
|
+
**Read code structure through the graph. If the graph is missing, BUILD it. If it is out of date, UPDATE it. Grep only where the answer cannot be indexed.**
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
NEED A STRUCTURAL ANSWER? (what imports this, who calls this, what breaks if I change it)
|
|
319
|
+
├── Graph present and fresh? → query it
|
|
320
|
+
├── Graph missing? → `gsd-t graph index` — BUILD IT, then query
|
|
321
|
+
├── Graph stale? → re-index the touched set, then query
|
|
322
|
+
├── Graph at the old path? → it EXISTS; move it (`gsd-t graph index`), then query
|
|
323
|
+
└── Build/repair FAILED? → HALT and say so. Never answer the structural question by grep.
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Grep is correct ONLY where the content cannot be indexed** — `.md`, `.sql`, `.json`, `.sh`, config, prose, comments. For anything about code structure, grep is not a weaker answer, it is a **different and wrong one**: it matches text, the question is about relationships.
|
|
327
|
+
|
|
328
|
+
**This governs plain conversational work, not just `/gsd-t-*` commands.** The failure that produced this rule (binvoice, 2026-08-11) was an ordinary session: it reached for the graph, found none, grepped an 827-file project, and nothing objected. Checking the graph's existence before reasoning about code is the first move, not a fallback.
|
|
329
|
+
|
|
330
|
+
**Absence is a repairable condition, not a stop sign.** When this was checked across the machine, 20 of 27 registered projects had no usable graph — 2 never built, 18 holding a real index at a path the tooling stopped reading after the store moved. Every one of those sessions had been grepping. `gsd-t update-all` now repairs both automatically and reports any it could not.
|
|
331
|
+
|
|
313
332
|
## Prime Rule
|
|
314
333
|
KEEP GOING. Only stop for:
|
|
315
334
|
1. Unrecoverable errors after 2 fix attempts (delegate to `gsd-t headless --debug-loop` first — only stop if exit code 4)
|
|
@@ -602,6 +602,21 @@ const budgetPlan = await runCli(
|
|
|
602
602
|
"slice-budget"
|
|
603
603
|
);
|
|
604
604
|
|
|
605
|
+
// What the finders will actually run. Declared HERE, at the scope that uses it.
|
|
606
|
+
//
|
|
607
|
+
// [RULE] slices-declared-at-the-scope-that-runs-them
|
|
608
|
+
//
|
|
609
|
+
// v5.11.26 assigned to a bare `slices` that was never declared anywhere, and
|
|
610
|
+
// v5.11.27 added a `const slices` inside probePlaceholderFaults() — a different
|
|
611
|
+
// scope entirely. The workflow sandbox runs in strict mode, so the assignment
|
|
612
|
+
// below threw `slices is not defined` and killed the Atos scan after 4 agents,
|
|
613
|
+
// before a single finder ran. Nothing had checked it: `node --check` parses an
|
|
614
|
+
// undeclared assignment happily, and no test executed this path.
|
|
615
|
+
//
|
|
616
|
+
// It starts as the probe's own slices, so the failure branch below needs no
|
|
617
|
+
// assignment — an unmeasured plan still runs what the probe carved.
|
|
618
|
+
let slices = rawSlices;
|
|
619
|
+
|
|
605
620
|
if (budgetPlan && budgetPlan.ok && Array.isArray(budgetPlan.slices) && budgetPlan.slices.length) {
|
|
606
621
|
const a = budgetPlan.after || {};
|
|
607
622
|
if (budgetPlan.slices.length > rawSlices.length) {
|