@tekyzinc/gsd-t 4.0.27 → 4.0.29

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.
@@ -1,12 +1,12 @@
1
1
  # Architecture — GSD-T Framework (@tekyzinc/gsd-t)
2
2
 
3
- ## Last Updated: 2026-03-22 (M23 Headless Mode)
3
+ ## Last Updated: 2026-06-04 (Scan #12 deep-doc pass, v4.0.12)
4
4
 
5
- > **Scan #11 note (2026-04-16, v3.11.11)**: this doc is partially stale relative to
6
- > M34 (Context Meter), M35 (Runway-Protected Execution), M36 (Unattended Supervisor),
7
- > M37 (Universal Auto-Pause), and the v3.11.11 switch to local token estimation.
8
- > See `.gsd-t/scan/architecture.md` for the current architecture snapshot and
9
- > `.gsd-t/techdebt.md` TD-103 for the doc-ripple milestone candidate.
5
+ > **Scan #12 note (2026-06-04, v4.0.12)**: Added M57 CI-parity gate, M58 test-data ledger,
6
+ > M61 Workflow engine (sandbox contract, _lib.js, orthogonal validation triad, stack rules,
7
+ > patch lifecycle), M66/M67 codebase scan redesign, and architecture corrections for
8
+ > critical verified findings (Workflow sandbox crashes, fan-out parallelism disabled,
9
+ > verify-gate false-pass, design-to-code bugs, token aggregator bugs, security findings).
10
10
 
11
11
  ## System Overview
12
12
 
@@ -20,22 +20,27 @@ The framework has no runtime — it is consumed entirely by Claude Code's slash
20
20
 
21
21
  ### CLI Installer (bin/gsd-t.js)
22
22
  - **Purpose**: Install, update, diagnose, and manage GSD-T across projects
23
- - **Location**: `bin/gsd-t.js` (1,798 lines, 90+ functions, all 30 lines)
23
+ - **Location**: `bin/gsd-t.js` (4,000+ lines as of v4.0.12, well past original 200-line target — accepted deviation per zero-dep constraint)
24
24
  - **Dependencies**: Node.js built-ins only (fs, path, os, child_process, https, crypto)
25
- - **Subcommands**: install, update, status, doctor, init, uninstall, update-all, register, changelog, graph (index/status/query), headless (exec/query/--debug-loop)
25
+ - **Subcommands**: install, update, status, doctor, init, uninstall, update-all, register, changelog, graph (index/status/query), headless (exec/query/--debug-loop), parallel, preflight, brief, verify-gate, verify-gate-judge, build-coverage, ci-parity, test-data, query, scan (stub — no-op), setup-playwright, check-coverage, tokens, tool-cost
26
26
  - **Organization**: Configuration → Guard section → Helpers → Heartbeat → Commands → Install/Update → Init → Status → Uninstall → Update-All → Doctor → Register → Update Check → Help → Main dispatch
27
- - **All functions 30 lines** (M6 refactoring). Largest: `doRegister()` at 30 lines, `summarize()` at 30 lines.
27
+ - **Known dead code**: `installContextMeter`, `configureContextMeterHooks`, `showStatusContextMeter`, and associated constants (~200 lines) - context meter was retired in M61 D1 but these functions are still called in `doInstall`/`doStatus`. The hook silently exits 0 via a guard when script is absent.
28
+ - **Known race**: `doInstall` calls five separate functions each reading/modifying/writing `settings.json` independently (no lock). External writers (Claude Code) can cause hook loss.
28
29
 
29
30
  ### Slash Commands (commands/*.md)
30
31
  - **Purpose**: Define the GSD-T methodology as executable workflows for Claude Code
31
32
  - **Location**: `commands/`
