mindforge-cc 11.9.1 → 11.9.2
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/.agent/mindforge/consult.md +1 -1
- package/.agent/mindforge/cost-report.md +1 -1
- package/.claude/commands/mindforge/consult.md +1 -1
- package/.claude/commands/mindforge/cost-report.md +1 -1
- package/.mindforge/MINDFORGE-SCHEMA.json +126 -13
- package/.mindforge/config.json +3 -3
- package/.mindforge/engine/cost-tracking/router.md +1 -1
- package/.mindforge/engine/cost-tracking/token-ledger.md +21 -24
- package/.mindforge/memory/sync-manifest.json +1 -1
- package/.mindforge/metrics/METRICS-SCHEMA.md +13 -4
- package/.mindforge/personas/cost-optimizer.md +2 -2
- package/.mindforge/personas/multi-model-bridge.md +1 -1
- package/.mindforge/skills/cost-aware-routing/SKILL.md +3 -3
- package/.mindforge/skills/multi-llm-consult/SKILL.md +2 -2
- package/CHANGELOG.md +208 -0
- package/MINDFORGE.md +3 -3
- package/README.md +50 -2
- package/RELEASENOTES.md +53 -0
- package/bin/autonomous/audit-writer.js +48 -33
- package/bin/dashboard/api-router.js +11 -10
- package/bin/dashboard/error-response.js +44 -0
- package/bin/dashboard/frontend/index.html +20 -3
- package/bin/dashboard/metrics-aggregator.js +29 -8
- package/bin/dashboard/revops-api.js +12 -2
- package/bin/dashboard/server.js +85 -5
- package/bin/dashboard/temporal-api.js +11 -5
- package/bin/engine/remediation-engine.js +12 -1
- package/bin/engine/temporal-hub.js +41 -9
- package/bin/eval/eval-harness.js +212 -1
- package/bin/eval/golden-set-retrieval.json +9 -0
- package/bin/governance/policy-engine.js +8 -0
- package/bin/hindsight-injector.js +8 -2
- package/bin/hooks/instinct-capture-hook.js +7 -1
- package/bin/learning/instinct-cli.js +7 -24
- package/bin/memory/knowledge-capture.js +23 -3
- package/bin/memory/knowledge-graph.js +70 -31
- package/bin/memory/vector-hub.js +304 -31
- package/bin/mindforge-cli.js +43 -11
- package/bin/models/cost-tracker.js +22 -23
- package/bin/models/model-router.js +28 -7
- package/bin/models/usage-record.js +71 -0
- package/bin/utils/file-lock.js +106 -0
- package/bin/utils/mindforge-params.js +124 -0
- package/bin/validate-config.js +34 -16
- package/changelogs/v11.9.2.md +209 -0
- package/docs/References/config-reference.md +73 -14
- package/docs/sdk-reference.md +1 -1
- package/package.json +4 -2
|
@@ -31,7 +31,7 @@ $ARGUMENTS
|
|
|
31
31
|
- Identify divergence (models disagree — flag for user)
|
|
32
32
|
- Identify novel insights (unique points from one model)
|
|
33
33
|
7. **Present results** with clear attribution (which model said what).
|
|
34
|
-
8. Log consultation in token-
|
|
34
|
+
8. Log consultation in token-usage.jsonl (model, tokens, cost per call).
|
|
35
35
|
9. Report total cost of this consultation.
|
|
36
36
|
10. Remind: "External opinions are advisory — user sovereignty applies."
|
|
37
37
|
</process>
|
|
@@ -19,7 +19,7 @@ $ARGUMENTS
|
|
|
19
19
|
|
|
20
20
|
<process>
|
|
21
21
|
1. Parse flags: --window (time period, default: current session), --by-model, --by-task, --phase.
|
|
22
|
-
2. Read `.mindforge/metrics/token-
|
|
22
|
+
2. Read `.mindforge/metrics/token-usage.jsonl` for the specified window.
|
|
23
23
|
3. **Compute totals:**
|
|
24
24
|
- Total tokens (input, output, cached)
|
|
25
25
|
- Total estimated cost (USD)
|
|
@@ -31,7 +31,7 @@ $ARGUMENTS
|
|
|
31
31
|
- Identify divergence (models disagree — flag for user)
|
|
32
32
|
- Identify novel insights (unique points from one model)
|
|
33
33
|
7. **Present results** with clear attribution (which model said what).
|
|
34
|
-
8. Log consultation in token-
|
|
34
|
+
8. Log consultation in token-usage.jsonl (model, tokens, cost per call).
|
|
35
35
|
9. Report total cost of this consultation.
|
|
36
36
|
10. Remind: "External opinions are advisory — user sovereignty applies."
|
|
37
37
|
</process>
|
|
@@ -19,7 +19,7 @@ $ARGUMENTS
|
|
|
19
19
|
|
|
20
20
|
<process>
|
|
21
21
|
1. Parse flags: --window (time period, default: current session), --by-model, --by-task, --phase.
|
|
22
|
-
2. Read `.mindforge/metrics/token-
|
|
22
|
+
2. Read `.mindforge/metrics/token-usage.jsonl` for the specified window.
|
|
23
23
|
3. **Compute totals:**
|
|
24
24
|
- Total tokens (input, output, cached)
|
|
25
25
|
- Total estimated cost (USD)
|
|
@@ -1,33 +1,146 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"title": "MindForge Project Configuration Schema",
|
|
4
|
-
"description": "JSON Schema for MINDFORGE.md
|
|
4
|
+
"description": "JSON Schema for MINDFORGE.md bracketed parameter assignments ([KEY] = value)",
|
|
5
5
|
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"VERSION",
|
|
8
|
+
"REACTIVE_MODE",
|
|
9
|
+
"PLANNER",
|
|
10
|
+
"EXECUTOR",
|
|
11
|
+
"MIN_SOUL_SCORE"
|
|
12
|
+
],
|
|
13
|
+
"recommended": [
|
|
14
|
+
"COST_WARN_USD",
|
|
15
|
+
"COST_HARD_LIMIT_USD",
|
|
16
|
+
"BLOCK_ON_SECURITY"
|
|
17
|
+
],
|
|
6
18
|
"properties": {
|
|
19
|
+
"NAME": { "type": "string", "description": "Project display name" },
|
|
20
|
+
"VERSION": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
23
|
+
"description": "MindForge version this registry targets (must equal package.json version)"
|
|
24
|
+
},
|
|
25
|
+
"STABLE": { "type": "boolean", "description": "Registry is a released/stable configuration" },
|
|
26
|
+
"MODE": { "type": "string", "description": "Operating mode label (free-form)" },
|
|
27
|
+
"REQUIRED_CORE_VERSION": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
30
|
+
"description": "Minimum MindForge core version required by this project"
|
|
31
|
+
},
|
|
32
|
+
"SOVEREIGN_IDENTITY": {
|
|
33
|
+
"type": "boolean",
|
|
34
|
+
"nonOverridable": true,
|
|
35
|
+
"description": "NON-OVERRIDABLE: identity verification is always required"
|
|
36
|
+
},
|
|
37
|
+
"SRE_LAYER_ENABLED": { "type": "boolean", "description": "Enable the SRE persona layer" },
|
|
38
|
+
"SWARM_ORCHESTRATION": { "type": "boolean", "description": "Enable dynamic swarm orchestration" },
|
|
39
|
+
"AUTO_SWARM_THRESHOLD": {
|
|
40
|
+
"type": "number", "minimum": 0, "maximum": 10,
|
|
41
|
+
"description": "Difficulty score above which a swarm is auto-spawned"
|
|
42
|
+
},
|
|
43
|
+
"CONTEXT7_DEPTH": {
|
|
44
|
+
"type": "enum", "values": ["MINIMAL", "STANDARD", "EXTENDED"],
|
|
45
|
+
"description": "Depth of Context7 knowledge injection"
|
|
46
|
+
},
|
|
47
|
+
"DYNAMISM_LEVEL": {
|
|
48
|
+
"type": "number", "minimum": 1, "maximum": 5,
|
|
49
|
+
"description": "How aggressively the engine reshapes its own plan (1=static, 5=fully dynamic)"
|
|
50
|
+
},
|
|
51
|
+
"REACTIVE_MODE": { "type": "boolean", "description": "Enable the reactive (auto-discovery) engine" },
|
|
52
|
+
"CONTEXT_SHARDING": { "type": "boolean", "description": "Enable the sharded memory loop" },
|
|
53
|
+
"ADS_LOOP_ENFORCED": { "type": "boolean", "description": "Enforce the adversarial decision loop before architectural change" },
|
|
54
|
+
"TEMPORAL_VISION": { "type": "boolean", "description": "Enable temporal hindsight / steering" },
|
|
55
|
+
"RAG_2_AUTO_SHADOW": { "type": "boolean", "description": "Run RAG-2 retrieval in shadow mode" },
|
|
56
|
+
"ENABLE_ART_TRACING": { "type": "boolean", "description": "Enable agent reasoning trace (ART) capture" },
|
|
57
|
+
"ENABLE_ZTAI": {
|
|
58
|
+
"type": "boolean",
|
|
59
|
+
"nonOverridable": true,
|
|
60
|
+
"description": "NON-OVERRIDABLE: zero-trust agent identity cannot be bypassed"
|
|
61
|
+
},
|
|
62
|
+
"ZTAI_KEY_TYPE": { "type": "string", "description": "Declared ZTAI key algorithm label" },
|
|
63
|
+
"NEXUS_TRACE_RETENTION_DAYS": {
|
|
64
|
+
"type": "number", "minimum": 1, "maximum": 365,
|
|
65
|
+
"description": "Days of NexusTracer trace retention"
|
|
66
|
+
},
|
|
67
|
+
"CADIA_CORE": { "type": "boolean", "description": "Enable the CADIA core layer" },
|
|
68
|
+
"PQAS_ENFORCED": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": "Post-quantum attestation enforcement (SIMULATED/inactive by default — see bin/governance/quantum-crypto.js)"
|
|
71
|
+
},
|
|
72
|
+
"PROACTIVE_HOMING": { "type": "boolean", "description": "Enable proactive homing / next-task discovery" },
|
|
73
|
+
"PLANNER": { "type": "string", "description": "Model id for the planning persona (canonical: PLANNER_MODEL)" },
|
|
74
|
+
"EXECUTOR": { "type": "string", "description": "Model id for execution agents (canonical: EXECUTOR_MODEL)" },
|
|
75
|
+
"REVIEWER": { "type": "string", "description": "Model id for the code reviewer (canonical: REVIEWER_MODEL)" },
|
|
76
|
+
"VERIFIER": { "type": "string", "description": "Model id for the verification persona (canonical: VERIFIER_MODEL)" },
|
|
77
|
+
"SECURITY": { "type": "string", "description": "Model id for security review (canonical: SECURITY_MODEL)" },
|
|
78
|
+
"DEBUG": { "type": "string", "description": "Model id for the debug specialist (canonical: DEBUG_MODEL)" },
|
|
79
|
+
"RESEARCH": { "type": "string", "description": "Model id for the research agent (canonical: RESEARCH_MODEL)" },
|
|
80
|
+
"QA": { "type": "string", "description": "Model id for the QA engineer (canonical: QA_MODEL)" },
|
|
81
|
+
"QUICK": { "type": "string", "description": "Model id for tier-1 budget-bias tasks (canonical: QUICK_MODEL)" },
|
|
82
|
+
"COST_WARN_USD": {
|
|
83
|
+
"type": "number", "minimum": 0, "maximum": 10000,
|
|
84
|
+
"description": "Daily spend at which a cost warning is emitted"
|
|
85
|
+
},
|
|
86
|
+
"COST_HARD_LIMIT_USD": {
|
|
87
|
+
"type": "number", "minimum": 0, "maximum": 10000,
|
|
88
|
+
"description": "Daily hard cost limit in USD. DECLARED BUT NOT ENFORCED as of 11.9.2: bin/models/cost-tracker.js reads MODEL_COST_HARD_LIMIT_USD, which this registry does not declare, so preflight() returns early and no cap is applied. Do not treat this as a spend control. Tracked as COST-02."
|
|
89
|
+
},
|
|
90
|
+
"ADS_DEBATE_ROUNDS": {
|
|
91
|
+
"type": "number", "minimum": 1, "maximum": 10,
|
|
92
|
+
"description": "Red-team/blue-team debate rounds per architectural decision"
|
|
93
|
+
},
|
|
94
|
+
"MIN_SOUL_SCORE": {
|
|
95
|
+
"type": "number", "minimum": 0, "maximum": 10,
|
|
96
|
+
"nonOverridable": true,
|
|
97
|
+
"description": "NON-OVERRIDABLE: minimum SOUL score required for architectural changes"
|
|
98
|
+
},
|
|
99
|
+
"REQUIRE_ADR": { "type": "boolean", "description": "Require an ADR for architectural decisions" },
|
|
100
|
+
"BLOCK_ON_SECURITY": {
|
|
101
|
+
"type": "boolean",
|
|
102
|
+
"nonOverridable": true,
|
|
103
|
+
"description": "NON-OVERRIDABLE: security gate enforcement cannot be disabled"
|
|
104
|
+
},
|
|
105
|
+
"BROWSER_PORT": {
|
|
106
|
+
"type": "number", "minimum": 1024, "maximum": 65535,
|
|
107
|
+
"description": "Port for the browser/QA harness"
|
|
108
|
+
},
|
|
109
|
+
"DASHBOARD_PORT": {
|
|
110
|
+
"type": "number", "minimum": 1024, "maximum": 65535,
|
|
111
|
+
"description": "Port for the MindForge dashboard"
|
|
112
|
+
},
|
|
113
|
+
"API_URL": { "type": "string", "description": "Base URL of the project API under development" },
|
|
114
|
+
"SHARD_RETAIN_DAYS": {
|
|
115
|
+
"type": "number", "minimum": 1, "maximum": 365,
|
|
116
|
+
"description": "Days to retain context shards"
|
|
117
|
+
},
|
|
118
|
+
"FORBIDDEN": { "type": "string", "description": "Multi-line block of project prohibitions injected into every agent prompt" },
|
|
119
|
+
"INSTRUCTIONS": { "type": "string", "description": "Multi-line block of project instructions injected into every agent prompt" },
|
|
7
120
|
"MINDFORGE_VERSION_REQUIRED": {
|
|
8
121
|
"type": "string",
|
|
9
122
|
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
10
123
|
"description": "Minimum MindForge version required for this config"
|
|
11
124
|
},
|
|
12
125
|
"PLANNER_MODEL": {
|
|
13
|
-
"type": "
|
|
14
|
-
"
|
|
15
|
-
"description": "
|
|
126
|
+
"type": "string",
|
|
127
|
+
"deprecated": true,
|
|
128
|
+
"description": "DEPRECATED long form of [PLANNER]. Model id for the planning agent (free-form: model ids churn faster than this schema)"
|
|
16
129
|
},
|
|
17
130
|
"EXECUTOR_MODEL": {
|
|
18
|
-
"type": "
|
|
19
|
-
"
|
|
20
|
-
"description": "
|
|
131
|
+
"type": "string",
|
|
132
|
+
"deprecated": true,
|
|
133
|
+
"description": "DEPRECATED long form of [EXECUTOR]. Model id for execution agents"
|
|
21
134
|
},
|
|
22
135
|
"REVIEWER_MODEL": {
|
|
23
|
-
"type": "
|
|
24
|
-
"
|
|
25
|
-
"description": "
|
|
136
|
+
"type": "string",
|
|
137
|
+
"deprecated": true,
|
|
138
|
+
"description": "DEPRECATED long form of [REVIEWER]. Model id for the code reviewer"
|
|
26
139
|
},
|
|
27
140
|
"SECURITY_MODEL": {
|
|
28
|
-
"type": "
|
|
29
|
-
"
|
|
30
|
-
"description": "
|
|
141
|
+
"type": "string",
|
|
142
|
+
"deprecated": true,
|
|
143
|
+
"description": "DEPRECATED long form of [SECURITY]. Model id for security review"
|
|
31
144
|
},
|
|
32
145
|
"TIER1_AUTO_APPROVE": {
|
|
33
146
|
"type": "boolean",
|
package/.mindforge/config.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "11.9.
|
|
2
|
+
"version": "11.9.2",
|
|
3
3
|
"environment": "development",
|
|
4
4
|
"governance": {
|
|
5
5
|
"drift_threshold": 0.75,
|
|
6
6
|
"critical_drift_threshold": 0.5,
|
|
7
7
|
"res_threshold": 0.8,
|
|
8
|
-
"active_did": "did:mindforge:
|
|
8
|
+
"active_did": "did:mindforge:766e07ac-8f56-4840-be61-316b90bbed35"
|
|
9
9
|
},
|
|
10
10
|
"revops": {
|
|
11
11
|
"market_registry": {
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"project_weekly_warn_usd": 50,
|
|
126
126
|
"project_weekly_hard_limit_usd": 200
|
|
127
127
|
},
|
|
128
|
-
"ledger_path": ".mindforge/metrics/token-
|
|
128
|
+
"ledger_path": ".mindforge/metrics/token-usage.jsonl"
|
|
129
129
|
},
|
|
130
130
|
"proactive_suggestions": {
|
|
131
131
|
"enabled": true,
|
|
@@ -41,7 +41,7 @@ These always override the matrix:
|
|
|
41
41
|
3. Map score to tier via decision matrix
|
|
42
42
|
4. Apply override rules
|
|
43
43
|
5. Check budget: if remaining budget < estimated cost, downgrade one tier with WARNING
|
|
44
|
-
6. Log routing decision to token-
|
|
44
|
+
6. Log routing decision to token-usage.jsonl
|
|
45
45
|
7. Return selected model ID
|
|
46
46
|
|
|
47
47
|
## Budget Guard
|
|
@@ -5,43 +5,40 @@ Append-only ledger recording all token usage for analytics, budgeting, and optim
|
|
|
5
5
|
|
|
6
6
|
## Storage
|
|
7
7
|
|
|
8
|
-
- Location: `.mindforge/metrics/token-
|
|
8
|
+
- Location: `.mindforge/metrics/token-usage.jsonl` (canonical shape: `bin/models/usage-record.js`)
|
|
9
9
|
- Format: JSON Lines (one entry per model interaction)
|
|
10
10
|
- Rotation: Archive entries older than 30 days to `.mindforge/metrics/archive/`
|
|
11
11
|
- Retention: Archives kept for 90 days, then deleted
|
|
12
12
|
|
|
13
13
|
## Entry Format
|
|
14
14
|
|
|
15
|
-
Each line in the ledger is a complete JSON object
|
|
15
|
+
Each line in the ledger is a complete JSON object. The authoritative shape is
|
|
16
|
+
`bin/models/usage-record.js`; this is what `bin/models/cost-tracker.js`
|
|
17
|
+
actually appends today (all five providers in `bin/models/*-provider.js` emit it):
|
|
16
18
|
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
|
-
"id": "txn-[uuid]",
|
|
20
|
-
"timestamp": "2026-05-25T10:30:00Z",
|
|
21
|
-
"session_id": "session-abc123",
|
|
22
|
-
"task_id": "task-def456",
|
|
23
|
-
"phase": "execute",
|
|
24
21
|
"model": "claude-sonnet-4-6",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
"output": 3200,
|
|
30
|
-
"cached_input": 8000,
|
|
31
|
-
"total": 15700
|
|
32
|
-
},
|
|
22
|
+
"input_tokens": 12500,
|
|
23
|
+
"output_tokens": 3200,
|
|
24
|
+
"cache_read_input_tokens": 8000,
|
|
25
|
+
"cache_creation_input_tokens": 0,
|
|
33
26
|
"cost_usd": 0.085,
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"files_touched": 3,
|
|
40
|
-
"skills_loaded": ["code-quality", "testing-standards"],
|
|
41
|
-
"outcome": "success"
|
|
27
|
+
"task_name": "Plan 3-04",
|
|
28
|
+
"session_id": "session-abc123",
|
|
29
|
+
"phase": 3,
|
|
30
|
+
"date": "2026-05-25",
|
|
31
|
+
"timestamp": "2026-05-25T10:30:00.000Z"
|
|
42
32
|
}
|
|
43
33
|
```
|
|
44
34
|
|
|
35
|
+
`cost_usd` is the ONLY cost field. `total_cost_usd` belongs to cross-review
|
|
36
|
+
reports (`bin/review/cross-review-engine.js`) and must never appear here.
|
|
37
|
+
|
|
38
|
+
Not yet emitted (aspirational — do not read these): `id`, `task_id`, `tier`,
|
|
39
|
+
`routing_reason`, `budget_remaining`, `task_type`, `files_touched`,
|
|
40
|
+
`skills_loaded`, `outcome`.
|
|
41
|
+
|
|
45
42
|
## Reporting Queries
|
|
46
43
|
|
|
47
44
|
The `/mindforge:cost-report` command reads this ledger to produce:
|
|
@@ -71,7 +68,7 @@ debugging | $0.85 | 32,000 | 8
|
|
|
71
68
|
|
|
72
69
|
## Integration
|
|
73
70
|
|
|
74
|
-
- Written to by
|
|
71
|
+
- Written to by `bin/models/cost-tracker.js` `record()` after every model interaction (called from `bin/models/model-client.js:77`)
|
|
75
72
|
- Read by `/mindforge:cost-report` command
|
|
76
73
|
- Summarized weekly into `.mindforge/metrics/weekly-cost-summary.json`
|
|
77
74
|
- Referenced by AgRevOps dashboard for ROI tracking
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
# MindForge Metrics — Schema Reference
|
|
2
2
|
|
|
3
3
|
## Files
|
|
4
|
-
- `session-quality.jsonl`
|
|
5
|
-
- `
|
|
6
|
-
|
|
7
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
85
|
+
- Log every external call in token-usage.jsonl
|
|
86
86
|
</critical_rules>
|
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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?
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,213 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [11.9.2] — 2026-08-16 — Correctness: audit-chain integrity, dashboard crash policy, secret scanning
|
|
4
|
+
|
|
5
|
+
Patch release. No new features. Correctness work closing defects found by a
|
|
6
|
+
multi-agent audit of v11.9.1, plus the regression suites that keep them closed.
|
|
7
|
+
Contains a breaking change to the dashboard HTTP surface — see BREAKING below.
|
|
8
|
+
|
|
9
|
+
### BREAKING
|
|
10
|
+
|
|
11
|
+
Shipped under a PATCH bump. The break is confined to the dashboard's own HTTP
|
|
12
|
+
surface, which binds to 127.0.0.1 only — but if you script against it, read this.
|
|
13
|
+
|
|
14
|
+
- **Dashboard error responses changed shape.** `detail` is removed from 5 endpoints and
|
|
15
|
+
raw errno strings from 10 more; `correlation_id` is added to 15; a malformed request
|
|
16
|
+
body now returns `application/json` instead of express's `text/html` error page.
|
|
17
|
+
Anything parsing `detail` must correlate on the logged `correlation_id` instead. This
|
|
18
|
+
was deliberate — those fields leaked absolute filesystem paths, and therefore the
|
|
19
|
+
operator's username and home directory, into an unauthenticated response body
|
|
20
|
+
(`requireAuth` exempts GET).
|
|
21
|
+
- **The dashboard now EXITS on an unhandled rejection or uncaught exception** where
|
|
22
|
+
11.9.1 logged and continued. If you supervise the process, expect restarts where you
|
|
23
|
+
previously saw a logged error. Rationale in the Fixed section below: log-and-continue
|
|
24
|
+
held client sockets open until the client timed out, and had made `shutdown()` swallow
|
|
25
|
+
a throwing token unlink and keep serving the authenticated mutation API after SIGTERM.
|
|
26
|
+
- **`node bin/validate-config.js` and `mindforge security-scan` can now fail.** They
|
|
27
|
+
previously reported `MINDFORGE.md valid — 0 settings configured` and exited 0 on every
|
|
28
|
+
input. If you run either in CI, a genuinely invalid registry will now red-line where it
|
|
29
|
+
used to pass. Note this reaches **fresh installs and `--force` reinstalls only** — the
|
|
30
|
+
installer does not overwrite an existing `.mindforge/MINDFORGE-SCHEMA.json`, so a plain
|
|
31
|
+
upgrade keeps the old permissive schema.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **`security-scan` could not fail.** `bin/validate-config.js` and
|
|
36
|
+
`bin/models/model-router.js` each parsed `MINDFORGE.md` with a plain `KEY=value` regex, but
|
|
37
|
+
the registry declares its 43 parameters as bracketed `[KEY] = value`. Every schema property
|
|
38
|
+
resolved to `undefined` and short-circuited, so the command reported
|
|
39
|
+
`MINDFORGE.md valid — 0 settings configured` and exited 0 on any input. The schema also had
|
|
40
|
+
no `required` key at all. Both parsers now share `bin/utils/mindforge-params.js`, which also
|
|
41
|
+
accepts the legacy plain form (`examples/starter-project/MINDFORGE.md` ships 28 such lines),
|
|
42
|
+
and the schema declares real `required`/`recommended` sets.
|
|
43
|
+
**Behaviour change for consumers:** three CI gates go from unfailable to failable —
|
|
44
|
+
`.github/workflows/mindforge-ci.yml:38`, `.gitlab-ci-mindforge.yml:12`, and
|
|
45
|
+
`.github/workflows/control-plane.yml:100`. If one red-lines on a valid value, the schema
|
|
46
|
+
bound is wrong; do not "fix" it by editing `MINDFORGE.md`. Model routing is unchanged —
|
|
47
|
+
30 persona x tier combinations resolve identically.
|
|
48
|
+
- **Trace retrieval returned nothing usable.** Queries were wrapped as a single FTS phrase, so
|
|
49
|
+
any query containing one absent term scored zero; and `traces_search` was keyed on `trace_id`
|
|
50
|
+
rather than the primary key, so each span's DELETE evicted the previous span and only the last
|
|
51
|
+
span per trace stayed searchable — 2,270 of 5,117 content-bearing traces, 44.4%, unsearchable.
|
|
52
|
+
Queries are now tokenised, OR-joined and ranked by tf-idf (`matchinfo('pcnx')`); the index is
|
|
53
|
+
re-keyed and rebuilt losslessly from the base table. `bin/eval/eval-harness.js` and its golden
|
|
54
|
+
set had zero callers and are now reachable as `npm run eval:retrieval`, with the baseline
|
|
55
|
+
committed: mean recall@10 0.6417, nDCG 0.5698 over 519 documents.
|
|
56
|
+
- **The cost ledger reported two totals for one concept.** `sum(cost_usd)` was $13.73 while
|
|
57
|
+
`sum(total_cost_usd)` was $0.00, and `tests/dashboard.test.js` wrote the reader's field name,
|
|
58
|
+
so the mismatch tested green. `bin/models/usage-record.js` is now the single definition of the
|
|
59
|
+
ledger path, record shape, per-entry cost and day bucket. The configured `ledger_path` pointed
|
|
60
|
+
at `token-ledger.jsonl`, a file that has never existed; that ghost filename had spread to 17
|
|
61
|
+
places across 13 files and is now absent. The dashboard cost tile no longer renders `$0.00`
|
|
62
|
+
on a 500 — it had no `res.ok` check, and because errors return well-formed JSON the catch
|
|
63
|
+
never fired, making an outage indistinguishable from zero spend.
|
|
64
|
+
A maintainer tool, `scripts/purge-synthetic-usage.js`, removes fixture rows: dry-run by
|
|
65
|
+
default, backs up first, idempotent, and aborts leaving the ledger untouched if the rewrite
|
|
66
|
+
fails. It is run from a repository checkout — `scripts/` is not in the published tarball, so
|
|
67
|
+
installed consumers do not have it.
|
|
68
|
+
- **Audit hash chain could fork under concurrent writers.** `bin/autonomous/audit-writer.js`
|
|
69
|
+
read the chain head and appended with no mutual exclusion, and cached the head in-process
|
|
70
|
+
indefinitely — so once a second process appended, the first kept chaining from a superseded
|
|
71
|
+
hash. Added `bin/utils/file-lock.js` (a fail-closed advisory lock promoted from
|
|
72
|
+
`bin/learning/instinct-cli.js`, deliberately NOT from `.agent/bin/lib/state.cjs`, which
|
|
73
|
+
writes anyway when the lock cannot be taken) held across read-head-through-fsync, and made
|
|
74
|
+
the cached head carry the file size that witnesses it is still the tail. 8 concurrent
|
|
75
|
+
appenders went from 199 broken links + 4 forks per 200 entries to 0. A lock alone was
|
|
76
|
+
measured insufficient — it still left 2 breaks and 1 fork, because the stale cache is a
|
|
77
|
+
second, independent defect.
|
|
78
|
+
- **Knowledge-graph edge updates were lost under concurrency.** `deprecateEdge`,
|
|
79
|
+
`reinforceEdge` and `applyDecay` in `bin/memory/knowledge-graph.js` each did
|
|
80
|
+
`readAllEdges()` -> mutate -> append with no lock, and `addEdge` appended unserialised
|
|
81
|
+
against them. Measured at HEAD over 4 runs of 8 processes x 20 `reinforceEdge` calls:
|
|
82
|
+
93-129 of 160 increments lost, final `traversal_count` 31-67 instead of 160. All four
|
|
83
|
+
write paths now hold the `graph-edges.jsonl` lock across read-through-append; the same
|
|
84
|
+
probe then loses 0 of 160 in every run, with no lock-acquisition failures.
|
|
85
|
+
- `bin/governance/policy-engine.js`: `logAudit`'s un-awaited audit write now has a
|
|
86
|
+
`.catch()` — a lock-contention failure is reported at the decision site instead of
|
|
87
|
+
escaping as an unhandled rejection.
|
|
88
|
+
- `bin/hooks/instinct-capture-hook.js` appended to the instinct store without the lock that
|
|
89
|
+
`instinct-cli`'s prune/import rewrite holds, so a hook append landing in that window was
|
|
90
|
+
clobbered by the rename. It now takes the same lock.
|
|
91
|
+
- `tests/v7-sovereign-security.test.js`: `new PolicyEngine()` no longer defaults
|
|
92
|
+
`planningDir` to `process.cwd()`, which appended test verdicts to the operator's real
|
|
93
|
+
`.planning/RISK-AUDIT.jsonl`.
|
|
94
|
+
- Packaging: `package.json` files[] now excludes `**/*.lock` so a lockfile orphaned by a
|
|
95
|
+
hard kill cannot leak into the npm tarball (verified: without the negation, a
|
|
96
|
+
`.mindforge/memory/graph-edges.jsonl.lock` does ship).
|
|
97
|
+
|
|
98
|
+
- **Audit-chain forgery via un-awaited rollback.** `HindsightInjector.inject` called
|
|
99
|
+
the async `TemporalHub.rollbackTo` without `await`, so its rejection escaped the
|
|
100
|
+
surrounding `try/catch` while execution continued: a failed rollback still fsync'd a
|
|
101
|
+
hash-chained `hindsight_injected` entry and flipped `auto-state.json` to
|
|
102
|
+
`awaiting_regeneration` for something that never happened. The log gained a
|
|
103
|
+
cryptographically valid record of a non-event, and `verify-audit` reported the chain
|
|
104
|
+
valid — valid and wrong.
|
|
105
|
+
- **CLI `defaultArgs` were replaced by user arguments, not prepended.** `mindforge
|
|
106
|
+
health <anything>` lost `--check` and fell through to `installer-core`'s real
|
|
107
|
+
`install()` with `force: true`. Now prepended.
|
|
108
|
+
- **`_verifyMetadata` compared UTF-16 code units, not bytes**, so a 64-unit / 65-byte
|
|
109
|
+
`integrity` still threw `RangeError` — and the caller degraded that throw into
|
|
110
|
+
"proceeding without integrity check" and restored the snapshot anyway. Read and
|
|
111
|
+
verify are now separate stages; only a genuinely absent `SNAPSHOT-META.json` reaches
|
|
112
|
+
the tolerant path.
|
|
113
|
+
- **Dashboard `RevOpsAPI` was required but never mounted**, so `/api/revops/overview`
|
|
114
|
+
404'd while the AgRevOps panels and docs described it as live. Even mounted it threw:
|
|
115
|
+
`getAuditEntries()` returns `{entries,total,limit,offset}` and three engines call
|
|
116
|
+
`.filter()` on it.
|
|
117
|
+
- **Dashboard leaked error internals to clients.** `err.message` reached response
|
|
118
|
+
bodies from 14 sites (`api-router.js` ×10, `temporal-api.js` ×3, `revops-api.js` ×1);
|
|
119
|
+
for fs-sourced errors that string carries absolute paths, disclosing the operator's
|
|
120
|
+
username and home directory. All sites now log server-side and return a generic
|
|
121
|
+
message plus a `correlation_id`, behind a 4-arg terminal handler that stops express
|
|
122
|
+
rendering `err.stack` when `NODE_ENV !== 'production'`.
|
|
123
|
+
- **Test runner discovery was a flat `readdirSync`**, so any suite in a subdirectory was
|
|
124
|
+
invisible. Now a recursive walk that prunes `tmp-*` / `node_modules` / dot
|
|
125
|
+
directories — directories only, never files.
|
|
126
|
+
- Three orphan files removed: one truncated `.planning/AUDIT.jsonl` to zero, one
|
|
127
|
+
overwrote `.planning/STATE.md`, one called a function absent from `bin/`. Recursion
|
|
128
|
+
made the `STATE.md` clobberer reachable by a single in-place rename; the other two
|
|
129
|
+
were unreachable by the runner at any depth. **The claim in `5177225`'s message that
|
|
130
|
+
all three were newly armed by recursion is correct for one of the three and
|
|
131
|
+
over-attributed for the other two.**
|
|
132
|
+
- Three relocated demos kept one-level-up requires after moving a directory deeper, so
|
|
133
|
+
all three exited 1; corrected to `../../bin/`.
|
|
134
|
+
|
|
135
|
+
### Changed
|
|
136
|
+
|
|
137
|
+
- **`mindforge audit-skill`, `register-skill`, `install-skill` and `record-learning` no
|
|
138
|
+
longer carry `defaultArgs`.** Prepending turned them from inert into live state
|
|
139
|
+
writers: `audit-skill <name> <ver> <tier>` appended a hash-chained
|
|
140
|
+
`{event:'skill_installed', validation_passed:true}` entry for a skill that does not
|
|
141
|
+
exist, and `register-skill` wrote a malformed row above the table header of
|
|
142
|
+
`.mindforge/org/skills/MANIFEST.md`, which ships in the tarball. Bare invocations now
|
|
143
|
+
print usage and exit 0 without reaching those writers, as at v11.9.1.
|
|
144
|
+
- **`subagent` is a first-class command.** Prepending `spawn` shadowed `spawn-agent`'s
|
|
145
|
+
`subagent` mode, whose documented route was `mindforge spawn subagent <name>`.
|
|
146
|
+
- **The dashboard now exits on an unhandled rejection instead of logging and
|
|
147
|
+
continuing.** An escaped rejection is the only reliable signal that an async call was
|
|
148
|
+
left un-awaited, and express 4.22.1 does not route async handler rejections to error
|
|
149
|
+
middleware — log-and-continue held the client socket open until the client gave up
|
|
150
|
+
(2.5s, 4s and 8s clients all timed out) versus a ~15ms reset on exit. Symmetric with
|
|
151
|
+
`uncaughtException`, whose log-and-continue form had made `shutdown()` swallow a
|
|
152
|
+
throwing token unlink and keep serving the token-authenticated mutation API **after
|
|
153
|
+
SIGTERM**, with the bearer token still on disk and valid in memory.
|
|
154
|
+
- **Dashboard error responses changed shape.** `detail` is removed from 5 endpoints,
|
|
155
|
+
raw errno strings from 10 more, `correlation_id` is added to 15, and a malformed
|
|
156
|
+
request body now returns `application/json` rather than express's `text/html` error
|
|
157
|
+
page. Anything parsing `detail` must correlate on the logged id instead.
|
|
158
|
+
|
|
159
|
+
### Added
|
|
160
|
+
|
|
161
|
+
- **Secret scanning enforced at three layers**: `.gitleaks.toml`, a `.husky/pre-commit`
|
|
162
|
+
gate that fails loudly when gitleaks is absent rather than skipping, and
|
|
163
|
+
`.github/workflows/secret-scan.yml` scanning full history. `scripts/ci/verify-secret-scan.sh`
|
|
164
|
+
self-tests the scanner — it distinguishes "scanned clean" from "scanned and found"
|
|
165
|
+
from "did not scan", because gitleaks exits 1 for both a finding and a failed config
|
|
166
|
+
load, and writes no report in the latter case.
|
|
167
|
+
|
|
168
|
+
### Tests
|
|
169
|
+
|
|
170
|
+
- Suite totals for this release: **105 files, 103 pass, 2 environment-dependent skips**
|
|
171
|
+
(`browser`, `sre-integration`). Eight new suites across the release:
|
|
172
|
+
`temporal-integrity`, `dashboard-error-leak`, `dashboard-crash-guards`,
|
|
173
|
+
`dashboard-wiring`, `cli-router`, `mindforge-params`, `file-lock`, `retrieval-fts`.
|
|
174
|
+
- **Four suites could not report failure and now can.** `v8-persistence`,
|
|
175
|
+
`v8-skill-evolution` and `v8-orbital-governance` ended `finally { process.exit(0) }`, and
|
|
176
|
+
`v7-pillar-integration` had zero assertions with a premium-model gate that named two models
|
|
177
|
+
absent from the registry for several releases. `npm test` is the only quality step before
|
|
178
|
+
`npm publish`, and the runner gates on child exit codes, so a blind suite blinded the publish
|
|
179
|
+
gate. Verified by injected failure rather than inspection.
|
|
180
|
+
`dashboard-wiring` derives the expected router set
|
|
181
|
+
from `server.js`'s own requires, so adding a router without mounting it fails.
|
|
182
|
+
`cli-router` runs against a mirror-root sandbox under `os.tmpdir()` — required, not
|
|
183
|
+
tidiness: the case that proves audit forgery is prevented would otherwise forge an
|
|
184
|
+
entry into the real chain on every run. `revops-roi.test.js` had 0 assertions and
|
|
185
|
+
could not fail; it now has 6.
|
|
186
|
+
|
|
187
|
+
### Not fixed — deferred to v12
|
|
188
|
+
|
|
189
|
+
- **No hook is registered in any consumer install.** The installer copies 9 hook
|
|
190
|
+
scripts into `<runtime>/hooks/`, but nothing writes `.claude/settings.json` and it is
|
|
191
|
+
absent from `package.json` `files[]`. Verified by installing the tarball into a
|
|
192
|
+
scratch project. Every gate this release hardens is inert until that lands.
|
|
193
|
+
- **`requireAuth` exempts GET and OPTIONS**, so every read route — including
|
|
194
|
+
`/api/audit`, which serves the hash-chained audit log — is credential-free to any
|
|
195
|
+
local process. Mutations are protected. This is a threat-model decision, not a patch.
|
|
196
|
+
- **`audit-skill audit <name> <ver> <tier>`** — the explicit form — still reaches a
|
|
197
|
+
writer that performs no existence check and hardcodes `validation_passed: true`. Only
|
|
198
|
+
the bare invocation is closed.
|
|
199
|
+
- **Snapshot integrity is not an authenticity control.** `HMAC_KEY` is a literal in
|
|
200
|
+
shipped source, the HMAC covers only the metadata object so file **contents** are
|
|
201
|
+
unsigned (editing a file inside a signed snapshot leaves the signature valid), and
|
|
202
|
+
deleting `SNAPSHOT-META.json` bypasses verification entirely.
|
|
203
|
+
- `cwd: ROOT` in the CLI, which resolves consumer state inside `node_modules`.
|
|
204
|
+
- `security-scan` cannot fail: its parser expects `KEY=value` while `MINDFORGE.md` uses
|
|
205
|
+
`[KEY] = value`, so it always reports 0 settings and exits 0.
|
|
206
|
+
- Version drift in six publishable manifests (`Formula/mindforge.rb`, `Dockerfile`,
|
|
207
|
+
`mcp-server/server.json`, `mcp-server/src/index.ts`, the plugin manifest and the
|
|
208
|
+
marketplace entry) is untouched here — none is gated, and the Formula pins a tarball
|
|
209
|
+
sha256 that cannot exist before publish.
|
|
210
|
+
|
|
3
211
|
## [11.9.1] — 2026-07-29 — Packaging Fix: Restore Missing Workflow Commands
|
|
4
212
|
|
|
5
213
|
### Fixed
|