@tekyzinc/gsd-t 5.5.10 → 5.5.11

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,22 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [5.5.11] - 2026-07-29
6
+
7
+ ### Fixed — the new style gate would have failed 27 untouched documents in three projects
8
+
9
+ Caught by running the gate live in a downstream project immediately after propagation rather than trusting the "copied 1 bin tool(s)" report. v5.5.10 shipped the gate to all 33 registered projects, but the grandfather list that exempts pre-v1.2.0 documents existed only in the GSD-T repo. binvoice (19 documents), NiceNote (6) and IssueRecorder (2) had none — so the next `gsd-t-verify` run in those projects would have failed on documents nobody touched, written to a then-valid standard.
10
+
11
+ The gate now establishes its own starting line: on the `--dir` path, when the list file is absent and the directory already holds documents, it writes the list once from the existing set and reports `seeded: { reason: "seeded-pre-existing", count, docs }`.
12
+
13
+ This is **not a fallback** — it masks no failure and continues past none; it defines where the gate begins. Three properties keep it honest: written **once** (a self-re-seeding list would silently absolve every newly-drifted document, which is the banned behavior), keyed on the file being absent, and always surfaced naming every document covered. A document created after the seed is gated normally; a single `--doc` call never seeds; an un-writable directory returns exit 64 with the reason rather than a silent mass-pass or mass-fail.
14
+
15
+ - `bin/gsd-t-pseudocode-style.cjs`: `seedGrandfatherList()` + envelope `seeded` field.
16
+ - `test/pseudocode-style-gate.test.js`: 4 new tests (15 → 19) — seed happens, seed never re-runs, `--doc` never seeds, un-writable directory exits 64.
17
+ - `.gsd-t/contracts/pseudocode-source-of-truth-contract.md`: §1.1.5 documents the seed and why it is not a fallback.
18
+
19
+ Verified live: binvoice's 19 documents now report `exitCode 0`, 19 seeded, 0 violations. Suite 3052/0/13-skip.
20
+
5
21
  ## [5.5.10] - 2026-07-29
6
22
 
7
23
  ### Added — PseudoCode style is governed: the flow IS the document
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v5.5.10** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v5.5.11** - 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.
@@ -252,10 +252,56 @@ function loadGrandfathered(dir) {
252
252
  const t = l.trim();
253
253
  if (t && !t.startsWith("#")) out.add(t);
254
254
  }
255
- } catch { /* absent list = nothing grandfathered */ }
255
+ } catch { /* absent list = nothing grandfathered (see seedGrandfatherList) */ }
256
256
  return out;
257
257
  }
258
258
 
259
+ /**
260
+ * First-run seed for a project that already had PseudoCode docs before this gate
261
+ * existed.
262
+ *
263
+ * WHY THIS IS NOT A FALLBACK (No-Fallback-Ever doctrine):
264
+ * this does not continue past a failure or mask one. It establishes the gate's
265
+ * STARTING LINE. The gate governs docs authored under contract §1.1; docs that
266
+ * predate it were written to a different (then-valid) standard, and retroactively
267
+ * failing them would make an unrelated verify run fail in a downstream project for
268
+ * work nobody touched. That is a false failure, not a caught defect.
269
+ *
270
+ * The seed is: WRITTEN ONCE (never rewritten — a list that re-seeded itself would
271
+ * silently absolve every newly-drifted doc, which IS the banned behavior), keyed on
272
+ * the list file being ABSENT, and always SURFACED with reason "seeded-pre-existing"
273
+ * naming every doc it covers. A doc created AFTER the seed is gated normally.
274
+ *
275
+ * @returns {{ seeded: boolean, names: string[], error?: string }}
276
+ */
277
+ function seedGrandfatherList(dir, docBasenames) {
278
+ const listPath = path.join(dir, GRANDFATHER_FILE);
279
+ if (fs.existsSync(listPath)) return { seeded: false, names: [] };
280
+ if (docBasenames.length === 0) return { seeded: false, names: [] };
281
+
282
+ const body = [
283
+ "# Docs that predate the §1.1 flow-line style gate (contract v1.2.0).",
284
+ "# Seeded automatically on this gate's FIRST run in this project, so pre-existing",
285
+ "# docs are not retroactively failed. Each is reported as a logged skip WITH A",
286
+ "# REASON — never a silent pass.",
287
+ "#",
288
+ "# This file is written ONCE and never re-seeded: a doc created after this point",
289
+ "# is gated normally. Removing a name here is how a doc opts INTO the gate —",
290
+ "# convert it to the §1.1 flow style in the same change.",
291
+ ...docBasenames,
292
+ "",
293
+ ].join("\n");
294
+
295
+ try {
296
+ fs.writeFileSync(listPath, body, "utf8");
297
+ } catch (e) {
298
+ // Cannot write (read-only checkout, permissions) — surface it, do NOT
299
+ // silently fail 20 docs and do NOT silently pass them either.
300
+ return { seeded: false, names: [], error: `cannot seed ${GRANDFATHER_FILE}: ${e && e.message}` };
301
+ }
302
+ return { seeded: true, names: docBasenames.slice() };
303
+ }
304
+
259
305
  /**
260
306
  * Run the gate over one doc or a whole directory (§7 discovery glob).
261
307
  * Never throws.
@@ -283,6 +329,17 @@ function run({ doc, dir }) {
283
329
  }
284
330
  }
285
331
 
332
+ // First-run seed: a project whose docs predate this gate gets its starting line
333
+ // established once, surfaced with a reason. Only on the --dir path (the whole-set
334
+ // view); a single --doc call never seeds.
335
+ let seedInfo = null;
336
+ if (dir) {
337
+ seedInfo = seedGrandfatherList(dir, docs.map((d) => path.basename(d)).sort());
338
+ if (seedInfo.error) {
339
+ return { ok: false, exitCode: 64, reason: seedInfo.error, violations: [] };
340
+ }
341
+ }
342
+
286
343
  const results = [];
287
344
  const violations = [];
288
345
  const skips = [];
@@ -295,7 +352,7 @@ function run({ doc, dir }) {
295
352
  if (r.exitCode > worstExit) worstExit = r.exitCode;
296
353
  }
297
354
 
298
- return {
355
+ const envelope = {
299
356
  ok: worstExit === 0,
300
357
  exitCode: worstExit,
301
358
  docsChecked: docs.length,
@@ -303,6 +360,11 @@ function run({ doc, dir }) {
303
360
  skips,
304
361
  violations,
305
362
  };
363
+ if (seedInfo && seedInfo.seeded) {
364
+ // Surfaced, never silent: name the migration and every doc it covers.
365
+ envelope.seeded = { reason: "seeded-pre-existing", count: seedInfo.names.length, docs: seedInfo.names };
366
+ }
367
+ return envelope;
306
368
  }
307
369
 
308
370
  function parseArgs(argv) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "5.5.10",
3
+ "version": "5.5.11",
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",