@tekyzinc/gsd-t 4.19.14 → 4.20.10

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/bin/gsd-t.js CHANGED
@@ -203,6 +203,24 @@ const {
203
203
  } = require("./playwright-bootstrap.cjs");
204
204
  const { hasUI } = require("./ui-detection.cjs");
205
205
 
206
+ // M100 D1: stack-adaptive storage scaffolder — the sole init-scaffold seam.
207
+ // Presents real alternatives and PAUSES for human approval; never silently
208
+ // picks a logging backend. See .gsd-t/contracts/logging-scaffold-seam-contract.md.
209
+ const { scaffoldLogging } = require("./gsd-t-logging-scaffolder.cjs");
210
+
211
+ // runLoggingScaffoldStep(projectDir, opts): the init-dispatch integration
212
+ // point. Calls the scaffolder and explicitly checks the envelope's `status`
213
+ // field: on "PAUSED" it halts BEFORE any sink/template write and surfaces
214
+ // alternatives[] to the caller; it only proceeds (halted:false) once a
215
+ // resolved `backend` comes back (fresh approval or a valid recorded choice).
216
+ function runLoggingScaffoldStep(projectDir, opts) {
217
+ const envelope = scaffoldLogging(Object.assign({ projectDir }, opts || {}));
218
+ if (envelope.status === "PAUSED") {
219
+ return { halted: true, alternatives: envelope.alternatives, resumeToken: envelope.resumeToken };
220
+ }
221
+ return { halted: false, backend: envelope.backend, envelope };
222
+ }
223
+
206
224
  function readProjectDeps(projectDir) {
207
225
  const pkgPath = path.join(projectDir, "package.json");
208
226
  if (!fs.existsSync(pkgPath)) return [];
@@ -2130,6 +2148,26 @@ async function doInit(projectName) {
2130
2148
  // M52 D1: auto-install the journey-coverage gate. Idempotent — no-op if marker present.
2131
2149
  if (hasUI(projectDir)) installJourneyCoverageHook(projectDir);
2132
2150
 
2151
+ // M100 D1: storage scaffolder step. Presents real backend alternatives and
2152
+ // PAUSES for human approval — the ONE sanctioned pause against Level-3
2153
+ // full-auto. On PAUSED, halts here and surfaces alternatives; never writes
2154
+ // a trace/audit sink or picks a backend silently. See
2155
+ // .gsd-t/contracts/logging-scaffold-seam-contract.md.
2156
+ try {
2157
+ const loggingOutcome = runLoggingScaffoldStep(projectDir);
2158
+ if (loggingOutcome.halted) {
2159
+ warn("Logging backend not yet chosen — scaffolder is PAUSED for human approval:");
2160
+ for (const alt of loggingOutcome.alternatives) {
2161
+ info(` - ${alt.backend}${alt.recommended ? " (recommended)" : ""}: ${alt.label} — ${alt.reason}`);
2162
+ }
2163
+ info(`Re-run init with an approved backend to resume (resumeToken: ${loggingOutcome.resumeToken}).`);
2164
+ } else {
2165
+ success(`Logging backend: ${loggingOutcome.backend}`);
2166
+ }
2167
+ } catch (e) {
2168
+ warn(`Logging scaffold step errored: ${e.message || e}`);
2169
+ }
2170
+
2133
2171
  showInitTree(projectDir);
2134
2172
  }
2135
2173
 
@@ -3736,13 +3774,17 @@ function refreshVersionAsync() {
3736
3774
  }
3737
3775
 
3738
3776
  function showUpdateNotice(latest) {
3739
- log("");
3740
- log(` ${YELLOW}╭──────────────────────────────────────────────╮${RESET}`);
3741
- log(` ${YELLOW}│${RESET} Update available: ${DIM}${PKG_VERSION}${RESET} ${GREEN}${latest}${RESET} ${YELLOW}│${RESET}`);
3742
- log(` ${YELLOW}│${RESET} Run: ${CYAN}npm update -g @tekyzinc/gsd-t${RESET} ${YELLOW}│${RESET}`);
3743
- log(` ${YELLOW}│${RESET} Then: ${CYAN}gsd-t update-all${RESET} ${YELLOW}│${RESET}`);
3744
- log(` ${YELLOW}│${RESET} Changelog: ${CYAN}gsd-t changelog${RESET} ${YELLOW}│${RESET}`);
3745
- log(` ${YELLOW}╰──────────────────────────────────────────────╯${RESET}`);
3777
+ // Human-facing banner MUST go to stderr — writing it to stdout corrupts the JSON
3778
+ // output of machine commands (e.g. `graph body`, `graph --output json`), breaking
3779
+ // any JSON.parse consumer. stderr keeps the banner visible without polluting stdout.
3780
+ const e = (msg) => console.error(msg);
3781
+ e("");
3782
+ e(` ${YELLOW}╭──────────────────────────────────────────────╮${RESET}`);
3783
+ e(` ${YELLOW}│${RESET} Update available: ${DIM}${PKG_VERSION}${RESET} → ${GREEN}${latest}${RESET} ${YELLOW}│${RESET}`);
3784
+ e(` ${YELLOW}│${RESET} Run: ${CYAN}npm update -g @tekyzinc/gsd-t${RESET} ${YELLOW}│${RESET}`);
3785
+ e(` ${YELLOW}│${RESET} Then: ${CYAN}gsd-t update-all${RESET} ${YELLOW}│${RESET}`);
3786
+ e(` ${YELLOW}│${RESET} Changelog: ${CYAN}gsd-t changelog${RESET} ${YELLOW}│${RESET}`);
3787
+ e(` ${YELLOW}╰──────────────────────────────────────────────╯${RESET}`);
3746
3788
  }
3747
3789
 
3748
3790
  function doChangelog() {
@@ -4871,6 +4913,8 @@ module.exports = {
4871
4913
  promptForApiKeyIfMissing,
4872
4914
  resolveApiKeyEnvVar,
4873
4915
  runTaskCounterRetirementMigration,
4916
+ // M100: storage scaffolder seam
4917
+ runLoggingScaffoldStep,
4874
4918
  };
4875
4919
 
4876
4920
  // ─── Main ────────────────────────────────────────────────────────────────────
@@ -4972,6 +5016,22 @@ if (require.main === module) {
4972
5016
  case "graph":
4973
5017
  doGraph(args.slice(1));
4974
5018
  break;
5019
+ case "migrate-logging": {
5020
+ // M100 D1 wiring on d5's behalf — d1 is the SOLE editor of bin/gsd-t.js;
5021
+ // d5 owns bin/gsd-t-migrate-logging.cjs (the module) and
5022
+ // commands/gsd-t-migrate-logging.md (the command). See
5023
+ // .gsd-t/contracts/logging-scaffold-seam-contract.md §Ownership boundary.
5024
+ let migrateLogging;
5025
+ try {
5026
+ migrateLogging = require("./gsd-t-migrate-logging.cjs");
5027
+ } catch (e) {
5028
+ error(`migrate-logging module not found: ${e.message || e}`);
5029
+ process.exit(1);
5030
+ }
5031
+ Promise.resolve(migrateLogging.run ? migrateLogging.run(args.slice(1)) : migrateLogging(args.slice(1)))
5032
+ .catch((e) => { error(e.message || String(e)); process.exit(1); });
5033
+ break;
5034
+ }
4975
5035
  case "headless":
4976
5036
  doHeadless(args.slice(1));
4977
5037
  break;
@@ -76,6 +76,7 @@ HEADLESS (CI/CD) CLI
76
76
  research-gate Classify a guessed claim: internal (grep) / external (web) / ambiguous (LLM judge) [M89]
77
77
  architectural-trigger Fire the architectural-assumption trigger (divergence-sampling or extend-existing-code) [M90]
78
78
  loop-ledger Record a debug cycle, read exit state, detect non-convergence (premise-re-examination) [M90]
79
+ migrate-logging Brownfield: scaffold trace + audit logging into an existing project, additively [M100]
79
80
 
80
81
  BACKLOG Manual
81
82
  ───────────────────────────────────────────────────────────────────────────────
@@ -553,6 +554,13 @@ Use these when user asks for help on a specific command:
553
554
  - **CLI**: `gsd-t loop-ledger append-cycle --assertion "<symptom>" --surface "<file>" --fileClass unit --projectDir <dir>`. `gsd-t loop-ledger read-exit-state --projectDir <dir>`. Exit 0 on success.
554
555
  - **Contract**: `.gsd-t/contracts/unproven-assumption-doctrine-contract.md` §3 v1.0.0 STABLE.
555
556
 
557
+ ### migrate-logging (M100)
558
+ - **Summary**: Brownfield migration — scaffolds the two framework-default logging streams (trace + audit) into an EXISTING project, ADDITIVELY. Trace is a default for every project except explicit opt-out recorded at `.gsd-t/trace-optout.json` (see `trace-logging-contract.md` §opt-out-record — a stateless CLI/library with no runtime data-flow may opt out); audit is a default except an explicit opt-out recorded at `.gsd-t/audit-optout.json` (see `audit-logging-contract.md` §opt-out-record) — the migration honors an existing opt-out for either stream rather than forcing a store on it. Every pre-existing project file is left byte-for-byte unchanged; only new logging files are added. Dispatch is wired into `bin/gsd-t.js` `case "migrate-logging"` by d1 (the sole editor of that file) on d5's behalf — the module (`bin/gsd-t-migrate-logging.cjs`) and this command are owned by d5 via the scaffold-seam contract.
559
+ - **Files**: `bin/gsd-t-migrate-logging.cjs`. Contracts: `.gsd-t/contracts/logging-scaffold-seam-contract.md`, `.gsd-t/contracts/logging-schema-distillation-contract.md`, `trace-logging-contract.md`, `audit-logging-contract.md`.
560
+ - **Use when**: An existing (brownfield) project needs the trace/audit defaults retrofitted without touching its current code or tests.
561
+ - **CLI**: `gsd-t migrate-logging <projectDir> [--plan <path-to-plan.md>]`. Exit 0 on success · 1 on migration error.
562
+ - **Proven**: `test/m100-d5-migration-fixture.test.js` — runs the migration against a throwaway fixture repo and asserts additive/non-destructive behavior (pre-existing files unchanged) before/after snapshot comparison.
563
+
556
564
  ## Unknown Command
557
565
 
558
566
  If user asks for help on unrecognized command:
@@ -350,6 +350,17 @@ Operator overrides: `gsd-t setup-playwright [path]` (explicit single-project ins
350
350
 
351
351
  The spawn-time gate in `bin/headless-auto-spawn.cjs` re-runs the install on first need if the project skipped this step (e.g., older project that pre-dates M50).
352
352
 
353
+ ## Step 11.5: Logging Backend Scaffold (M100)
354
+
355
+ The `bin/gsd-t.js init` flow calls `runLoggingScaffoldStep(projectDir)` (from `bin/gsd-t-logging-scaffolder.cjs`) automatically, right before the init tree summary. This is the sole init-scaffold seam for M100's trace/audit logging.
356
+
357
+ - It detects the stack (has-DB → `db-table` alternative; no-server/desktop → `local-sqlite` | `local-jsonl`, with SQLite flagged over flat-file for audit queryability).
358
+ - It **presents real alternatives and PAUSES for human approval** — this is the ONE sanctioned pause against the Level-3 full-auto default (see `.gsd-t/contracts/logging-scaffold-seam-contract.md`). It never silently picks a backend.
359
+ - On re-run with a previously-approved choice, it resumes deterministically (no re-prompt) and records the backend into the project's `CLAUDE.md`.
360
+ - If it halts with `status:"PAUSED"`, report the presented alternatives to the user and wait for them to choose before re-running init with an approved backend — do NOT guess or auto-select on their behalf.
361
+
362
+ See `.gsd-t/contracts/logging-scaffold-seam-contract.md` for the full seam envelope shape consumed by d2 (trace), d4 (audit), and d5 (migrate-logging).
363
+
353
364
  ## Step 12: Test Verification
354
365
 
355
366
  After initialization:
@@ -0,0 +1,46 @@
1
+ # GSD-T: Migrate Logging — Brownfield Trace + Audit Retrofit
2
+
3
+ Scaffolds the two framework-default logging streams — **trace** (transient debug signal, no opt-out) and **audit** (durable accountability record, default except explicit opt-out) — into an EXISTING project, additively. See `~/.claude/CLAUDE.md` § Logging Defaults for the two hard rules this command implements.
4
+
5
+ ## What this does
6
+
7
+ - Copies the trace module template (`templates/logging/trace-module.template.ts`) to `src/logging/trace.ts` — **only if that file does not already exist**.
8
+ - Copies the audit module template (`templates/logging/audit-module.template.ts`) to `src/logging/audit.ts` — **only if that file does not already exist**.
9
+ - Distills the per-project trace category / audit action schema from the project's own plan (when `--plan` is given) into `.gsd-t/logging-schema.json` — never confabulated; an unstated category/action is a gap, not a guess.
10
+ - Runs d1's stack-adaptive storage scaffolder (`scaffoldLogging()`), which detects the stack and **pauses for human approval** before recording a storage backend — never silently picks one.
11
+
12
+ ## Non-destructive guarantee (MANDATORY)
13
+
14
+ This command is **purely additive**. Every write is preceded by an existence check; a file that already exists in the target project is left byte-for-byte untouched. It is proven non-destructive on a throwaway fixture in `test/m100-d5-migration-fixture.test.js` — a run that modifies or deletes any pre-existing fixture file is a test FAILURE.
15
+
16
+ ## Usage
17
+
18
+ ```
19
+ gsd-t migrate-logging <projectDir> [--plan <path-to-plan.md>] [--approve <db-table|local-sqlite|local-jsonl>]
20
+ ```
21
+
22
+ - `<projectDir>` — required. The existing project to retrofit.
23
+ - `--plan <path>` — optional. Distills the concrete trace category / audit action set from this plan file. Omit to get an empty (never invented) schema.
24
+ - `--approve <backend>` — optional. Approves a storage backend up front (`db-table` / `local-sqlite` / `local-jsonl`). Omit to let the scaffolder pause and present alternatives first.
25
+
26
+ ## Step 1: Run the migration
27
+
28
+ Invoke the module via the CLI dispatch (owned by d1 — `bin/gsd-t.js` `case "migrate-logging"`; the module itself is owned by this domain, see `.gsd-t/contracts/logging-scaffold-seam-contract.md`):
29
+
30
+ ```bash
31
+ gsd-t migrate-logging "$ARGUMENTS"
32
+ ```
33
+
34
+ ## Step 2: Report
35
+
36
+ Show the created/skipped file lists and the storage scaffold result (approved backend, or the PAUSED alternatives list awaiting human approval) exactly as returned by the module — do not summarize away a PAUSED state as if it were complete.
37
+
38
+ ## Step 3: If storage is PAUSED
39
+
40
+ Present the alternatives to the user and wait for an explicit backend choice (the ONE sanctioned pause against the Level-3 full-auto default — see `.gsd-t/contracts/logging-scaffold-seam-contract.md`). Re-run with `--approve <backend>` once chosen.
41
+
42
+ $ARGUMENTS
43
+
44
+ ## Auto-Clear
45
+
46
+ All work is committed to project files. Execute `/clear` to free the context window for the next command.
@@ -20,9 +20,10 @@ preflight → brief → verify-gate (deterministic Track 1+2)
20
20
  Per `.gsd-t/contracts/orthogonal-validation-contract.md` v1.0.0 STABLE, the three triad stages are orthogonal objective functions — no collapse, no substitution, no transitive trust. Synthesis preserves category labels.
21
21
 
22
22
  **Hard-failing gates** (each halts before triad):
23
- - `verify-gate` — deterministic Track 1 (preflight envelope) + Track 2 (tsc/biome/npm-test/knip/gitleaks/scc fan-out)
23
+ - `verify-gate` — deterministic Track 1 (preflight envelope) + Track 2 (tsc/biome/npm-test/knip/gitleaks/scc/logging-envelope fan-out)
24
24
  - M57 `build-coverage` + `ci-parity` — origin TimeTracking v1.10.12 Dockerfile incident
25
25
  - M58 `test-data --purge` — origin GSD-T-Board v0.1.10 2442 E2E orphans incident
26
+ - M100 `logging-envelope` — structural predicate (`bin/gsd-t-logging-envelope-check.cjs`) enforcing BOTH the trace envelope (`ts`/`category`/`decision`/`detail`) and the audit envelope (`ts`/`actor`/`action`/`target`/`before`/`after`/`context`) over per-project-varying schemas — never a hardcoded category/action value. Also enforces the trace PII bar (recursing into nested `data`), the no-collapse boundary (a record MUST NOT carry top-level markers from both streams), append-only/immutability, retention-configurability, and audit-default-except-opt-out (`.gsd-t/audit-optout.json`). FAIL-CLOSED — never warn-and-proceed. Contract: `.gsd-t/contracts/logging-verify-gate-contract.md`.
26
27
 
27
28
  ## Step 1: Read the current milestone state
28
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "4.19.14",
3
+ "version": "4.20.10",
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",
@@ -222,6 +222,16 @@ The hard rules (non-negotiable, all projects):
222
222
  - **Functional, not layout.** Every assertion must prove state changed / data flowed / content loaded / widget responded — not mere existence (`isVisible`/`toBeAttached`). If a test would pass on empty HTML with the right IDs and no JS, rewrite it.
223
223
  - **Test-data cleanup.** Tests that insert data MUST register it via the `withTestData()` fixture so verify Step 4.5 (`gsd-t test-data --purge`) can remove it; an adapter throw/refusal FAILs the gate. Adapters refuse to delete ids lacking the ledger `taggedPrefix`. See [[feedback_test_data_cleanup_convention]] + `.gsd-t/contracts/test-data-ledger-contract.md`.
224
224
 
225
+ ## Logging Defaults — Trace + Audit (M100 — MANDATORY)
226
+
227
+ Every GSD-T project gets TWO logging streams scaffolded by default at `gsd-t-init` — never opt-in, and never silently skipped (an opt-out must be an explicit, reasoned, recorded decision, not a silent absence). Contracts: `.gsd-t/contracts/trace-logging-contract.md`, `.gsd-t/contracts/audit-logging-contract.md`, `.gsd-t/contracts/logging-schema-distillation-contract.md`, `.gsd-t/contracts/logging-scaffold-seam-contract.md`.
228
+
229
+ - **Rule 1 — Trace is a default for EVERY project EXCEPT explicit opt-out.** Trace = a transient, PII-barred, toggleable DEBUGGING SIGNAL STREAM (`ts`/`category`/`decision`/`detail` envelope). Scaffolded into every project regardless of stack; `gsd-t-verify` FAILs a project with no discoverable trace module/store AND no valid opt-out record. A stateless CLI/library with no runtime data-flow (no requests/jobs/integrations/user sessions) may opt out by writing the canonical opt-out record to `.gsd-t/trace-optout.json` (`{"traceOptOut": true, "reason": "<why>"}` — see `trace-logging-contract.md` §opt-out-record); a running application must NOT opt out.
230
+ - **Rule 2 — Audit is a default for EVERY project EXCEPT explicit opt-out declared in the project's own CLAUDE.md.** Audit = a durable, admin-queryable, append-only ACCOUNTABILITY record (`ts`/`actor`/`action`/`target`/`before`/`after`/`context` envelope). A project that genuinely has no admin-facing accountability surface (e.g. a pure local trace-only tool) may opt out by writing the canonical opt-out record to `.gsd-t/audit-optout.json` (`{"auditOptOut": true, "reason": "<why>"}` — see `audit-logging-contract.md` §opt-out-record). `gsd-t-verify` FAILs any project with neither a discoverable audit store NOR a valid opt-out record; a valid opt-out is honored and does NOT fail the project for missing audit.
231
+ - **Storage is stack-adaptive and human-approval-gated** — `bin/gsd-t-logging-scaffolder.cjs` detects the stack, presents real alternatives, and STOPS for approval; it never silently picks a backend (the one sanctioned pause against the Level-3 full-auto default).
232
+ - **Trace and audit NEVER collapse into one stream.** A trace envelope carrying audit markers (`before`/`after`/`actor`/`action`) or vice-versa is a contract violation and a `gsd-t-verify` FAIL — see each contract's §no-collapse boundary.
233
+ - **Brownfield migration**: `gsd-t migrate-logging <projectDir>` scaffolds both streams into an EXISTING project additively — it never modifies or deletes a pre-existing file. See `commands/gsd-t-migrate-logging.md`.
234
+
225
235
  ## Orthogonal Validation Triad (Mandatory)
226
236
 
227
237
  Every code-producing phase ends with `gsd-t-verify.workflow.js`, which runs three orthogonal validators as `parallel()` `agent()` stages with schema-validated output. Per `.gsd-t/contracts/orthogonal-validation-contract.md` v1.0.0 STABLE, they are declared orthogonal objective functions — no collapse, no substitution, no transitive trust.