mindforge-cc 11.9.1 → 11.9.3

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.
Files changed (121) hide show
  1. package/.agent/CLAUDE.md +37 -13
  2. package/.agent/hooks/mindforge-block-no-verify.js +61 -13
  3. package/.agent/hooks/mindforge-config-protection.js +82 -3
  4. package/.agent/hooks/mindforge-context-monitor.js +1 -1
  5. package/.agent/hooks/mindforge-workflow-guard.js +2 -2
  6. package/.agent/hooks/run-with-flags.js +190 -20
  7. package/.agent/mindforge/browse.md +2 -2
  8. package/.agent/mindforge/checkpoint.md +1 -1
  9. package/.agent/mindforge/consult.md +1 -1
  10. package/.agent/mindforge/cost-report.md +1 -1
  11. package/.agent/mindforge/harness-audit.md +1 -1
  12. package/.agent/mindforge/orch-add-feature.md +1 -1
  13. package/.agent/mindforge/orch-build-mvp.md +1 -1
  14. package/.agent/mindforge/orch-change-feature.md +1 -1
  15. package/.agent/mindforge/orch-fix-defect.md +1 -1
  16. package/.agent/mindforge/orch-refine-code.md +1 -1
  17. package/.agent/mindforge/qa.md +2 -2
  18. package/.claude/CLAUDE.md +37 -13
  19. package/.claude/commands/mindforge/browse.md +2 -2
  20. package/.claude/commands/mindforge/checkpoint.md +1 -1
  21. package/.claude/commands/mindforge/consult.md +1 -1
  22. package/.claude/commands/mindforge/cost-report.md +1 -1
  23. package/.claude/commands/mindforge/harness-audit.md +1 -1
  24. package/.claude/commands/mindforge/orch-add-feature.md +1 -1
  25. package/.claude/commands/mindforge/orch-build-mvp.md +1 -1
  26. package/.claude/commands/mindforge/orch-change-feature.md +1 -1
  27. package/.claude/commands/mindforge/orch-fix-defect.md +1 -1
  28. package/.claude/commands/mindforge/orch-refine-code.md +1 -1
  29. package/.claude/commands/mindforge/qa.md +2 -2
  30. package/.mindforge/MINDFORGE-SCHEMA.json +126 -13
  31. package/.mindforge/config.json +4 -4
  32. package/.mindforge/engine/autonomous/headless-adapter.md +2 -2
  33. package/.mindforge/engine/cost-tracking/router.md +1 -1
  34. package/.mindforge/engine/cost-tracking/token-ledger.md +21 -24
  35. package/.mindforge/engine/temporal-protocol.md +2 -2
  36. package/.mindforge/governance/change-classifier.md +20 -4
  37. package/.mindforge/memory/sync-manifest.json +1 -1
  38. package/.mindforge/metrics/METRICS-SCHEMA.md +13 -4
  39. package/.mindforge/personas/cost-optimizer.md +2 -2
  40. package/.mindforge/personas/multi-model-bridge.md +1 -1
  41. package/.mindforge/skills/agent-architecture-audit/SKILL.md +2 -2
  42. package/.mindforge/skills/cost-aware-routing/SKILL.md +3 -3
  43. package/.mindforge/skills/multi-llm-consult/SKILL.md +2 -2
  44. package/.mindforge/skills/orch-pipeline/SKILL.md +4 -4
  45. package/CHANGELOG.md +402 -0
  46. package/MINDFORGE.md +13 -6
  47. package/README.md +51 -2
  48. package/RELEASENOTES.md +55 -2
  49. package/SECURITY.md +22 -3
  50. package/bin/autonomous/audit-writer.js +48 -33
  51. package/bin/autonomous/auto-runner.js +65 -2
  52. package/bin/change-classifier.js +151 -16
  53. package/bin/dashboard/api-router.js +28 -47
  54. package/bin/dashboard/error-response.js +44 -0
  55. package/bin/dashboard/frontend/app.js +429 -0
  56. package/bin/dashboard/frontend/index.html +14 -390
  57. package/bin/dashboard/metrics-aggregator.js +75 -30
  58. package/bin/dashboard/revops-api.js +12 -2
  59. package/bin/dashboard/server.js +245 -6
  60. package/bin/dashboard/sse-bridge.js +11 -8
  61. package/bin/dashboard/temporal-api.js +11 -5
  62. package/bin/engine/remediation-engine.js +12 -1
  63. package/bin/engine/sre-manager.js +1 -1
  64. package/bin/engine/temporal-cli.js +56 -6
  65. package/bin/engine/temporal-hub.js +41 -9
  66. package/bin/engine/verification-runner.js +134 -17
  67. package/bin/engine/verify-cli.js +25 -7
  68. package/bin/eval/eval-harness.js +212 -1
  69. package/bin/eval/golden-set-retrieval.json +9 -0
  70. package/bin/governance/approval-record.js +147 -0
  71. package/bin/governance/approve.js +12 -7
  72. package/bin/governance/policy-engine.js +41 -3
  73. package/bin/governance/policy-gate-hardened.js +36 -1
  74. package/bin/governance/verify-approvals.js +163 -0
  75. package/bin/harness-audit.js +224 -10
  76. package/bin/hindsight-injector.js +8 -2
  77. package/bin/hooks/instinct-capture-hook.js +19 -5
  78. package/bin/install.js +63 -3
  79. package/bin/installer/harness-adapter-compliance.js +339 -28
  80. package/bin/installer/hook-registration.js +504 -0
  81. package/bin/installer-core.js +451 -63
  82. package/bin/learning/instinct-cli.js +14 -24
  83. package/bin/memory/knowledge-capture.js +23 -3
  84. package/bin/memory/knowledge-graph.js +70 -31
  85. package/bin/memory/vector-hub.js +500 -44
  86. package/bin/migrations/0.6.0-to-1.0.0.js +30 -25
  87. package/bin/migrations/1.0.0-to-2.0.0.js +22 -23
  88. package/bin/mindforge-cli.js +110 -17
  89. package/bin/models/cost-tracker.js +126 -29
  90. package/bin/models/model-client.js +6 -1
  91. package/bin/models/model-router.js +28 -7
  92. package/bin/models/usage-record.js +71 -0
  93. package/bin/revops/debt-monitor.js +57 -13
  94. package/bin/security/trust-gate-hook.js +50 -6
  95. package/bin/skill-validator.js +6 -1
  96. package/bin/skills-builder/skill-scorer.js +46 -6
  97. package/bin/updater/self-update.js +6 -1
  98. package/bin/updater/version-comparator.js +21 -1
  99. package/bin/utils/file-lock.js +106 -0
  100. package/bin/utils/mindforge-params.js +124 -0
  101. package/bin/utils/mindforge-version.js +99 -0
  102. package/bin/utils/redact-secrets.js +106 -0
  103. package/bin/validate-config.js +75 -17
  104. package/bin/wizard/setup-wizard.js +4 -1
  105. package/bin/wizard/theme.js +9 -1
  106. package/changelogs/index.json +11 -9
  107. package/changelogs/v11.9.2.md +209 -0
  108. package/changelogs/v11.9.3.md +195 -0
  109. package/docs/References/config-reference.md +76 -14
  110. package/docs/References/sdk-api.md +1 -1
  111. package/docs/Templates/Codebase/architecture.md +1 -1
  112. package/docs/commands-reference.md +4 -5
  113. package/docs/faq.md +25 -5
  114. package/docs/getting-started.md +3 -3
  115. package/docs/sdk-reference.md +15 -7
  116. package/docs/troubleshooting.md +10 -6
  117. package/docs/user-guide.md +14 -14
  118. package/examples/sdk-integration/README.md +1 -1
  119. package/package.json +10 -4
  120. package/subagents/.claude-plugin/marketplace.json +1 -1
  121. package/bin/dashboard/approval-handler.js +0 -136