32
- - **Count**: 49 (45 GSD-T workflow + 4 utility: gsd, branch, checkin, Claude-md, global-change) includes gsd-t-health, gsd-t-pause (M13), gsd-t-reflect (M14), gsd-t-visualize (M15), gsd-t-prd (M16), global-change (M20)
33
- - **Format**: Pure markdown with step-numbered instructions, team mode blocks, document ripple sections, and $ARGUMENTS terminator
33
+ - **Count**: 51 (as of v4.0.12 run `ls commands/ | wc -l` for current count; do not hand-maintain)
34
+ - **Format**: Pure markdown with step-numbered instructions, thin Workflow invokers (`Workflow({scriptPath, args})`), document ripple sections, and $ARGUMENTS terminator
35
+ - **Note**: As of M61, command files are THIN INVOKERS - they call `Workflow({scriptPath, args})`. The workflow logic lives in `templates/workflows/*.workflow.js`. The `scriptPath` MUST be resolved to an absolute path via `gsd-t workflow-path <name>` at invoke time.
34
36
 
35
- ### Templates (templates/*.md)
36
- - **Purpose**: Starter files for project initialization
37
+ ### Templates (templates/)
38
+ - **Purpose**: Starter files for project initialization + workflow orchestration scripts + subagent prompt protocols
37
39
  - **Location**: `templates/`
38
- - **Count**: 9 (CLAUDE-global, CLAUDE-project, requirements, architecture, workflows, infrastructure, progress, backlog, backlog-settings)
40
+ - **Init templates**: CLAUDE-global, CLAUDE-project, requirements, architecture, workflows, infrastructure, progress, backlog, backlog-settings, design-contract, element-contract, widget-contract, page-contract, shared-services-contract, design-chart-taxonomy, context-meter-config.json
41
+ - **Workflow scripts** (`templates/workflows/`): 9 native Workflow scripts (gsd-t-scan is correctly runtime-native; 7 others are broken pending M71 migration completion)
42
+ - **Subagent protocols** (`templates/prompts/`): qa-subagent.md, red-team-subagent.md, design-verify-subagent.md - loaded by `_lib.loadProtocol(name)`; never inlined into Workflow scripts
43
+ - **Stack rules** (`templates/stacks/`): stack-specific rules injected at spawn time. Universal rules prefixed `_` (e.g. `_security.md`, `_auth.md`, `_markdown.md`). Known: NOT injected into M61 Workflow agents.
39
44
  - **Tokens**: `{Project Name}` and `{Date}` replaced during init via `applyTokens()`
40
45
 
41
46
  ### Hook Scripts (scripts/)
@@ -1064,6 +1069,218 @@ post-wave), color-state thresholds, silent-fail on malformed inputs, Full
1064
1069
  Report markdown sections, and `/api/parallelism*` endpoint shape + 5s
1065
1070
  cache behaviour.
1066
1071
 
