@tekyzinc/gsd-t 4.19.14 → 4.20.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,39 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [4.20.11] - 2026-07-12
6
+
7
+ ### Added — M101: Architect's Oversight Doctrine
8
+
9
+ Fills GSD-T's empty architect seat. Every existing quality gate (Red Team, QA, code-review, pre-mortem) asks "is this correct?" — none asked "is this the smartest, simplest design given what already exists?" The result was the wrong thing built correctly, tested thoroughly, and shipped (origin: a real waste where a whole-page scan re-derived a value already stored locally, invisible under jargon). Now every build runs a Six-Stage Pass before code: Objective → Conflict → Reuse (process AND output, queried against the code graph) → Simplicity → Reuse-forecast → Risk, each answered with evidence not conviction. Three-layer enforcement, sibling of the M90 Unproven-Assumption Doctrine.
10
+
11
+ - `templates/CLAUDE-global.md` + `~/.claude/CLAUDE.md`: the doctrine (definition layer) — Six-Stage Pass, reuse logic (HIGH/LOW forecast, extract-don't-mutate, graph-registered reuse-candidate links to prevent silent duplicate sprawl), plain-English proof, jargonless output co-equal with brevity (absorbs backlog #47).
12
+ - `~/.claude/scripts/gsd-t-architect-oversight-guard.js`: PreToolUse Write|Edit reminder hook (trigger layer) — one line at the build moment, fail-open, code-only (silent on prose/pseudocode/docs/non-project). Wired into settings.json.
13
+ - `templates/workflows/gsd-t-phase.workflow.js`: injects the Six-Stage directive into plan/milestone phases (execution layer; `[RULE] phase-workflow-injects-architect-pass`, enforced by the existing guard-map gate).
14
+ - `.gsd-t/contracts/architects-oversight-contract.md` v1.0.0 STABLE; `.gsd-t/pseudocode/PseudoCode-ArchitectsOversight.md` (self-obedience, plain-English house style).
15
+ - `scripts/gsd-t-auto-route.js`: sharpened READER_CONTRACT jargon rule + 2 worked examples (backlog #47).
16
+ - `test/m101-architect-oversight-hook.test.js`: 9 tests (fires on code, silent on prose, fails open on garbage).
17
+
18
+ Follow-on (recorded, not built): a dedicated verify agent for pseudocode-completeness / reuse-evidence / no-silent-twin checks. The existing guard-map gate already enforces the `[RULE]` marker.
19
+
20
+ ## [4.20.10] - 2026-07-08
21
+
22
+ ### Added — M100: Universal Trace + Audit Logging (framework defaults)
23
+
24
+ Trace + audit logging are now GSD-T framework defaults — every new project is born with a toggleable capture-everything trace stream (PII-barred; opt-out-able for stateless CLIs/libraries) and an immutable, admin-queryable audit stream (opt-out-able), enforced by a structural verify gate. Trace and audit are two DISTINCT streams that never collapse (the two machinery domains share no file, mechanizing the invariant by construction). Piloted end-to-end into greenfield UMI-Automation.
25
+
26
+ - 2 primary contracts + 3 support contracts + 2 PseudoCode behavior maps.
27
+ - `bin/gsd-t-logging-scaffolder.cjs` — storage scaffolder with a human-approval PAUSE (never silently picks a backend).
28
+ - `bin/gsd-t-logging-envelope-check.cjs` — structural verify gate (per-record + per-project discovery incl. SQLite, PII bar, no-collapse, presence-vs-null, trace+audit opt-out).
29
+ - `templates/logging/{trace,audit}-module.template.ts` + `bin/gsd-t-{trace,audit}-distill.cjs`; audit = real SQLite, append-only triggers + sentinel + self-heal, GSD-T-independent admin query.
30
+ - `bin/gsd-t-migrate-logging.cjs` + `commands/gsd-t-migrate-logging.md` + 2 CLAUDE.md hard rules + a symmetric trace opt-out (`.gsd-t/trace-optout.json`); GSD-T self-opts-out of both.
31
+
32
+ ### Fixed — update banner corrupted machine JSON stdout
33
+
34
+ The "Update available" banner wrote to stdout after a command's JSON envelope — breaking JSON.parse consumers of `graph body` / `graph --output json`. Moved to stderr.
35
+
36
+ **Known limitation (documented):** audit immutability is trigger-based defense-in-depth, NOT cryptographic tamper-proofing against a hostile process with direct .db-file write access (a fundamental SQLite limit). Tamper-evidence (hash-chain) is backlog #48.
37
+
5
38
  ## [4.19.14] - 2026-07-07
6
39
 
7
40
  ### Changed — `/gsd-t-stories`: pagination, test-case coloring, in-image diagram titles
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v4.19.14** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v4.20.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.
@@ -24,6 +24,7 @@
24
24
  **Design Brief Artifact** — during partition, UI/frontend projects (React, Vue, Svelte, Flutter, Tailwind) automatically get `.gsd-t/contracts/design-brief.md` with color palette, typography, spacing system, component patterns, and tone/voice. Non-UI projects skip silently. User-customized briefs are preserved. Referenced in plan phase for visual consistency.
25
25
  **Design Verification Agent** — after QA passes on design-to-code projects, a dedicated verification agent opens a browser with both the built frontend AND the original design (Figma page, design image, or MCP screenshot) side-by-side for direct visual comparison. Produces a structured element-by-element comparison table (30+ rows) with specific design values vs. implementation values and MATCH/DEVIATION verdicts. An artifact gate enforces that the comparison table exists — missing it blocks completion. Separation of concerns: coding agents code, verification agents verify. Wired into execute (Step 5.25) and quick (Step 5.25). Only fires when `.gsd-t/contracts/design-contract.md` exists — non-design projects are unaffected.
26
26
  **Exploratory Testing** — after scripted tests pass, if Playwright MCP is registered in Claude Code settings, QA agents get 3 minutes and Red Team gets 5 minutes of interactive browser exploration. All findings tagged `[EXPLORATORY]` and tracked separately in QA calibration. Silent skip when Playwright MCP absent. Wired into execute, quick, integrate, and debug.
27
+ **Universal Trace + Audit Logging (M100)** — every project gets two logging streams by default, each a default for EVERY project EXCEPT explicit opt-out: **trace** (transient, PII-barred debug signal — a stateless CLI/library with no runtime data-flow may opt out via `.gsd-t/trace-optout.json`) and **audit** (durable, append-only, admin-queryable accountability record — opt out via `.gsd-t/audit-optout.json`), mirroring each other's opt-out convention. Storage is stack-adaptive and human-approval-gated (`bin/gsd-t-logging-scaffolder.cjs` — never silently picks a backend); `gsd-t-verify` enforces both envelopes structurally and blocks any collapse of the two streams into one. Brownfield projects get `gsd-t migrate-logging` (additive/non-destructive scaffold-in). Contracts: `.gsd-t/contracts/trace-logging-contract.md`, `audit-logging-contract.md`, `logging-schema-distillation-contract.md`, `logging-scaffold-seam-contract.md`.
27
28
 
28
29
  ---
29
30
 
@@ -228,6 +229,7 @@ This will replace changed command files, back up your CLAUDE.md if customized, a
228
229
  | `/gsd-t-design-audit` | Compare built screen against Figma design — structured deviation report | Manual |
229
230
  | `/gsd-t-design-build` | Build from design contracts with two-terminal review (Term 1 builder) | Manual |
230
231
  | `/gsd-t-design-review` | Independent review agent for design build (Term 2 reviewer) | Auto |
232
+ | `gsd-t migrate-logging <projectDir>` | Brownfield: scaffold trace + audit logging into an existing project, additively (M100) | Manual |
231
233
 
232
234
  ### Backlog Management
233
235
 
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * GSD-T Audit-Half Action Distiller (M100-D4-T2)
6
+ *
7
+ * Distills the concrete per-project audit ACTION set from the project's own
8
+ * plan/integration points — NEVER confabulates an example
9
+ * (`feedback_no_confabulated_examples`). An unstated action is a QUESTION,
10
+ * not an invented value. Ships the opt-out record writer for the audit
11
+ * default-except-opt-out convention.
12
+ *
13
+ * Contract: .gsd-t/contracts/logging-schema-distillation-contract.md
14
+ * Consumed contract: .gsd-t/contracts/audit-logging-contract.md §opt-out-record.
15
+ *
16
+ * NEVER shares a file with the trace distiller (bin/gsd-t-trace-distill.cjs,
17
+ * owned by d2) — mechanizes no-collapse by construction (this file's own
18
+ * path is distinct from that path).
19
+ *
20
+ * Exports:
21
+ * distillAuditActions(planPath) -> { actions: Array<{ action, target, source }> }
22
+ * writeOptOut(projectDir, reason) -> the written opt-out record
23
+ * readOptOut(projectDir) -> the opt-out record, or null if absent/invalid
24
+ */
25
+
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+
29
+ // ── §opt-out-record — pinned shape (audit-logging-contract.md §opt-out-record) ──
30
+
31
+ const OPTOUT_REL_PATH = path.join('.gsd-t', 'audit-optout.json');
32
+
33
+ /**
34
+ * Writes the canonical opt-out record to `<projectDir>/.gsd-t/audit-optout.json`.
35
+ * Shape is FIXED by the contract — do not invent alternate keys/paths.
36
+ */
37
+ function writeOptOut(projectDir, reason) {
38
+ if (typeof reason !== 'string' || reason.trim().length === 0) {
39
+ throw new Error('writeOptOut: reason must be a non-empty string');
40
+ }
41
+ const record = { auditOptOut: true, reason };
42
+ const dir = path.join(projectDir, '.gsd-t');
43
+ fs.mkdirSync(dir, { recursive: true });
44
+ const filePath = path.join(projectDir, OPTOUT_REL_PATH);
45
+ fs.writeFileSync(filePath, JSON.stringify(record, null, 2) + '\n', 'utf8');
46
+ return record;
47
+ }
48
+
49
+ /**
50
+ * Reads + validates the opt-out record. Returns null if the file is absent,
51
+ * unparseable, or fails either field rule (fail-closed — an unrecognized
52
+ * record is treated as absent, never as an implicit pass).
53
+ */
54
+ function readOptOut(projectDir) {
55
+ const filePath = path.join(projectDir, OPTOUT_REL_PATH);
56
+ let parsed;
57
+ try {
58
+ if (!fs.existsSync(filePath)) return null;
59
+ parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
60
+ } catch (_err) {
61
+ return null;
62
+ }
63
+ if (!parsed || typeof parsed !== 'object') return null;
64
+ if (parsed.auditOptOut !== true) return null;
65
+ if (typeof parsed.reason !== 'string' || parsed.reason.trim().length === 0) return null;
66
+ return parsed;
67
+ }
68
+
69
+ // ── Distillation — grounded extraction, never confabulated ─────────────────
70
+
71
+ // Structural cues that mark a plan line as an accountability-worthy human
72
+ // decision point (approve/reject/edit a record with a before/after state).
73
+ // This is a STRUCTURAL grep over the plan's own text — it extracts what the
74
+ // plan says, it does not invent a domain-specific action.
75
+ // Note: bare noun 'approval' is intentionally excluded — the approve[sd]?
76
+ // branch already covers the decision verb, and keeping the action set
77
+ // verb-consistent avoids emitting action:'approval' alongside 'approve'/
78
+ // 'approved' for the same decision (code-review nit).
79
+ const DECISION_VERB_RE = /\b(approve[sd]?|reject[sd]?|edit(?:ed|s)?|revis(?:e|ed|es)|review(?:ed|s)?|impersonat(?:e|ed|es|ion)|refund(?:ed|s)?|delet(?:e|ed|es)|role[- ]?chang(?:e|ed|es)|export(?:ed|s)?)\b/i;
80
+
81
+ // Lines that look like a markdown heading or list item naming a step.
82
+ const PLAN_LINE_RE = /^\s*(?:[-*+]\s+|#{1,6}\s+|\d+[.)]\s+)(.*\S)\s*$/;
83
+
84
+ /**
85
+ * Extracts a target noun phrase near the matched verb — best-effort, purely
86
+ * structural (adjacent capitalized/quoted token), never a fabricated value.
87
+ * Falls back to the generic 'record' target only when no more specific noun
88
+ * is structurally recoverable from the line itself.
89
+ */
90
+ function _extractTarget(line) {
91
+ const quoted = line.match(/"([^"]+)"|'([^']+)'|`([^`]+)`/);
92
+ if (quoted) return quoted[1] || quoted[2] || quoted[3];
93
+ const capitalized = line.match(/\b([A-Z][a-zA-Z]*(?:\s[A-Z][a-zA-Z]*)*)\b/);
94
+ if (capitalized) return capitalized[1];
95
+ return 'record';
96
+ }
97
+
98
+ /**
99
+ * distillAuditActions(planPath) -> { actions: Array<{ action, target, source }> }
100
+ *
101
+ * Reads the project's own plan file and extracts accountability-worthy
102
+ * actions GROUNDED in the plan's actual text (source = the exact matched
103
+ * line, for grep-traceability back to the plan). Returns an EMPTY array
104
+ * (never an error, never a confabulated placeholder) when the plan contains
105
+ * no accountability-worthy actions — the empty-input pole is a legitimate,
106
+ * non-error outcome.
107
+ */
108
+ function distillAuditActions(planPath) {
109
+ if (!fs.existsSync(planPath)) {
110
+ throw new Error('distillAuditActions: plan file not found: ' + planPath);
111
+ }
112
+ const text = fs.readFileSync(planPath, 'utf8');
113
+ const lines = text.split(/\r?\n/);
114
+
115
+ const actions = [];
116
+ for (const rawLine of lines) {
117
+ const lineMatch = rawLine.match(PLAN_LINE_RE);
118
+ const candidate = lineMatch ? lineMatch[1] : rawLine;
119
+ if (!candidate || !DECISION_VERB_RE.test(candidate)) continue;
120
+
121
+ const verbMatch = candidate.match(DECISION_VERB_RE);
122
+ const action = verbMatch[1].toLowerCase();
123
+ const target = _extractTarget(candidate);
124
+
125
+ actions.push({
126
+ action,
127
+ target,
128
+ source: candidate.trim(),
129
+ });
130
+ }
131
+
132
+ return { actions };
133
+ }
134
+
135
+ module.exports = {
136
+ distillAuditActions,
137
+ writeOptOut,
138
+ readOptOut,
139
+ OPTOUT_REL_PATH,
140
+ // Test surface:
141
+ _extractTarget,
142
+ DECISION_VERB_RE,
143
+ };
144
+
145
+ // ── CLI ──────────────────────────────────────────────────────────────────
146
+
147
+ function _parseArgv(argv) {
148
+ const out = { cmd: null, planPath: null, projectDir: '.', reason: null };
149
+ out.cmd = argv[0] || null;
150
+ for (let i = 1; i < argv.length; i++) {
151
+ const a = argv[i];
152
+ if (a === '--plan') out.planPath = argv[++i];
153
+ else if (a === '--project') out.projectDir = argv[++i];
154
+ else if (a === '--reason') out.reason = argv[++i];
155
+ }
156
+ return out;
157
+ }
158
+
159
+ if (require.main === module) {
160
+ const args = _parseArgv(process.argv.slice(2));
161
+ if (args.cmd === 'distill') {
162
+ const result = distillAuditActions(args.planPath);
163
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
164
+ } else if (args.cmd === 'opt-out') {
165
+ const record = writeOptOut(args.projectDir, args.reason);
166
+ process.stdout.write(JSON.stringify(record, null, 2) + '\n');
167
+ } else {
168
+ process.stderr.write('Usage: gsd-t-audit-distill.cjs distill --plan <path> | opt-out --project <dir> --reason <text>\n');
169
+ process.exit(1);
170
+ }
171
+ }