@@ -44,9 +44,25 @@ Scan the actual diff content, not only filenames, for patterns such as:
44
44
  This protects against security-critical code being added to innocuous filenames
45
45
  like `src/utils/helper.ts`.
46
46
 
47
- ### Signal C — AUDIT history patterns
48
- If the current phase has a recent HIGH or CRITICAL `security_finding`, the next
49
- change in that phase is elevated to Tier 3 automatically.
47
+ ### Signal C — AUDIT history patterns (SPECIFIED, NOT IMPLEMENTED)
48
+ Intended behaviour: if the current phase has a recent HIGH or CRITICAL
49
+ `security_finding`, the next change in that phase is elevated to Tier 3
50
+ automatically.
51
+
52
+ **This signal does not exist in `bin/change-classifier.js`.** It is recorded here
53
+ as a design intent, not as a live protection, because it would read from
54
+ `.planning/AUDIT.jsonl` — which is gitignored (`.gitignore:81`), untracked, and
55
+ absent from `package.json` `files[]`. That file therefore does not exist in the
56
+ fresh clone the classifier actually runs in
57
+ (`.github/workflows/control-plane.yml`). Implementing it against a source that is
58
+ structurally unavailable at the point of enforcement would produce a signal that
59
+ silently never fires — the same defect class as the Signal B gap above, where 13
60
+ of the 19 documented patterns were specified and absent.
61
+
62
+ The `security_finding` event itself is real and carries `severity`: see
63
+ `bin/dashboard/metrics-aggregator.js:160` and `bin/revops/debt-monitor.js:23`,
64
+ both of which read it from a local audit log. Enabling Signal C needs a decision
65
+ about how phase history reaches CI, not merely classifier code.
50
66
 
51
67
  ## Classification audit entry
52
68
  Record why the tier was selected:
@@ -56,7 +72,7 @@ Record why the tier was selected:
56
72
  "event": "change_classified",
57
73
  "tier": 3,
58
74
  "classification_reason": "code pattern: jwt.sign found in src/utils/helper.ts",
59
- "signals_checked": ["file_path", "code_content", "audit_history"],
75
+ "signals_checked": ["file_path", "code_content"],
60
76
  "signal_triggered": "code_content",
61
77
  "pattern_matched": "jwt.sign"
62
78
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "pattern-library.jsonl": {
3
- "lastSync": "2026-07-29T10:18:46.944Z",
3
+ "lastSync": "2026-08-21T12:02:25.078Z",
4
4
  "localCount": 1
5
5
  }
6
6
  }
@@ -1,13 +1,22 @@
1
1
  # MindForge Metrics — Schema Reference
2
2
 
3
3
  ## Files
4
- - `session-quality.jsonl`
5
- - `phase-metrics.jsonl`
6
- - `skill-usage.jsonl`
7
- - `compaction-quality.jsonl`
4
+ - `session-quality.jsonl` — **no producer in this repo**; every reference to it
5
+ (`bin/dashboard/metrics-aggregator.js`, `sdk/src/client.ts`,
6
+ `mcp-server/src/vendor/client.ts`) is a READ. Expected to be supplied by the
7
+ agent/host; MindForge only consumes it.
8
+ - `phase-metrics.jsonl` — no producer in this repo
9
+ - `skill-usage.jsonl` — no producer in this repo
10
+ - `compaction-quality.jsonl` — no producer in this repo
11
+ - `token-usage.jsonl` — **code-written** by `bin/models/cost-tracker.js`; canonical
12
+ shape is `bin/models/usage-record.js`. Cost lives in `cost_usd` and nowhere else.
13
+ Gitignored and excluded from the npm tarball.
8
14
 
9
15
  All files are append-only JSONL.
10
16
 
17
+ Per-session cost is NOT a `session-quality.jsonl` field: the dashboard joins it
18
+ from `token-usage.jsonl` on `session_id`.
19
+
11
20
  ## session-quality.jsonl fields
12
21
  - session_id, date, phase, developer_id
13
22
  - tasks_attempted, tasks_completed, tasks_failed
@@ -39,7 +39,7 @@ Map score to model tier via the routing decision matrix.
39
39
  </step>
40
40
 
41
41
  <step name="check_budget">
42
- Read token-ledger.jsonl for current session/project spend.
42
+ Read token-usage.jsonl for current session/project spend.
43
43
  Compare against budget limits in config.json.
44
44
  If approaching warn threshold: flag to user.
45
45
  </step>
@@ -66,6 +66,6 @@ Recommend routing adjustments for next session.
66
66
  - NEVER skip security overrides to save money (auth/payment always >= standard tier)
67
67
  - NEVER exceed hard budget limit without explicit user approval
68
68
  - NEVER silently downgrade model quality — always inform
69
- - Track every model interaction in token-ledger.jsonl
69
+ - Track every model interaction in token-usage.jsonl
70
70
  - Report cost transparency in every session summary
71
71
  </critical_rules>
@@ -82,5 +82,5 @@ Report to user with:
82
82
  - ALWAYS attribute responses to their source model
