@tekyzinc/gsd-t 4.19.13 → 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/CHANGELOG.md +27 -0
- package/README.md +3 -1
- package/bin/gsd-t-audit-distill.cjs +171 -0
- package/bin/gsd-t-logging-envelope-check.cjs +566 -0
- package/bin/gsd-t-logging-scaffolder.cjs +281 -0
- package/bin/gsd-t-migrate-logging.cjs +203 -0
- package/bin/gsd-t-trace-distill.cjs +196 -0
- package/bin/gsd-t-verify-gate.cjs +2 -0
- package/bin/gsd-t.js +67 -7
- package/commands/gsd-t-help.md +8 -0
- package/commands/gsd-t-init.md +11 -0
- package/commands/gsd-t-migrate-logging.md +46 -0
- package/commands/gsd-t-stories.md +27 -12
- package/commands/gsd-t-verify.md +2 -1
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +10 -0
- package/templates/logging/audit-module.template.ts +469 -0
- package/templates/logging/trace-module.template.ts +190 -0
- package/templates/playbooks/tekyz-user-stories-format.md +31 -12
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
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
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;
|
package/commands/gsd-t-help.md
CHANGED
|
@@ -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:
|
package/commands/gsd-t-init.md
CHANGED
|
@@ -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.
|
|
@@ -32,12 +32,18 @@ For EACH story, author in EXACTLY this order (per the format reference):
|
|
|
32
32
|
3. **Story:** `*As a <role>, I want <capability>, so that <benefit>.*` (strict template, one sentence.)
|
|
33
33
|
4. **Workflow:** numbered concrete interaction steps (user action → system response), present tense.
|
|
34
34
|
5. **Acceptance Criteria:** bulleted, **grouped by sub-area** with a bold sub-heading per group; include error/edge/recovery groups. Each bullet one testable assertion.
|
|
35
|
-
6. **Flow Diagram
|
|
36
|
-
7. **Mapped Test Cases
|
|
35
|
+
6. **Flow Diagram** (the LAST-but-one section; the diagram carries its OWN title banner INSIDE the image — see Step 4d — so there is NO external `Flow Diagram:` markdown label and NO footer label): a per-story Mermaid flowchart of THIS story's workflow → rendered PNG (with in-image title) → embedded (Step 4).
|
|
36
|
+
7. **Mapped Test Cases** (the LAST section of every story — each story ENDS here): a colored table `TC ID | Type | Test Title | Expected Result` (styling in Step 4e). `TC-NNN` sequential across the whole doc; `Type` ∈ {Positive, Negative, Edge}; cover happy-path + failure + boundary; every acceptance-criteria group represented by ≥1 test case.
|
|
37
|
+
|
|
38
|
+
**Pagination (MANDATORY — hard rule, exactly as stated):**
|
|
39
|
+
- **Each Epic (`EP-NN`) starts a NEW PAGE** (page-break BEFORE the epic heading).
|
|
40
|
+
- **The FIRST story of that epic flows on the SAME page** as the epic heading (no break between them).
|
|
41
|
+
- **Each SUBSEQUENT story in the same epic starts a NEW PAGE** (page-break BEFORE that story's `PREFIX-NNN` heading).
|
|
42
|
+
- Because every story ENDS with its Mapped Test Cases table, a page thus contains exactly one story (or epic-heading + first story). Enforce in `.docx` via page-break-before on epic headings and on every non-first story heading.
|
|
37
43
|
|
|
38
44
|
**Heading placement + no orphans (MANDATORY layout rules):**
|
|
39
|
-
- **Each section label sits ABOVE the content it introduces — never below it.**
|
|
40
|
-
- **Headings must NOT be orphaned across a page break.** A section label (`
|
|
45
|
+
- **Each section label sits ABOVE the content it introduces — never below it.** `Mapped Test Cases:` immediately PRECEDES its table; `Workflow:` precedes its steps; `Acceptance Criteria:` precedes its bullets. A label rendered after/below its block is a defect. (The Flow Diagram is the EXCEPTION — it has NO external label; its title is baked into the image, Step 4d.)
|
|
46
|
+
- **Headings must NOT be orphaned across a page break.** A section label (`Mapped Test Cases:`, a story `PREFIX-NNN` title, an epic `EP-NN`) must stay on the same page as at least the first line of its content (keep-with-next). Enforce with `keepNext` on heading paragraphs in the `.docx` conversion. With the pagination rule above (one story per page), orphaning is largely prevented structurally, but keep-with-next remains the backstop.
|
|
41
47
|
|
|
42
48
|
**No confabulation** (`feedback_no_confabulated_examples`): every story, workflow step, and test case must trace to something in the actual input source. If the source is silent on a needed detail, mark it a `[TODO: confirm with client]` — never invent product specifics.
|
|
43
49
|
|
|
@@ -71,18 +77,16 @@ classDef newfeat fill:#e2f0fb,stroke:#5b9bd5,color:#1f4e79,stroke-dasharray:4
|
|
|
71
77
|
|
|
72
78
|
The whole diagram MUST fit inside the page's visible area. **Compare aspect ratios first, then clamp ONLY the constraining dimension** — this is the standard "contain" fit; it guarantees no clipping and no distortion. Do NOT eyeball it or rely on layout luck.
|
|
73
79
|
|
|
74
|
-
**Page dimensions** (the visible printable area) default to **US Letter portrait content box ≈ 6.5in × 9in** (W×H, i.e. 8.5×11 minus 1in margins) unless the deliverable specifies otherwise.
|
|
75
|
-
|
|
76
|
-
**⚠️ RESERVE LABEL SPACE — critical.** Every diagram has a heading label ABOVE it (`Flow Diagram:`) that must sit on the SAME page (4b keep-with-next). If the image is set to the FULL page height, there is no room for the label → keep-with-next pushes the whole image to the next page (the Newman failure). So the height the image may occupy is **`avail_height = page_height − label_reserve`**, where `label_reserve ≈ 0.5in` (heading line + gap). Use `avail_height` — NOT the full `page_height` — as the height constraint. Width is unaffected (`avail_width = page_width`). `page_AR = avail_width / avail_height`.
|
|
80
|
+
**Page dimensions** (the visible printable area) default to **US Letter portrait content box ≈ 6.5in × 9in** (W×H, i.e. 8.5×11 minus 1in margins) unless the deliverable specifies otherwise. Because the diagram carries its OWN title banner INSIDE the image (Step 4d) — there is NO external label above it — the image may use the FULL page box: `avail_width = page_width`, `avail_height = page_height`. `page_AR = avail_width / avail_height`. (The one-story-per-page pagination rule means the diagram owns its page.)
|
|
77
81
|
|
|
78
82
|
**Algorithm — run per rendered diagram:**
|
|
79
83
|
1. **Render** the Mermaid to PNG (Step 4c), then **measure its actual pixel dimensions** `img_w × img_h` (e.g. via `sips -g pixelWidth -g pixelHeight <png>` on macOS, or `mmdc` output metadata). `img_AR = img_w / img_h`.
|
|
80
|
-
2. **Compute both aspect ratios**
|
|
84
|
+
2. **Compute both aspect ratios** — compare SHAPES, not sizes yet.
|
|
81
85
|
3. **Clamp the constraining dimension:**
|
|
82
|
-
- **If `img_AR > page_AR`** (image is *wider* than the
|
|
83
|
-
- **If `img_AR < page_AR`** (image is *taller* than the
|
|
86
|
+
- **If `img_AR > page_AR`** (image is *wider* than the page box) → **width is the constraint → set embedded `width = avail_width` (= page_width)** (height scales proportionally, lands ≤ avail_height). *Example: a 5-wide × 4-tall image → set width = page width.*
|
|
87
|
+
- **If `img_AR < page_AR`** (image is *taller* than the page box) → **height is the constraint → set embedded `height = avail_height` (= page_height)** (width scales proportionally). *Example: a 2-wide × 4-tall image → set height = page height.*
|
|
84
88
|
- **If equal** → either works; set width = avail_width.
|
|
85
|
-
4. **Embed at that ONE clamped dimension** so the renderer scales the other proportionally. In markdown, use an HTML `<img>` with only the clamped side set (e.g. `<img src="media/<name>.png" width="…" />` or `height="…"`) — never set both (that distorts). For `.docx`, pandoc honors the single dimension.
|
|
89
|
+
4. **Embed at that ONE clamped dimension** so the renderer scales the other proportionally. In markdown, use an HTML `<img>` with only the clamped side set (e.g. `<img src="media/<name>.png" width="…" />` or `height="…"`) — never set both (that distorts). For `.docx`, pandoc honors the single dimension.
|
|
86
90
|
|
|
87
91
|
**Layout still matters as an INPUT to the ratio** (not a substitute for it): choose `flowchart LR` for long linear flows and `TD` for short ones so the rendered `img_AR` is closer to the page shape *before* clamping — this maximizes the final on-page size. But the aspect-ratio clamp above is what GUARANTEES the fit; the direction choice only optimizes how much of the page it fills.
|
|
88
92
|
|
|
@@ -94,9 +98,20 @@ Never ship a diagram wider or taller than the page (`feedback_no_silent_degradat
|
|
|
94
98
|
2. Render each to PNG: `mmdc -i <src>.mmd -o share/media/<name>.png --width 1600 --backgroundColor white --scale 2 --padding 20` (Mermaid CLI `@mermaid-js/mermaid-cli`; fall back to `npx @mermaid-js/mermaid-cli …`).
|
|
95
99
|
3. **If `mmdc` is unavailable → HALT** and tell the user to install it (`npm i -g @mermaid-js/mermaid-cli`). Do NOT silently ship raw Mermaid where an embedded image is expected (`feedback_no_silent_degradation`).
|
|
96
100
|
4. **Measure + clamp per the 4b aspect-ratio algorithm:** read the rendered PNG's pixel `img_w × img_h` (`sips -g pixelWidth -g pixelHeight share/media/<name>.png`), compute `img_AR` vs `page_AR`, and pick the ONE clamped dimension (width=page_width if wider, else height=page_height).
|
|
97
|
-
5. Embed each rendered PNG at that clamped dimension using an HTML `<img>` with only the constraining side set — e.g. `<img src="media/<name>.png" width="6.5in" />` OR `<img src="media/<name>.png" height="9in" />` (never both). Place it
|
|
101
|
+
5. Embed each rendered PNG at that clamped dimension using an HTML `<img>` with only the constraining side set — e.g. `<img src="media/<name>.png" width="6.5in" />` OR `<img src="media/<name>.png" height="9in" />` (never both). Place it directly where the story's diagram belongs — with NO external `Flow Diagram:` label and NO footer label (the title is in the image, Step 4d).
|
|
98
102
|
6. Keep the `.mmd` source (editable, version-controllable) alongside the PNG.
|
|
99
103
|
|
|
104
|
+
### 4d. In-image title banner (MANDATORY — replaces the external Flow Diagram label)
|
|
105
|
+
|
|
106
|
+
Each per-story diagram carries its OWN title INSIDE the rendered image — a filled banner at the TOP showing the story id + title (matching the sample: `NWMN-003` bold on line 1, the story title on line 2, on a light-purple fill). This lets the doc DROP the external `Flow Diagram:` markdown label AND any footer label. Implement as the first node(s) of the flowchart, styled as the banner (a full-width `screen`-class node with the two lines), OR via a mermaid `title`/subgraph header styled to match. Font: bold id line + regular title line, dark-purple text (`#2d2160`) on light-purple fill (`#ece9fb`) — the `screen` classDef. The app-flow chart (§1) gets a matching banner with the product name.
|
|
107
|
+
|
|
108
|
+
### 4e. Mapped Test Cases table coloring (MANDATORY)
|
|
109
|
+
|
|
110
|
+
The test-case table is COLORED, not plain (matching the sample):
|
|
111
|
+
- **Header row:** white bold text on a **purple gradient / solid purple fill** (`#7c5cfc`-ish), all four columns.
|
|
112
|
+
- **`Type` cell tinted by value:** **Positive → green** (`#e6f4ea` fill, green text) · **Negative → peach/orange** (`#fdecd8` fill, amber text) · **Edge → blue** (`#e2eefb` fill, blue text). Only the Type cell is tinted; other cells stay white with normal text.
|
|
113
|
+
- Markdown tables can't carry cell fills, so for the `.docx` this coloring is applied at conversion (a pandoc pipeline / post-process on the table), OR the table is authored as raw HTML with inline styles that pandoc converts to Word table shading. Keep the plain-markdown table as the editable source; apply the color styling in the rendered/delivered output.
|
|
114
|
+
|
|
100
115
|
## Step 5: Assemble + Deliver
|
|
101
116
|
|
|
102
117
|
1. Assemble front matter (product, "Prepared by Tekyz Inc.", version, source-of-truth note; SAMPLE disclaimer only if illustrative) + §1 + §2 + §3.
|
package/commands/gsd-t-verify.md
CHANGED
|
@@ -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.
|
|
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.
|