1072
+ ## CI-Parity Gate (M57, v3.27.x+)
1073
+
1074
+ `bin/gsd-t-build-coverage.cjs` + `bin/gsd-t-ci-parity.cjs` form the M57 FAIL-blocking gate inside `gsd-t-verify.workflow.js`. They exist because the TimeTracking v1.10.12 incident: a new `hooks/` directory was committed, absent from the Dockerfile COPY stanza, and shipped broken while local verify reported VERIFIED.
1075
+
1076
+ **Build Coverage** (`bin/gsd-t-build-coverage.cjs`):
1077
+ - Detects new top-level paths added in a milestone commit range that no CI build artifact references.
1078
+ - Structurally parses CI config (Dockerfile COPY/ADD, cloudbuild.yaml `steps[].args`, GitHub Actions `jobs.<job>.steps[].run`). No substring matching.
1079
+ - `paths whose first segment is node_modules` are never flagged.
1080
+ - CLI: `gsd-t build-coverage [--json] [--base REF] [--head REF]`.
1081
+ - Contract: `.gsd-t/contracts/build-coverage-contract.md` v1.0.0 STABLE.
1082
+
1083
+ **CI Parity** (`bin/gsd-t-ci-parity.cjs`):
1084
+ - Reproduces the project's actual CI build locally.
1085
+ - Auto-detects CI config in locked precedence: `cloudbuild.yaml` > `.github/workflows/*.yml` > `Dockerfile RUN` > `package.json scripts`.
1086
+ - Clears build caches before running so stale incremental artifacts cannot mask regressions (cold-build parity).
1087
+ - When a Dockerfile is present, runs `docker build` unconditionally.
1088
+ - Contract: `.gsd-t/contracts/ci-parity-contract.md` v1.0.0 STABLE.
1089
+
1090
+ Both gates run inside `gsd-t-verify.workflow.js` as FAIL-blocking stages before the orthogonal validation triad. A failed gate produces `VERIFY-FAILED` and blocks milestone promotion.
1091
+
1092
+ ## Test-Data Ledger (M58, v3.28.x+)
1093
+
1094
+ `bin/gsd-t-test-data-ledger.cjs` is an append-only JSONL ledger tracking test data inserted during a Verify run, plus a purge engine that removes those records after the suite completes. Origin: GSD-T-Board v0.1.10 left 2442 orphaned `E2E_*` records in production data after an unattended verify run.
1095
+
1096
+ **Adapters** (`bin/gsd-t-test-data-adapters/`):
1097
+ - `localStorage-key-prefix.cjs` - purges localStorage keys starting with a registered prefix.
1098
+ - `file-json-array.cjs` - removes tagged items from a JSON array file.
1099
+ - `sqlite-table-where.cjs` - deletes rows from a SQLite table by id with tag-prefix guard.
1100
+ - Custom adapters: `registerAdapter(kind, { purge(...) })` at test setup time.
1101
+
1102
+ Each adapter re-validates the tag prefix before deleting (defense in depth). An adapter that refuses or throws causes verify to FAIL (block-promotion semantics).
1103
+
1104
+ **Playwright fixture** (`templates/test-helpers/test-data-fixture.ts`):
1105
+ ```
1106
+ export const test = base.extend(withTestData());
1107
+ test('...', async ({ testData }) => {
1108
+ const id = testData.tag('E2E_DRAG');
1109
+ await testData.register({ kind: 'localStorage-key-prefix', store: 'app:idea:', id, taggedPrefix: 'E2E_' });
1110
+ });
1111
+ ```
1112
+
1113
+ **Purge gate**: `gsd-t-verify.workflow.js` Step 4.5 runs `gsd-t test-data --purge --run "$GSD_T_VERIFY_RUN_ID"`. Contract: `.gsd-t/contracts/test-data-ledger-contract.md` v1.0.0 STABLE.
1114
+
1115
+ ## GSD-T Workflow Engine (M61, v4.0.10+)
1116
+
1117
+ M61 is the major architectural shift: routine GSD-T phases move from Claude-Code-inline markdown steps to native Anthropic Workflow scripts. The Workflow tool is the execution substrate; command files become thin invokers.
1118
+
1119
+ ### Sandbox Contract (M71 - critical)
1120
+
1121
+ The native Workflow runtime exposes EXACTLY: `agent()`, `parallel()`, `pipeline()`, `log()`, `phase()`, `budget`, `args`. It does NOT provide `require`, `module`, `fs`, `path`, `child_process`, or `process`. Using any of those throws `ReferenceError: require is not defined` at runtime. `node --check` validates syntax only and cannot catch this.
1122
+
1123
+ **The correctly-migrated workflow**: `templates/workflows/gsd-t-scan.workflow.js` - does zero file I/O in the orchestrator body; all reads/writes happen inside `agent()` stages which have Bash/Read/Write/Grep tools.
1124
+
1125
+ **Known debt (CRITICAL)**: `gsd-t-execute.workflow.js`, `gsd-t-verify.workflow.js`, `gsd-t-wave.workflow.js`, `gsd-t-integrate.workflow.js`, `gsd-t-debug.workflow.js`, `gsd-t-quick.workflow.js`, and `gsd-t-phase.workflow.js` all call `require('./_lib.js')` at the top level and crash immediately. The M71 lint test (`test/m71-workflow-runtime-native-lint.test.js`) only guards `gsd-t-scan.workflow.js`; the other six are outside the guard.
1126
+
1127
+ ### args Normalization (M71)
1128
+
1129
+ The Workflow runtime passes `args` as a JSON STRING (not a parsed object). Reading `args.projectDir` directly yields `undefined`. All workflow scripts must normalize first:
1130
+ ```js
1131
+ const _args = (typeof args === "string")
1132
+ ? (() => { try { return JSON.parse(args); } catch (_) { return {}; } })()
1133
+ : (args || {});
1134
+ const projectDir = _args.projectDir || ".";
1135
+ ```
1136
+
1137
+ ### Workflow Scripts (`templates/workflows/`)
1138
+
1139
+ | Script | Status | Purpose |
1140
+ |--------|--------|---------|
1141
+ | `gsd-t-scan.workflow.js` | Runtime-native (M71 migrated) | Volume-probe + deep-finder fan-out + synthesis + document |
1142
+ | `gsd-t-execute.workflow.js` | BROKEN (require at top level) | preflight + brief + disjointness + parallel domain workers + integrate + verify-gate |
1143
+ | `gsd-t-verify.workflow.js` | BROKEN (require + child_process) | M57 CI-parity + M58 test-data purge + orthogonal triad |
1144
+ | `gsd-t-wave.workflow.js` | BROKEN (unused lib import crashes) | composes execute + verify |
1145
+ | `gsd-t-integrate.workflow.js` | BROKEN (require at top level) | cross-domain wire-up + verify-gate |
1146
+ | `gsd-t-debug.workflow.js` | BROKEN (require at top level) | 2-cycle diagnose/fix/verify |
1147
+ | `gsd-t-quick.workflow.js` | BROKEN (require at top level) | preflight + brief + single-task + verify-gate |
1148
+ | `gsd-t-phase.workflow.js` | BROKEN (require at top level) | generic upper-stage runner (partition/plan/discuss/...) |
1149
+
1150
+ ### _lib.js (`templates/workflows/_lib.js`)
1151
+
1152
+ Shared helpers for Workflow scripts. CommonJS (uses `require`, `fs`, `path`, `spawnSync`). These helpers are called from INSIDE `agent()` stages (which are subagent processes that have full Node.js access), NOT at orchestrator top-level (which is the sandbox). Exports:
1153
+
1154
+ - `generateBrief({kind, milestone, domain, task, spawnId, projectDir})` - invokes `gsd-t brief` or local `bin/gsd-t-context-brief.cjs`, returns `{ok, briefPath, via}`.
1155
+ - `runPreflight({projectDir, checks})` - invokes `gsd-t preflight --json` or local `bin/cli-preflight.cjs`, returns preflight envelope.
1156
+ - `proveFileDisjointness({projectDir, domains})` - invokes `gsd-t parallel --dry-run --domain X --domain Y ...` (known bug: last-wins parseArgv discards all but last `--domain`).
1157
+ - `runVerifyGate({projectDir, skipUltra, skipUltraReason})` - invokes `gsd-t verify-gate --json`.
1158
+ - `loadProtocol(name)` - reads `templates/prompts/{name}-subagent.md` from the installed GSD-T package.
1159
+ - `readDomainTasks(projectDir, domain)` - reads `.gsd-t/domains/{domain}/tasks.md`.
1160
+ - `readScope(projectDir, domain)` - reads `.gsd-t/domains/{domain}/scope.md`.
1161
+
1162
+ Tool resolution: prefers `{projectDir}/bin/<tool>.cjs` (project-local), falls back to `gsd-t` on PATH (preserves M55-D5 project-local-bin invariant).
1163
+
1164
+ ### Orthogonal Validation Triad
1165
+
1166
+ Three non-substitutable validators run as `parallel()` `agent()` stages in `gsd-t-verify.workflow.js`. Per `.gsd-t/contracts/orthogonal-validation-contract.md` v1.0.0 STABLE:
1167
+
1168
+ | Validator | Model | Verdict | Skippable |
1169
+ |-----------|-------|---------|-----------|
1170
+ | `/code-review ultra` - cooperative correctness + cleanup | sonnet | important/nit/pre-existing | Yes (requires `skipUltraReason`; `skipUltra=true` is INELIGIBLE for VERIFIED) |
1171
+ | Red Team - adversarial/security/boundaries | opus | `FAIL` (any CRITICAL/HIGH) or `GRUDGING-PASS` | No |
1172
+ | QA - test mechanics + shallow-test detection + contract compliance | sonnet | pass/fail | No |
1173
+
1174
+ Design verification (4th stage) activates when `.gsd-t/contracts/design-contract.md` or `.gsd-t/contracts/design/` exists. Synthesis merges results without category collapse. Verdict: `VERIFIED` / `VERIFIED-WITH-WARNINGS` / `VERIFY-FAILED`.
1175
+
1176
+ **Known bug**: synthesis agent is the sole arbiter with no programmatic guard enforcing Red Team FAIL -> VERIFY-FAILED. A hallucinating synthesis agent could grant VERIFIED despite a Red Team FAIL.
1177
+
1178
+ ### Stack Rules Engine (M61 SC7)
1179
+
1180
+ `bin/rule-engine.js` + `bin/model-selector.js` + `templates/stacks/`.
1181
+
1182
+ - `rule-engine.js` - declarative JSONL rules in `.gsd-t/metrics/rules.jsonl`. Evaluates patterns against task-metrics data, manages activation tracking and patch lifecycle. Exports: `getActiveRules`, `evaluateRules`, `getPreMortemRules`, `getPatchTemplate`, `recordActivation`, `flagInactiveRules`, `consolidateRules`.
1183
+ - `model-selector.js` - maps GSD-T phases to model tiers (haiku/sonnet/opus). `selectModel({phase})` returns `{model, reason, escalation_hook}`. Contract: `.gsd-t/contracts/model-selection-contract.md` v1.0.0. Known drift: `plan` returns `sonnet` but contract declares `opus`; `impact`, `complete-milestone`, `scan`, `backlog-promote` fall through to sonnet default (unknown phase), contract says opus for first two.
1184
+ - `templates/stacks/` - stack-specific rules (react.md, typescript.md, etc.) + universal rules (`_security.md`, `_auth.md`, `_markdown.md`). Detection from `package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`. Known: Stack rules are NOT injected into M61 Workflow `agent()` spawns. The injection path (`bin/gsd-t-task-brief.js::detectStack()`) is only called in tests, not by production Workflows.
1185
+
1186
+ ### Patch Lifecycle (`bin/patch-lifecycle.js`)
1187
+
1188
+ Five-stage progression: `candidate` - `applied` - `measured` - `promoted` - `graduated`. Provides auto-improvement feedback loop from rule-engine findings to permanent methodology artifacts. Known bugs:
1189
+ - `applyPatch()` and `recordMeasurement()` are never called anywhere (only `createCandidate`, `checkPromotionGate`, `promote`, `graduate` exist in complete-milestone.md). No patch ever leaves `candidate`.
1190
+ - `improvement_pct` computed as `(after - before) / |before| * 100` - treats all metrics as higher-is-better. `fix_cycles` (lower is better) never promotes.
1191
+ - Graduation unreachable: `recordMeasurement` stops processing after `promote()` sets status to `promoted`; `measured_milestones.length` never grows post-promotion.
1192
+
1193
+ ### Codebase Scan Engine (M66/M67 redesign)
1194
+
1195
+ `templates/workflows/gsd-t-scan.workflow.js` is the ONLY correctly runtime-native Workflow script. Architecture:
1196
+
1197
+ ```
1198
+ preflight(agent) -> volume-probe(agent: sonnet) -> pipeline(deep-finder per slice -> single verify)
1199
+ -> synthesis(agent: opus, archive + write register + git)
1200
+ -> document(parallel per-doc agents: living docs + 5 dimension files + plain-english)
1201
+ -> render(agent: HTML report)
1202
+ ```
1203
+
1204
+ Fan-out: by codebase VOLUME (not fixed 5-teammate count). The probe decides actual slice count via cohesive sub-domain decomposition with a hard VOLUME-DERIVED CAP:
1205
+
1206
+ | Size | Cap |
1207
+ |------|-----|
1208
+ | tiny (5 files) | 3 |
1209
+ | mid (300 files) | 10 |
1210
+ | large (1809 files / ~1M LOC) | ~27 |
1211
+ | huge (10k+ files) | 50 |
1212
+
1213
+ `_args.maxSlicesHint` optionally overrides the cap. The orchestrator body does NO I/O - all reads/writes are inside `agent()` stages.
1214
+
1215
+ Known bugs in support modules (do not affect scan.workflow.js which calls agents with Bash access):
1216
+ - `bin/scan-renderer.js:tryD2()` line 73 writes literal `'app -> db: query'` stub instead of `mmdContent` parameter. D2 fallback always renders wrong content.
1217
+ - `bin/scan-schema-parsers.js::parseDrizzle()` - `colRe` runs against full file content instead of per-table block; all columns attributed to every table.
1218
+ - `bin/scan-data-collector.js::parseTechDebtItems()` - parses legacy prose format, not the current `### TD-NNN` section format. Tech Debt table in HTML report always empty.
1219
+
1220
+ ### Design-to-Code Pipeline
1221
+
1222
+ `bin/design-orchestrator.js` + `scripts/gsd-t-design-review-server.js`.
1223
+
1224
+ - `design-orchestrator.js` - reads design contracts, spawns builder agents, manages review queue. Known bugs: (a) `buildPrompt()` and `buildSingleItemPrompt()` hardcode "Vue 3 + TypeScript" regardless of actual project framework - breaks React/Svelte/Angular; (b) `guessPaths()` hardcodes `.vue` extensions; (c) element auto-correction silently mutates design contract files without user confirmation (Destructive Action Guard violation).
1225
+ - `gsd-t-design-review-server.js` - Node.js proxy + review queue server. Known bugs: (a) `/review/api/exclude` endpoint references `reviewQueue` variable that is never declared - throws `ReferenceError` on any exclusion; (b) `proxyRequest()` does not decompress gzip/brotli before string operations - script injection silently fails; (c) `item.id` used in file paths without sanitization - path traversal vulnerability.
1226
+
1227
+ ### Unattended Mode (M61 Retirement)
1228
+
1229
+ The M61 orchestrator-shell retirement removed `bin/headless-auto-spawn.cjs`, `bin/gsd-t-unattended-platform.cjs`, `bin/gsd-t-token-capture.cjs`, `bin/supervisor-pid-fingerprint.cjs`, `bin/event-stream.cjs`, and `bin/unattended-watch-format.cjs`. These are replaced by "Native background Workflows + /loop skill" per CHANGELOG v4.0.10.
1230
+
1231
+ Known CRITICAL bugs from this retirement:
1232
+ - `commands/gsd-t-unattended.md` and `commands/gsd-t-unattended-watch.md` still reference all five deleted modules. Any invocation throws `MODULE_NOT_FOUND` immediately.
1233
+ - `bin/gsd-t-parallel.cjs::runDispatch` at line 553 attempts `require('./headless-auto-spawn.cjs')`, silently catches `MODULE_NOT_FOUND`, and demotes every `fan_out` decision to `sequential`. Fan-out parallelism is permanently disabled in production.
1234
+ - `scripts/hooks/pre-commit-capture-lint` invokes `gsd-t capture-lint` (also retired). Any project with this hook installed has ALL commits blocked unconditionally.
1235
+
1236
+ ### Context Brief (M55 D4 / M56 extension)
1237
+
1238
+ `bin/gsd-t-context-brief.cjs` + `bin/gsd-t-context-brief-kinds/` (11 kind collectors).
1239
+
1240
+ Kinds: `design-verify`, `discuss`, `execute`, `impact`, `milestone`, `partition`, `plan`, `qa`, `red-team`, `scan`, `verify`. (Contract at `.gsd-t/contracts/context-brief-contract.md` still lists only 6 kinds from M55; not yet updated to reflect M56 additions.)
1241
+
1242
+ Fail-closed kinds (throw if required sources missing): `qa`, `red-team`, `design-verify`. `--strict` upgrades fail-open kinds to fail-closed.
1243
+
1244
+ Known bug in `verify.cjs` kind collector: regex uses `\Z` (not valid in JS - treated as literal 'Z'). When the Falsifiable Success Criteria section is the LAST section in the charter (the typical layout), the lookahead never matches and `successCriteria` is always empty.
1245
+
1246
+ ### Real-Time Agent Dashboard (updates post-M55)
1247
+
1248
+ Known bugs:
1249
+ - `scripts/gsd-t-dashboard-autostart.cjs` references `./gsd-t-dashboard-server.js` at line 132/145. That file does NOT exist in `scripts/`. `require()` throws `MODULE_NOT_FOUND` synchronously. Dashboard autostart feature is completely broken.
1250
+ - `scripts/gsd-t-stream-feed-server.js::ingestStream` accumulates incoming bytes with no size limit. Unbounded growth can OOM the server.
1251
+ - `encodeWsCloseFrame` encodes payload length directly into `header[1]` without checking the 125-byte RFC 6455 control-frame limit. Malformed close frames sent to clients.
1252
+
1253
+ ### Token Aggregator (updates)
1254
+
1255
+ `scripts/gsd-t-token-aggregator.js` known bugs:
1256
+ - `updateTokenLog()` column indices are hardcoded to a 12-column format with a 'Compacted' column that no longer exists. Actual token-log.md has 11 columns. The function has never successfully updated token-log.md since the schema diverged; it is a permanent silent no-op.
1257
+ - `runTail()` calls `writeTokenUsageJsonl()` (appendFileSync) on every group-count change. Each call appends ALL current rows - triangular duplication. A session with 10 task groups produces 55 rows instead of 10.
1258
+
1259
+ ### Watch-State Path Traversal (Security)
1260
+
1261
+ `scripts/gsd-t-watch-state.js` line 153 constructs the state file path as `path.join(_stateDir(cwd), agentId + '.json')`. `agentId` comes from `--agent-id` CLI arg or `GSD_T_AGENT_ID` env var with no containment check. An `agentId` of `../../evil` resolves outside `.gsd-t/.watch-state/`. Recommendation: validate `startsWith(path.resolve(stateDir) + path.sep)` and allowlist `[a-zA-Z0-9_-]` characters.
1262
+
1263
+ ### Update Check Hook
1264
+
1265
+ `scripts/gsd-t-update-check.js::fetchLatestVersion()` has a syntax error in the inline `node -e` script at line 40: `r.on('data',(c)=>d+=c;` missing the closing `)` for `r.on()`. Produces `SyntaxError` - always returns `null`. SessionStart hook never emits `[GSD-T AUTO-UPDATE]` or `[GSD-T UPDATE]` signals. The `gsd-t.js` CLI path (using `scripts/gsd-t-fetch-version.js` separately) is unaffected.
1266
+
1267
+ ### Date Guard (`scripts/gsd-t-date-guard.js`)
1268
+
1269
+ PreToolUse hook that blocks Write/Edit calls whose content contains timestamps drifting more than +/-5 minutes from the live system clock. Known false positive: on Write of progress.md containing historical decision-log entries (from `/gsd-t-log` full-reconstruction or `/gsd-t-populate`), the guard blocks writes containing entries dated more than 5 minutes ago.
1270
+
1271
+ ### Known Architecture Concerns (updated)
1272
+
1273
+ 1. **Workflow sandbox migration incomplete (CRITICAL)**: Six of seven workflow scripts crash immediately due to `require()` at top level. Only `gsd-t-scan.workflow.js` is correctly runtime-native.
1274
+ 2. **Fan-out parallelism silently disabled (CRITICAL)**: `gsd-t-parallel.cjs::runDispatch` falls back to sequential on every production call because `headless-auto-spawn.cjs` was retired but the require is still present.
1275
+ 3. **Multi-domain disjointness gate checks only last domain**: `parseArgv` last-wins bug means `proveFileDisjointness` only checks the last `--domain` argument when called with multiple domains.
1276
+ 4. **False-pass in verify-gate on runParallel throw**: `[].every()` vacuously returns `true` making `track2.ok = true` even when all CLI tools crashed.
1277
+ 5. **CLI single-file size**: `bin/gsd-t.js` well over 4,000 lines. Accepted deviation (zero-dep constraint).
1278
+ 6. **Four-file synchronization**: Any command change requires updating README, GSD-T-README, CLAUDE-global template, and gsd-t-help. Manual process.
1279
+ 7. **Stack rules not injected into Workflow agents**: Detection logic exists only in the legacy `bin/gsd-t-task-brief.js` path, which is not called by any production Workflow.
1280
+ 8. **Hardcoded Neo4j password**: `'gsdt-graph-2026'` in `bin/gsd-t.js` lines 1312/1350. Local-only impact but predictable credential.
1281
+ 9. **`spawnClaudeSession` missing `--dangerously-skip-permissions`**: debug-loop and ledger-compaction headless spawns exit on first tool use.
1282
+ 10. **`queryBacklog` parses wrong format**: Looks for `| ` table rows; actual backlog.md uses `## N. title` headings. Always returns empty.
1283
+
1067
1284
  ## Planned Architecture Changes (M23-M24)