83
83
  - Maximum 2000 tokens per external prompt (cost control)
84
84
  - Maximum 3 consultations per session (rate limiting)
85
- - Log every external call in token-ledger.jsonl
85
+ - Log every external call in token-usage.jsonl
86
86
  </critical_rules>
@@ -79,7 +79,7 @@ audit has a real target, not an abstraction.
79
79
  | 9 | Answer shaping | SWARM-SUMMARY consolidation | Format corruption in the final response |
80
80
  | 10 | Platform rendering | Dashboard (localhost:7339) / CLI / API transport | Transport-layer mutation of a valid answer |
81
81
  | 11 | Hidden repair loops | soul-engine ADS rewrite + Temporal hindsight regeneration | Silent fallback/retry running a second LLM pass |
82
- | 12 | Persistence | auto-state.json + Merkle audit log | Expired state or cached artifacts reused as live evidence |
82
+ | 12 | Persistence | auto-state.json + hash-chained audit log | Expired state or cached artifacts reused as live evidence |
83
83
 
84
84
  ### Common Failure Patterns
85
85
 
@@ -148,7 +148,7 @@ Define what you're auditing:
148
148
  Gather evidence from the codebase:
149
149
  - **Source code** — swarm loop, hooks_route tool router, shard admission, prompt
150
150
  assembly across the source-of-truth hierarchy
151
- - **Logs** — NexusTracer session traces, Merkle-linked AUDIT entries, tool-call
151
+ - **Logs** — NexusTracer session traces, hash-chained AUDIT entries, tool-call
152
152
  records
153
153
  - **Config** — MINDFORGE.md parameters, tool schemas, PersonaFactory patches,
154
154
  provider settings
@@ -62,7 +62,7 @@ for cost-performance tradeoffs, or when budget limits are approaching.
62
62
  ### Budget Monitoring
63
63
 
64
64
  Check budget status regularly:
65
- - Session budget remaining: from token-ledger.jsonl
65
+ - Session budget remaining: from token-usage.jsonl
66
66
  - Warning threshold: `[COST_WARN_USD]` from config
67
67
  - Hard limit: `[COST_HARD_LIMIT_USD]` from config
68
68
 
@@ -72,12 +72,12 @@ Check budget status regularly:
72
72
  - Never exceed hard limit without explicit user approval
73
73
 
74
74
  ### After any task
75
- - Log actual model used + tokens consumed to token-ledger.jsonl
75
+ - Log actual model used + tokens consumed to token-usage.jsonl
76
76
  - Compare actual vs optimal tier (for future routing accuracy)
77
77
  - Report cost in session summary
78
78
 
79
79
  ## Self-check before task completion
80
80
  - [ ] Did I log the model routing decision with rationale?
81
- - [ ] Did I record actual token usage in token-ledger.jsonl?
81
+ - [ ] Did I record actual token usage in token-usage.jsonl?
82
82
  - [ ] Did I check remaining budget against session/project limits?
83
83
  - [ ] Did I flag any tasks where a cheaper model could have been used?
@@ -57,7 +57,7 @@ multiple AI providers, or when the user explicitly requests cross-model consulta
57
57
  ```
58
58
 
59
59
  ### During consultation
60
- - Log every external call in token-ledger.jsonl (model, tokens, cost)
60
+ - Log every external call in token-usage.jsonl (model, tokens, cost)
61
61
  - Never send more than 2000 tokens to external models per consultation
62
62
  - If a model is unavailable: skip it, note in output, continue with available models
63
63
  - Respect rate limits — max 3 consultations per session
@@ -70,6 +70,6 @@ multiple AI providers, or when the user explicitly requests cross-model consulta
70
70
 
71
71
  ## Self-check before task completion
72
72
  - [ ] Did I sanitize the prompt before sending to external models?
73
- - [ ] Did I log every external call in token-ledger.jsonl?
73
+ - [ ] Did I log every external call in token-usage.jsonl?
74
74
  - [ ] Did I attribute responses to their source model (no unattributed blending)?
75
75
  - [ ] Did I remind the user that external opinions are advisory?
@@ -128,7 +128,7 @@ Each phase delegates — it does not do the work inline.
128
128
  and `security-auditor` / `penetration-tester` whenever the diff touches a
129
129
  security trigger.
130
130
  - **6. Commit** — conventional commits (`feat:` / `fix:` / `refactor:` / …), one
131
- per logical chunk, **+ a Merkle-linked AUDIT.jsonl entry per commit**. → **GATE 2.**
131
+ per logical chunk, **+ a hash-chained AUDIT.jsonl entry per commit**. → **GATE 2.**
132
132
 
133
133
  ---
134
134
 
@@ -166,7 +166,7 @@ This family is **gated, not autonomous**:
166
166
  work, the manual security overhead is completed here before approval.
167
167
  2. **GATE 2 — before Commit.** Present the diff summary and proposed conventional
168
168
  commit messages; do not commit until the user confirms. Each confirmed commit
169
- writes a Merkle-linked AUDIT.jsonl entry (below).
169
+ writes a hash-chained AUDIT.jsonl entry (below).
170
170
 
171
171
  Everything between the gates flows without stopping.
172
172
 
@@ -227,7 +227,7 @@ On user confirmation at Gate 2, for **each** logical commit:
227
227
 
228
228
  1. Commit with a **conventional** message scoped to one logical change:
229
229
  `feat(<scope>): …` / `fix(<scope>): …` / `refactor(<scope>): …` / etc.
230
- 2. Append a **Merkle-linked** AUDIT.jsonl entry to `.planning/AUDIT.jsonl`. Each
230
+ 2. Append a **hash-chained** AUDIT.jsonl entry to `.planning/AUDIT.jsonl`. Each
231
231
  entry sets `previous_hash` to the prior entry's `_hash` and computes its own
232
232
  `_hash` (per `.mindforge/audit/AUDIT-SCHEMA.md`):
233
233
 
@@ -263,7 +263,7 @@ On user confirmation at Gate 2, for **each** logical commit:
263
263
  security trigger was touched; `/mindforge:security-scan` passed PRE-COMMIT
264
264
  with no unaddressed Medium+ findings.
265
265
  - [ ] Commits are conventional and scoped to one logical change.
266
- - [ ] Each commit wrote a Merkle-linked AUDIT.jsonl entry (`previous_hash`/`_hash`).
266
+ - [ ] Each commit wrote a hash-chained AUDIT.jsonl entry (`previous_hash`/`_hash`).
267
267
  - [ ] New / changed behavior has tests; coverage ≥ 80%.
268
268
 
269
269
  ---
package/CHANGELOG.md CHANGED
@@ -1,5 +1,407 @@
1
1
  # Changelog
2
2
 
3
+ ## [11.9.3] — 2026-08-21 — Honesty: gates that can fail, commands that run, a release path that is checked
4
+
5
+ Patch release. No new features. Twenty-one fixes, and they all turned out to be the
6
+ same defect: **an instrument reported success while doing nothing.** Gates that could
7
+ not fail, tests satisfied by a comment, docs describing capabilities with no code
8
+ behind them, commands printing success while performing no action, and a publish path
9
+ that no check ever touched.
10
+
11
+ Contains behaviour changes under a patch bump — several of the things being fixed were
12
+ bugs that a consumer could have been relying on. Read BREAKING before upgrading if you
13
+ script against the CLI or the installer.
14
+
15
+ ### BREAKING
16
+
17
+ Each of these is a bug fix whose correct behaviour differs from the shipped behaviour.
18
+
19
+ - **Routed CLI commands now act on YOUR project, not MindForge's own checkout.**
20
+ `bin/mindforge-cli.js` passed `cwd: ROOT` to every routed command, so `mindforge
21
+ classify` diffed MindForge's repository instead of yours, and `mindforge health`
22
+ inspected MindForge's `node_modules`. Measured across all 27 routed commands: 7
23
+ changed behaviour, all in the correct direction, none regressed. If you parsed output
24
+ that happened to describe MindForge itself, it now describes your project. (#201)
25
+
26
+ - **`npx mindforge-cc install` — and any other positional argument — now exits 1.**
27
+ The installer takes flags only and silently ignored stray words, so
28
+ `npx mindforge-cc install` appeared to work while installing nothing configured.
29
+ It now refuses with the correct form. `--runtime`'s value token is still accepted.
30
+ Use `npx mindforge-cc --claude --local`. (#202)
31
+
32
+ - **`mindforge verify` now SKIPS unavailable stages instead of failing them.** A project
33
+ with no ESLint config, no test script or no `bin/verify-audit.js` was reported as
34
+ FAILING those stages rather than as not having them. If your CI relied on a non-zero
35
+ exit in those cases, it will now pass. A run in which every stage skipped prints a
36
+ "NOTHING WAS VERIFIED" banner rather than a clean bill of health. (#204)
37
+
38
+ - **`scripts/sync-version.js` now exits non-zero when the plugin build artifacts are
39
+ stale.** A bump used to report `✅ every derivable channel is at <version>` and exit 0
40
+ while leaving `npm test` red. If you script this, handle the new exit code — it means
41
+ "run the build chain it just printed". (#211)
42
+
43
+ - **A self-install no longer writes over your tracked files.** Running the installer
44
+ inside a MindForge checkout printed that it was skipping and then overwrote 149
45
+ tracked files, including `CLAUDE.md`, `.claude/**`, `.agent/**` and `.mindforge/**`.
46
+ The skip is now honoured for local scope. (#200)
47
+
48
+ - **Releases must be tagged on a commit reachable from `main`.** The release workflow
49
+ now refuses a tag that is not an ancestor of `origin/main`. The documented flow is
50
+ develop → release → main; tagging elsewhere previously published, with provenance
51
+ attesting to that tree. (#216)
52
+
53
+ ### Fixed
54
+
55
+ **Installer**
56
+
57
+ - A self-install claimed to skip and then overwrote 149 tracked files. The gate is now
58
+ scope-aware (`isSelfInstall() && scope === 'local'`). (#200)
59
+ - Every `--global` install reported failure on a correct run: `verifyInstall` demanded
60
+ six `bin/**` paths regardless of scope, so a global install ended
61
+ `❌ 6 of 12 required file(s) missing` and exit 1, with a `--force` retry that could
62
+ not help. A global install writes 389 files to `$HOME/.claude` and, deliberately,
63
+ zero to `bin/`. (#210)
64
+ - 11 of 27 routed CLI verbs died on `MODULE_NOT_FOUND` in a real install: the router
65
+ shipped but 6 of the scripts it dispatches to did not. `coreFiles` grew from 2 entries
66
+ to 8. (#210)
67
+ - Two leaks: `/tmp` staging files left behind on abandoned runs, and developer runtime
68
+ state (`celestial.db`, `.browser-daemon-token`) copied into consumer projects.
69
+ `SENSITIVE_EXCLUDE` now covers both. (#210)
70
+ - The forge commands overwrote three `mindforge` commands of the same name. (#197)
71
+ - The documented default install did not deliver the CLI it documents. (#196)
72
+
73
+ **Versioning and release**
74
+
75
+ - `sync-version.js --fetch-sha` hashed npm's 404 error body. For an unpublished version
76
+ the registry answers `{"error":"Not found"}` and `curl -sL` exits 0, so the digest
77
+ written into the Homebrew formula was the SHA-256 of that error text — the same
78
+ constant for every unpublished version — and `--check` then passed. Now `curl -fsSL`
79
+ plus a gzip magic-byte check, and it refuses rather than writing a digest no artifact
80
+ can match. (#203)
81
+ - The Homebrew formula may now LAG canonical but never LEAD it. Requiring equality
82
+ before publishing required something impossible: the digest is the hash of a tarball
83
+ that does not exist yet, and `npm test` blocked the publish that would have made it
84
+ satisfiable. (#208)
85
+ - Semver comparison is numeric per component. Lexicographically, `11.10.0` reads as
86
+ *behind* `11.9.2` — wrong on exactly the first release past a `.9` minor. (#208)
87
+ - Three version channels had no writer at all, so `npm test` failed on every bump and
88
+ the documented remedy could not fix it: `mcp-server/server.json` (both keys, matched
89
+ by identifier), `AGENTS.md`, and `sdk/README.md`'s second shape. (#207, #211)
90
+ - **No channel covered a document a user receives.** `SECURITY.md` — the security policy
91
+ at the root of the published package — said "Current version: 11.9.0", and
92
+ getting-started, faq, troubleshooting, user-guide and sdk-reference all titled
93
+ themselves v11.9.0: three releases stale, while every npm manifest was correct.
94
+ `--check` was green throughout, because a channel that does not exist cannot drift.
95
+ Structural markers now track canonical; narrative measurements deliberately do not.
96
+ (#211)
97
+ - A bump is not finished when `sync-version.js` exits. Two tracked artifacts are gated
98
+ against `package.json` and only a build can write them —
99
+ `plugins/mindforge/.claude-plugin/plugin.json` and
100
+ `plugins/mindforge/mcp/dist/index.js`. They are now reported under
101
+ `🔨 REQUIRE A BUILD` with the exact three-command chain, which nothing had documented.
102
+ (#211)
103
+ - `sync-version.js` reported "a channel is AHEAD of canonical" whenever its exit code
104
+ was non-zero for any reason, so the `--fetch-sha` refusal for an unpublished tarball
105
+ claimed the formula LEADS canonical in the same run that printed "DEFERRED until after
106
+ publish (behind, not ahead)". (#211)
107
+ - `changelogs/index.json`, which `bin/updater/changelog-fetcher.js` reads as the
108
+ authoritative version list, was missing 11.9.2. (#218)
109
+
110
+ **Publishing**
111
+
112
+ - **The tag push that publishes was exempt from every gate.** Publishing is triggered by
113
+ exactly one event — a `v*` tag push — and the repository's only ruleset targets
114
+ branches, so its six required checks applied to nothing on the path that ships. GitHub
115
+ cannot attach required status checks to a tag. A `preflight` job now gates it. (#216)
116
+ - The `stable` npm dist-tag was moved by hand, or not at all — it sat four releases
117
+ behind `latest` (11.8.3 against 11.9.2), so `npm i mindforge-cc@stable` delivered a
118
+ build with none of the 11.9.x fixes. The release workflow now moves it as its final
119
+ step: forward-only, prereleases skipped, and verified against npm's uncached dist-tags
120
+ endpoint rather than the CDN-cached packument. (#216)
121
+
122
+ **Dashboard**
123
+
124
+ - `--status` and `--stop` were documented in nine places and implemented in none; both
125
+ printed nothing and exited 0. Now implemented, before `express` is required, so they
126
+ work without the dependency installed. (#206)
127
+ - `--stop` identified the target by the SHAPE of its command line, which matched any
128
+ `node <anything>/dashboard/server.js` — verified against
129
+ `node /var/www/unrelated_app/dashboard/server.js`. It now resolves the script's
130
+ realpath and compares it to its own. (#206)
131
+ - `--status` printed a port it could not know: the PID file records only the pid, so it
132
+ reported whatever port that invocation happened to receive. Measured, `--status` on a
133
+ server started with `--port 7466` printed "port 7339". (#206)
134
+
135
+ **Memory**
136
+
137
+ - Every abandoned exit left a full copy of the database on disk — 1.8 GB of orphaned
138
+ `.tmp` files. (#199)
139
+ - The SDK's WebSocket client took the caller's process down on a failed reconnect. (#191)
140
+
141
+ **Verification**
142
+
143
+ - `mindforge verify`'s lint stage used `--max-warnings=0`, which made it impossible to
144
+ pass in the repository it ships from: `npx eslint .` reports 199 problems / 0 errors /
145
+ 199 warnings, so `verify` reported a lint FAILURE on a tree that is green by the
146
+ project's own contract. Aligned with the project's definition; errors still fail. (#204)
147
+ - `temporal cleanup` printed "🧹 Cleaning up old temporal snapshots..." and
148
+ "✅ Cleanup complete." with no cleanup between them. Now wired to
149
+ `TemporalHub.gc({maxSnapshots: 50, maxAgeDays: 30})` with `--dry-run` and honest
150
+ counts, including zero. (#209)
151
+
152
+ **Documentation that named things that do not exist**
153
+
154
+ - The protocol files instructed the agent to run `soul-engine.js` and
155
+ `shard-controller.js`, neither of which exists anywhere in the package. Those steps
156
+ are reasoning protocols and now say so. (#205)
157
+ - Fifteen phantom `/mindforge:` slash commands in shipped docs. A reader following
158
+ `docs/user-guide.md` typed `/mindforge:personas --list` and got nothing. They were not
159
+ typos: `.agent/workflows/` holds 130 tracked files using those exact names — an old
160
+ target layout, committed and orphaned, shipping zero files. (#209)
161
+ - Four documented CLI invocations could not be run, each verified by running it:
162
+ `npx mindforge-cc@latest install` (exit 1), `mindforge-cli.js dashboard` (exit 1),
163
+ `npx mindforge auto` in a shipped engine doc (`auto` is a slash command, never a CLI
164
+ verb), and `@mindforge <verb>`, a syntax that exists nowhere. (#213)
165
+ - `workflow` is the most-documented CLI verb in the project and works, but appeared in
166
+ neither `--help` nor the "Available commands" list, so a user who mistyped it was told
167
+ it does not exist. (#213)
168
+ - Root `CLAUDE.md` named `bin/hooks/mindforge-context-monitor.js`; the file is under
169
+ `.agent/hooks/`. (#214)
170
+
171
+ ### Added
172
+
173
+ - **`preflight` job on the release workflow.** Asserts the tagged commit is an ancestor
174
+ of `origin/main`, then runs the six gates a tag push never saw, with the publish job
175
+ behind `needs:`. (#216)
176
+ - **Automatic `stable` dist-tag movement**, forward-only and verified. (#216)
177
+ - **`node bin/dashboard/server.js --status` / `--stop`.** Not CLI verbs —
178
+ `mindforge-cli.js dashboard` does not route. (#206)
179
+ - **`mindforge temporal cleanup --dry-run`.** (#209)
180
+ - New regression gates, each falsified by mutation before being trusted:
181
+ `tests/protocol-claims.test.js` (no exemption list, deliberately — a name-keyed
182
+ allowlist was shown to excuse the exact defect it was written for), the shipped-doc
183
+ phantom-command gate, the CLI-verb gate, the authority-doc `.js` gate, the
184
+ version-channel round trips, and assertions that the release preflight itself cannot
185
+ be silently removed.
186
+
187
+ ### Notes for operators
188
+
189
+ - `npm run version:check` is the offline drift check. A bump is finished only when
190
+ `sync-version.js` exits 0 — if it prints `🔨 REQUIRE A BUILD`, run the three commands
191
+ it names and commit both regenerated files.
192
+ - Releases are now gated on being tagged from `main`. One residual, inherent to
193
+ tag-triggered workflows: a tag push resolves the workflow from the TAGGED ref, so a
194
+ tag placed on a commit predating this release runs that commit's workflow and is
195
+ ungated.
196
+
197
+ ## [11.9.2] — 2026-08-16 — Correctness: audit-chain integrity, dashboard crash policy, secret scanning
198
+
199
+ Patch release. No new features. Correctness work closing defects found by a
200
+ multi-agent audit of v11.9.1, plus the regression suites that keep them closed.
201
+ Contains a breaking change to the dashboard HTTP surface — see BREAKING below.
202
+
203
+ ### BREAKING
204
+
205
+ Shipped under a PATCH bump. The break is confined to the dashboard's own HTTP
206
+ surface, which binds to 127.0.0.1 only — but if you script against it, read this.
207
+
208
+ - **Dashboard error responses changed shape.** `detail` is removed from 5 endpoints and
209
+ raw errno strings from 10 more; `correlation_id` is added to 15; a malformed request
210
+ body now returns `application/json` instead of express's `text/html` error page.
211
+ Anything parsing `detail` must correlate on the logged `correlation_id` instead. This
212
+ was deliberate — those fields leaked absolute filesystem paths, and therefore the
213
+ operator's username and home directory, into an unauthenticated response body
214
+ (`requireAuth` exempts GET).
215
+ - **The dashboard now EXITS on an unhandled rejection or uncaught exception** where
216
+ 11.9.1 logged and continued. If you supervise the process, expect restarts where you
217
+ previously saw a logged error. Rationale in the Fixed section below: log-and-continue
218
+ held client sockets open until the client timed out, and had made `shutdown()` swallow
219
+ a throwing token unlink and keep serving the authenticated mutation API after SIGTERM.
220
+ - **`node bin/validate-config.js` and `mindforge security-scan` can now fail.** They
221
+ previously reported `MINDFORGE.md valid — 0 settings configured` and exited 0 on every
222
+ input. If you run either in CI, a genuinely invalid registry will now red-line where it
223
+ used to pass. Note this reaches **fresh installs and `--force` reinstalls only** — the
224
+ installer does not overwrite an existing `.mindforge/MINDFORGE-SCHEMA.json`, so a plain
225
+ upgrade keeps the old permissive schema.
226
+
227
+ ### Fixed
228
+
229
+ - **`security-scan` could not fail.** `bin/validate-config.js` and
230
+ `bin/models/model-router.js` each parsed `MINDFORGE.md` with a plain `KEY=value` regex, but
231
+ the registry declares its 43 parameters as bracketed `[KEY] = value`. Every schema property
232
+ resolved to `undefined` and short-circuited, so the command reported
233
+ `MINDFORGE.md valid — 0 settings configured` and exited 0 on any input. The schema also had
234
+ no `required` key at all. Both parsers now share `bin/utils/mindforge-params.js`, which also
235
+ accepts the legacy plain form (`examples/starter-project/MINDFORGE.md` ships 28 such lines),
236
+ and the schema declares real `required`/`recommended` sets.
237
+ **Behaviour change for consumers:** three CI gates go from unfailable to failable —
238
+ `.github/workflows/mindforge-ci.yml:38`, `.gitlab-ci-mindforge.yml:12`, and
239
+ `.github/workflows/control-plane.yml:100`. If one red-lines on a valid value, the schema
240
+ bound is wrong; do not "fix" it by editing `MINDFORGE.md`. Model routing is unchanged —
241
+ 30 persona x tier combinations resolve identically.
242
+ - **Trace retrieval returned nothing usable.** Queries were wrapped as a single FTS phrase, so
243
+ any query containing one absent term scored zero; and `traces_search` was keyed on `trace_id`
244
+ rather than the primary key, so each span's DELETE evicted the previous span and only the last
245
+ span per trace stayed searchable — 2,270 of 5,117 content-bearing traces, 44.4%, unsearchable.
246
+ Queries are now tokenised, OR-joined and ranked by tf-idf (`matchinfo('pcnx')`); the index is
247
+ re-keyed and rebuilt losslessly from the base table. `bin/eval/eval-harness.js` and its golden
248
+ set had zero callers and are now reachable as `npm run eval:retrieval`, with the baseline
249
+ committed: mean recall@10 0.6417, nDCG 0.5698 over 519 documents.
250
+ - **The cost ledger reported two totals for one concept.** `sum(cost_usd)` was $13.73 while
251
+ `sum(total_cost_usd)` was $0.00, and `tests/dashboard.test.js` wrote the reader's field name,
252
+ so the mismatch tested green. `bin/models/usage-record.js` is now the single definition of the
253
+ ledger path, record shape, per-entry cost and day bucket. The configured `ledger_path` pointed
254
+ at `token-ledger.jsonl`, a file that has never existed; that ghost filename had spread to 17
255
+ places across 13 files and is now absent. The dashboard cost tile no longer renders `$0.00`
256
+ on a 500 — it had no `res.ok` check, and because errors return well-formed JSON the catch
257
+ never fired, making an outage indistinguishable from zero spend.
258
+ A maintainer tool, `scripts/purge-synthetic-usage.js`, removes fixture rows: dry-run by
259
+ default, backs up first, idempotent, and aborts leaving the ledger untouched if the rewrite
260
+ fails. It is run from a repository checkout — `scripts/` is not in the published tarball, so
261
+ installed consumers do not have it.
262
+ - **Audit hash chain could fork under concurrent writers.** `bin/autonomous/audit-writer.js`
263
+ read the chain head and appended with no mutual exclusion, and cached the head in-process
264
+ indefinitely — so once a second process appended, the first kept chaining from a superseded
265
+ hash. Added `bin/utils/file-lock.js` (a fail-closed advisory lock promoted from
266
+ `bin/learning/instinct-cli.js`, deliberately NOT from `.agent/bin/lib/state.cjs`, which
267
+ writes anyway when the lock cannot be taken) held across read-head-through-fsync, and made
268
+ the cached head carry the file size that witnesses it is still the tail. 8 concurrent
269
+ appenders went from 199 broken links + 4 forks per 200 entries to 0. A lock alone was
270
+ measured insufficient — it still left 2 breaks and 1 fork, because the stale cache is a
271
+ second, independent defect.
272
+ - **Knowledge-graph edge updates were lost under concurrency.** `deprecateEdge`,
273
+ `reinforceEdge` and `applyDecay` in `bin/memory/knowledge-graph.js` each did
274
+ `readAllEdges()` -> mutate -> append with no lock, and `addEdge` appended unserialised
275
+ against them. Measured at HEAD over 4 runs of 8 processes x 20 `reinforceEdge` calls:
276
+ 93-129 of 160 increments lost, final `traversal_count` 31-67 instead of 160. All four
277
+ write paths now hold the `graph-edges.jsonl` lock across read-through-append; the same
278
+ probe then loses 0 of 160 in every run, with no lock-acquisition failures.
279
+ - `bin/governance/policy-engine.js`: `logAudit`'s un-awaited audit write now has a
280
+ `.catch()` — a lock-contention failure is reported at the decision site instead of
281
+ escaping as an unhandled rejection.
282
+ - `bin/hooks/instinct-capture-hook.js` appended to the instinct store without the lock that
283
+ `instinct-cli`'s prune/import rewrite holds, so a hook append landing in that window was
284
+ clobbered by the rename. It now takes the same lock.
285
+ - `tests/v7-sovereign-security.test.js`: `new PolicyEngine()` no longer defaults
286
+ `planningDir` to `process.cwd()`, which appended test verdicts to the operator's real
287
+ `.planning/RISK-AUDIT.jsonl`.
288
+ - Packaging: `package.json` files[] now excludes `**/*.lock` so a lockfile orphaned by a
289
+ hard kill cannot leak into the npm tarball (verified: without the negation, a
290
+ `.mindforge/memory/graph-edges.jsonl.lock` does ship).
291
+
292
+ - **Audit-chain forgery via un-awaited rollback.** `HindsightInjector.inject` called
293
+ the async `TemporalHub.rollbackTo` without `await`, so its rejection escaped the
294
+ surrounding `try/catch` while execution continued: a failed rollback still fsync'd a
295
+ hash-chained `hindsight_injected` entry and flipped `auto-state.json` to
296
+ `awaiting_regeneration` for something that never happened. The log gained a
297
+ cryptographically valid record of a non-event, and `verify-audit` reported the chain
298
+ valid — valid and wrong.
299
+ - **CLI `defaultArgs` were replaced by user arguments, not prepended.** `mindforge
300
+ health <anything>` lost `--check` and fell through to `installer-core`'s real
301
+ `install()` with `force: true`. Now prepended.
302
+ - **`_verifyMetadata` compared UTF-16 code units, not bytes**, so a 64-unit / 65-byte
303
+ `integrity` still threw `RangeError` — and the caller degraded that throw into
304
+ "proceeding without integrity check" and restored the snapshot anyway. Read and
305
+ verify are now separate stages; only a genuinely absent `SNAPSHOT-META.json` reaches
306
+ the tolerant path.
307
+ - **Dashboard `RevOpsAPI` was required but never mounted**, so `/api/revops/overview`
308
+ 404'd while the AgRevOps panels and docs described it as live. Even mounted it threw:
309
+ `getAuditEntries()` returns `{entries,total,limit,offset}` and three engines call
310
+ `.filter()` on it.
311
+ - **Dashboard leaked error internals to clients.** `err.message` reached response
312
+ bodies from 14 sites (`api-router.js` ×10, `temporal-api.js` ×3, `revops-api.js` ×1);
313
+ for fs-sourced errors that string carries absolute paths, disclosing the operator's
314
+ username and home directory. All sites now log server-side and return a generic
315
+ message plus a `correlation_id`, behind a 4-arg terminal handler that stops express
316
+ rendering `err.stack` when `NODE_ENV !== 'production'`.
317
+ - **Test runner discovery was a flat `readdirSync`**, so any suite in a subdirectory was
318
+ invisible. Now a recursive walk that prunes `tmp-*` / `node_modules` / dot
319
+ directories — directories only, never files.
320
+ - Three orphan files removed: one truncated `.planning/AUDIT.jsonl` to zero, one
321
+ overwrote `.planning/STATE.md`, one called a function absent from `bin/`. Recursion
322
+ made the `STATE.md` clobberer reachable by a single in-place rename; the other two
323
+ were unreachable by the runner at any depth. **The claim in `5177225`'s message that
324
+ all three were newly armed by recursion is correct for one of the three and
325
+ over-attributed for the other two.**
326
+ - Three relocated demos kept one-level-up requires after moving a directory deeper, so
327
+ all three exited 1; corrected to `../../bin/`.
328
+
329
+ ### Changed
330
+
331
+ - **`mindforge audit-skill`, `register-skill`, `install-skill` and `record-learning` no
332
+ longer carry `defaultArgs`.** Prepending turned them from inert into live state
333
+ writers: `audit-skill <name> <ver> <tier>` appended a hash-chained
334
+ `{event:'skill_installed', validation_passed:true}` entry for a skill that does not
335
+ exist, and `register-skill` wrote a malformed row above the table header of
336
+ `.mindforge/org/skills/MANIFEST.md`, which ships in the tarball. Bare invocations now
337
+ print usage and exit 0 without reaching those writers, as at v11.9.1.
338
+ - **`subagent` is a first-class command.** Prepending `spawn` shadowed `spawn-agent`'s
339
+ `subagent` mode, whose documented route was `mindforge spawn subagent <name>`.
340
+ - **The dashboard now exits on an unhandled rejection instead of logging and
341
+ continuing.** An escaped rejection is the only reliable signal that an async call was
342
+ left un-awaited, and express 4.22.1 does not route async handler rejections to error
343
+ middleware — log-and-continue held the client socket open until the client gave up
344
+ (2.5s, 4s and 8s clients all timed out) versus a ~15ms reset on exit. Symmetric with
345
+ `uncaughtException`, whose log-and-continue form had made `shutdown()` swallow a
346
+ throwing token unlink and keep serving the token-authenticated mutation API **after
347
+ SIGTERM**, with the bearer token still on disk and valid in memory.
348
+ - **Dashboard error responses changed shape.** `detail` is removed from 5 endpoints,
349
+ raw errno strings from 10 more, `correlation_id` is added to 15, and a malformed
350
+ request body now returns `application/json` rather than express's `text/html` error
351
+ page. Anything parsing `detail` must correlate on the logged id instead.
352
+
353
+ ### Added
354
+
355
+ - **Secret scanning enforced at three layers**: `.gitleaks.toml`, a `.husky/pre-commit`
356
+ gate that fails loudly when gitleaks is absent rather than skipping, and
357
+ `.github/workflows/secret-scan.yml` scanning full history. `scripts/ci/verify-secret-scan.sh`
358
+ self-tests the scanner — it distinguishes "scanned clean" from "scanned and found"
359
+ from "did not scan", because gitleaks exits 1 for both a finding and a failed config
360
+ load, and writes no report in the latter case.
361
+
362
+ ### Tests
363
+
364
+ - Suite totals for this release: **105 files, 103 pass, 2 environment-dependent skips**
365
+ (`browser`, `sre-integration`). Eight new suites across the release:
366
+ `temporal-integrity`, `dashboard-error-leak`, `dashboard-crash-guards`,
367
+ `dashboard-wiring`, `cli-router`, `mindforge-params`, `file-lock`, `retrieval-fts`.
368
+ - **Four suites could not report failure and now can.** `v8-persistence`,
369
+ `v8-skill-evolution` and `v8-orbital-governance` ended `finally { process.exit(0) }`, and
370
+ `v7-pillar-integration` had zero assertions with a premium-model gate that named two models
371
+ absent from the registry for several releases. `npm test` is the only quality step before
372
+ `npm publish`, and the runner gates on child exit codes, so a blind suite blinded the publish
373
+ gate. Verified by injected failure rather than inspection.
374
+ `dashboard-wiring` derives the expected router set
375
+ from `server.js`'s own requires, so adding a router without mounting it fails.
376
+ `cli-router` runs against a mirror-root sandbox under `os.tmpdir()` — required, not
377
+ tidiness: the case that proves audit forgery is prevented would otherwise forge an
378
+ entry into the real chain on every run. `revops-roi.test.js` had 0 assertions and
379
+ could not fail; it now has 6.
380
+
381
+ ### Not fixed — deferred to v12
382
+
383
+ - **No hook is registered in any consumer install.** The installer copies 9 hook
384
+ scripts into `<runtime>/hooks/`, but nothing writes `.claude/settings.json` and it is
385
+ absent from `package.json` `files[]`. Verified by installing the tarball into a
386
+ scratch project. Every gate this release hardens is inert until that lands.
387
+ - **`requireAuth` exempts GET and OPTIONS**, so every read route — including
388
+ `/api/audit`, which serves the hash-chained audit log — is credential-free to any
389
+ local process. Mutations are protected. This is a threat-model decision, not a patch.
390
+ - **`audit-skill audit <name> <ver> <tier>`** — the explicit form — still reaches a
391
+ writer that performs no existence check and hardcodes `validation_passed: true`. Only
392
+ the bare invocation is closed.
393
+ - **Snapshot integrity is not an authenticity control.** `HMAC_KEY` is a literal in
394
+ shipped source, the HMAC covers only the metadata object so file **contents** are
395
+ unsigned (editing a file inside a signed snapshot leaves the signature valid), and
396
+ deleting `SNAPSHOT-META.json` bypasses verification entirely.
397
+ - `cwd: ROOT` in the CLI, which resolves consumer state inside `node_modules`.
398
+ - `security-scan` cannot fail: its parser expects `KEY=value` while `MINDFORGE.md` uses
399
+ `[KEY] = value`, so it always reports 0 settings and exits 0.
400
+ - Version drift in six publishable manifests (`Formula/mindforge.rb`, `Dockerfile`,
401
+ `mcp-server/server.json`, `mcp-server/src/index.ts`, the plugin manifest and the
402
+ marketplace entry) is untouched here — none is gated, and the Formula pins a tarball
403
+ sha256 that cannot exist before publish.
404
+
3
405
  ## [11.9.1] — 2026-07-29 — Packaging Fix: Restore Missing Workflow Commands
4
406
 
5
407
  ### Fixed
package/MINDFORGE.md CHANGED
@@ -1,9 +1,9 @@
1
- # MINDFORGE.md — Parameter Registry (v11.9.1)
1
+ # MINDFORGE.md — Parameter Registry (v11.9.3)
2
2
 
3
3
  ## 1. IDENTITY & VERSIONING
4
4
 
5
5
  [NAME] = MindForge
6
- [VERSION] = 11.9.1
6
+ [VERSION] = 11.9.3
7
7
  [STABLE] = true
8
8
  [MODE] = "Platform Sovereign"
9
9
  [REQUIRED_CORE_VERSION] = 11.9.1
@@ -98,8 +98,15 @@
98
98
  The following parameters cannot be overridden by plugins, agents, or session-level configuration:
99
99
 
100
100
  - [MIN_SOUL_SCORE] — Minimum SOUL score required for architectural changes
101
- - [BLOCK_ON_SECURITY] — Security gate enforcement cannot be disabled
102
- - [COST_HARD_LIMIT_USD] Hard cost limit cannot be raised without human approval
101
+ - [BLOCK_ON_SECURITY] — DECLARED, UNREAD. `git grep -l BLOCK_ON_SECURITY -- bin/` returns nothing:
102
+ no code reads this key, so it changes no behaviour and deleting it fails no validation (the schema
103
+ lists it as `recommended`, not `required`). What actually blocks a config-weakening edit is the
104
+ `mindforge-config-protection` hook, which is deny-class and fails closed — see SECURITY.md.
105
+ - [COST_HARD_LIMIT_USD] — **enforced as of 11.9.3** (COST-02). `bin/models/cost-tracker.js` `preflight()` reads this key, adds the call estimate to today's ledger spend, and throws `COST_LIMIT_REACHED`; `bin/models/model-client.js` re-throws it, so the model call is refused. Non-overridable means a plugin or session cannot raise the number — it does not mean a cap always exists: `0`, or the key being absent, legally disables the cap, because an upgrade never rewrites an existing MINDFORGE.md (`bin/installer-core.js:706`) and the schema lists this key as `recommended`, not `required`. A present-but-unreadable value (e.g. `= none`) is a hard config fault — `preflight()` throws `COST_LIMIT_MISCONFIGURED` instead of running uncapped
103
106
  - [BLOCK_ON_SECURITY] is non-overridable; PQAS itself is simulated/experimental (inactive by default) and is NOT a non-overridable guarantee — do not rely on it as an enforced control
104
- - [SOVEREIGN_IDENTITY] — Identity verification is always required
105
- - [ENABLE_ZTAI] Zero-trust identity cannot be bypassed
107
+ - [SOVEREIGN_IDENTITY] — DECLARED, UNREAD. No reader in `bin/`. No identity is verified as a result
108
+ of this key being set.
109
+ - [ENABLE_ZTAI] — DECLARED, UNREAD, and the feature it gates is inactive. No reader in `bin/`;
110
+ measured on a live 3116-entry AUDIT.jsonl, 0 entries carry a `signature` or `did`. "Cannot be
111
+ bypassed" overstates a switch that is not wired to anything — see docs/security/ZTAI-OVERVIEW.md,
112
+ which now leads with a status banner.