1068
1285
 
1069
1286
  **M23: Headless Mode**
@@ -1073,13 +1290,6 @@ cache behaviour.
1073
1290
  **M24: Docker**
1074
1291
  - Dockerfile + docker-compose for containerized enterprise execution.
1075
1292
 
1076
- ## Known Architecture Concerns
1077
-
1078
- 1. **CLI single-file size**: bin/gsd-t.js at 1,438 lines exceeds the 200-line convention, but splitting adds complexity for questionable benefit given zero-dependency constraint. Accepted deviation.
1079
- 2. **Four-file synchronization**: Any command change requires updating README, GSD-T-README, CLAUDE-global template, and gsd-t-help. Manual process — no automated validation.
1080
- 3. **Pre-Commit Gate unenforced**: Mental checklist in CLAUDE.md, not a git hook or CI check.
1081
- 4. **Progress.md Decision Log growth**: Unbounded append-only log. May need periodic archival strategy for long-lived projects.
1082
-
1083
1293
  ## M46 Worker Sub-Dispatch
1084
1294
 
1085
1295
  `bin/gsd-t-worker-dispatch.cjs` lets an unattended supervisor worker iteration fan out its own file-disjoint tasks as concurrent sub-workers. The module's `dispatchWorkerTasks({projectDir, parentSessionId, tasks, maxParallel})` entry point gates on three conditions: `process.env.GSD_T_UNATTENDED_WORKER === '1'` (caller runs inside a supervisor-launched worker child), `tasks.length > 1`, and pairwise file-disjointness across the task set's `files` arrays. When all three hold, it emits a spawn-plan frame with `kind: 'unattended-worker-sub'` and delegates execution to `bin/gsd-t-parallel.cjs::runDispatch` — the same M44-verified instrument the in-session planner uses. When any condition fails it returns `{parallel: false, reason}` and the worker falls through to its existing serial path.