mindforge-cc 5.4.0 → 5.10.0
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/CLAUDE.md +16 -7
- package/.mindforge/engine/nexus-tracer.js +7 -111
- package/CHANGELOG.md +48 -0
- package/README.md +48 -7
- package/RELEASENOTES.md +36 -1
- package/bin/dashboard/frontend/index.html +241 -1
- package/bin/dashboard/revops-api.js +47 -0
- package/bin/dashboard/server.js +1 -0
- package/bin/engine/feedback-loop.js +36 -1
- package/bin/engine/nexus-tracer.js +102 -17
- package/bin/engine/sre-manager.js +63 -9
- package/bin/engine/temporal-hindsight.js +27 -0
- package/bin/models/cloud-broker.js +89 -11
- package/bin/models/performance-stats.json +22 -0
- package/bin/revops/debt-monitor.js +60 -0
- package/bin/revops/roi-engine.js +60 -0
- package/bin/revops/velocity-forecaster.js +59 -0
- package/bin/skill-registry.js +66 -1
- package/bin/skill-validator.js +27 -1
- package/docs/INTELLIGENCE-MESH.md +12 -2
- package/docs/architecture/V5-ENTERPRISE.md +25 -22
- package/docs/commands-reference.md +4 -1
- package/docs/governance-guide.md +15 -7
- package/docs/usp-features.md +15 -72
- package/package.json +1 -1
package/bin/dashboard/server.js
CHANGED
|
@@ -34,6 +34,7 @@ try {
|
|
|
34
34
|
const SSE = require('./sse-bridge');
|
|
35
35
|
const API = require('./api-router');
|
|
36
36
|
const TemporalAPI = require('./temporal-api');
|
|
37
|
+
const RevOpsAPI = require('./revops-api');
|
|
37
38
|
|
|
38
39
|
// ── Express app ───────────────────────────────────────────────────────────────
|
|
39
40
|
const app = express();
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* MindForge — WaveFeedbackLoop (Pillar VI: Proactive Equilibrium)
|
|
3
3
|
* Monitors divergence during wave execution and triggers self-healing.
|
|
4
4
|
*/
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
5
7
|
|
|
6
8
|
class WaveFeedbackLoop {
|
|
7
9
|
constructor(config = {}) {
|
|
8
10
|
this.failureThreshold = config.failureThreshold || 0.20; // 20% failure rate
|
|
9
11
|
this.divergenceWeight = config.divergenceWeight || 1.5; // Bias for rapid divergence
|
|
12
|
+
this.statsPath = config.statsPath || path.join(__dirname, '..', 'models', 'performance-stats.json');
|
|
10
13
|
this.waveState = {
|
|
11
14
|
completed: 0,
|
|
12
15
|
failed: 0,
|
|
@@ -16,19 +19,51 @@ class WaveFeedbackLoop {
|
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
|
-
* Updates the feedback loop with a task result.
|
|
22
|
+
* Updates the feedback loop with a task result and records performance stats.
|
|
20
23
|
*/
|
|
21
24
|
update(result) {
|
|
22
25
|
this.waveState.total++;
|
|
26
|
+
const provider = result.providerId || 'unknown';
|
|
27
|
+
const taskType = result.taskType || 'default';
|
|
28
|
+
|
|
23
29
|
if (result.status === 'completed') {
|
|
24
30
|
this.waveState.completed++;
|
|
31
|
+
this.recordPerformance(provider, taskType, true);
|
|
25
32
|
} else if (result.status === 'failed') {
|
|
26
33
|
this.waveState.failed++;
|
|
34
|
+
this.recordPerformance(provider, taskType, false);
|
|
27
35
|
} else {
|
|
28
36
|
this.waveState.skipped++;
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Records performance metrics to persistent storage.
|
|
42
|
+
*/
|
|
43
|
+
recordPerformance(provider, taskType, isSuccess) {
|
|
44
|
+
if (provider === 'unknown') return;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
let stats = {};
|
|
48
|
+
if (fs.existsSync(this.statsPath)) {
|
|
49
|
+
stats = JSON.parse(fs.readFileSync(this.statsPath, 'utf8'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!stats[provider]) stats[provider] = {};
|
|
53
|
+
if (!stats[provider][taskType]) stats[provider][taskType] = { success: 0, failure: 0 };
|
|
54
|
+
|
|
55
|
+
if (isSuccess) {
|
|
56
|
+
stats[provider][taskType].success++;
|
|
57
|
+
} else {
|
|
58
|
+
stats[provider][taskType].failure++;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fs.writeFileSync(this.statsPath, JSON.stringify(stats, null, 2));
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.warn(`[MCA-WARN] Failed to record performance stats: ${e.message}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
32
67
|
/**
|
|
33
68
|
* Calculates the current divergence rate.
|
|
34
69
|
* @returns {number} - 0.0 to 1.0 divergence rate.
|
|
@@ -21,6 +21,10 @@ class NexusTracer {
|
|
|
21
21
|
this.enableZtai = config.enableZtai !== false;
|
|
22
22
|
this.sreManager = new SREManager();
|
|
23
23
|
|
|
24
|
+
// v5 Pillar III: Reasoning Entropy Monitoring (RES)
|
|
25
|
+
this.RES_THRESHOLD = 0.8; // Similarity threshold for stagnation
|
|
26
|
+
this.entropyCache = new Map(); // spanId -> [thoughtHistories]
|
|
27
|
+
|
|
24
28
|
// v5 Pillar IV: Agentic SBOM
|
|
25
29
|
this.sbom = {
|
|
26
30
|
manifest_version: '1.0.0',
|
|
@@ -41,7 +45,7 @@ class NexusTracer {
|
|
|
41
45
|
/**
|
|
42
46
|
* Start a new ART span.
|
|
43
47
|
*/
|
|
44
|
-
startSpan(name, attributes = {}, parentSpanId = null) {
|
|
48
|
+
async startSpan(name, attributes = {}, parentSpanId = null) {
|
|
45
49
|
const spanId = `sp_${crypto.randomBytes(6).toString('hex')}`;
|
|
46
50
|
const startTime = new Date().toISOString();
|
|
47
51
|
|
|
@@ -55,6 +59,8 @@ class NexusTracer {
|
|
|
55
59
|
attributes: {
|
|
56
60
|
...attributes,
|
|
57
61
|
service: 'mindforge-nexus',
|
|
62
|
+
host: require('os').hostname(),
|
|
63
|
+
pid: process.pid
|
|
58
64
|
}
|
|
59
65
|
};
|
|
60
66
|
|
|
@@ -77,7 +83,7 @@ class NexusTracer {
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
// Record span start in AUDIT.jsonl
|
|
80
|
-
this._recordEvent('span_started', {
|
|
86
|
+
await this._recordEvent('span_started', {
|
|
81
87
|
span_id: spanId,
|
|
82
88
|
parent_span_id: parentSpanId,
|
|
83
89
|
span_name: name,
|
|
@@ -91,7 +97,7 @@ class NexusTracer {
|
|
|
91
97
|
/**
|
|
92
98
|
* End an active span.
|
|
93
99
|
*/
|
|
94
|
-
endSpan(spanId, status = 'success', metadata = {}) {
|
|
100
|
+
async endSpan(spanId, status = 'success', metadata = {}) {
|
|
95
101
|
const span = this.activeSpans.get(spanId);
|
|
96
102
|
if (!span) return;
|
|
97
103
|
|
|
@@ -103,7 +109,7 @@ class NexusTracer {
|
|
|
103
109
|
this.sreManager.terminateEnclave(span.attributes.enclave_id);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
this._recordEvent('span_completed', {
|
|
112
|
+
await this._recordEvent('span_completed', {
|
|
107
113
|
span_id: spanId,
|
|
108
114
|
status,
|
|
109
115
|
...metadata
|
|
@@ -115,26 +121,100 @@ class NexusTracer {
|
|
|
115
121
|
/**
|
|
116
122
|
* Record a Reasoning Trace event (ART granularity).
|
|
117
123
|
*/
|
|
118
|
-
recordReasoning(spanId, agent, thought, resolution = 'none') {
|
|
124
|
+
async recordReasoning(spanId, agent, thought, resolution = 'none') {
|
|
119
125
|
const span = this.activeSpans.get(spanId);
|
|
120
126
|
let sanitizedThought = thought;
|
|
121
127
|
|
|
122
128
|
if (span && span.attributes.enclave_id) {
|
|
123
|
-
|
|
129
|
+
const result = this.sreManager.sanitizeThoughtChain(thought, span.attributes.enclave_id);
|
|
130
|
+
|
|
131
|
+
if (result.status === 'SRE-ISOLATED') {
|
|
132
|
+
// Log the ZK proof instead of the raw thought
|
|
133
|
+
await this._recordEvent('sre_proof_logged', {
|
|
134
|
+
span_id: spanId,
|
|
135
|
+
agent,
|
|
136
|
+
certificate: result,
|
|
137
|
+
resolution
|
|
138
|
+
});
|
|
139
|
+
return; // Skip standard reasoning trace for isolated content
|
|
140
|
+
}
|
|
141
|
+
sanitizedThought = result.content || thought;
|
|
124
142
|
}
|
|
125
143
|
|
|
126
|
-
|
|
144
|
+
// v5 Pillar III: PES (Proactive Equilibrium Scoring)
|
|
145
|
+
const entropy = this.calculateEntropy(spanId, sanitizedThought);
|
|
146
|
+
const isStagnant = entropy > this.RES_THRESHOLD;
|
|
147
|
+
|
|
148
|
+
await this._recordEvent('reasoning_trace', {
|
|
127
149
|
span_id: spanId,
|
|
128
150
|
agent,
|
|
129
151
|
thought: sanitizedThought,
|
|
130
|
-
resolution
|
|
152
|
+
resolution,
|
|
153
|
+
entropy: parseFloat(entropy.toFixed(4)),
|
|
154
|
+
is_stagnant: isStagnant
|
|
131
155
|
});
|
|
156
|
+
|
|
157
|
+
if (isStagnant) {
|
|
158
|
+
const history = this.entropyCache.get(spanId) || [];
|
|
159
|
+
const stagnationCount = history.filter(h => h.entropy > this.RES_THRESHOLD).length;
|
|
160
|
+
|
|
161
|
+
if (stagnationCount >= 3) {
|
|
162
|
+
await this._recordEvent('vulnerability_detected', {
|
|
163
|
+
span_id: spanId,
|
|
164
|
+
type: 'REASONING_LOOP',
|
|
165
|
+
severity: 'HIGH',
|
|
166
|
+
description: 'Agent reasoning entropy dropped below threshold (stagnation detected). Triggering proactive RCA.',
|
|
167
|
+
entropy_score: entropy
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Signal proactive recovery
|
|
171
|
+
await this.recordSelfHeal(spanId, {
|
|
172
|
+
type: 'PROACTIVE_RCA',
|
|
173
|
+
cause: 'REASONING_STAGNATION',
|
|
174
|
+
suggestion: 'Entropy threshold exceeded. Switch reasoning strategy.'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Calculates "Reasoning Entropy" (Similarity to previous thoughts).
|
|
182
|
+
* Range 0.0 (High Entropy/New) to 1.0 (Low Entropy/Repetitive).
|
|
183
|
+
*/
|
|
184
|
+
calculateEntropy(spanId, currentThought) {
|
|
185
|
+
if (!this.entropyCache.has(spanId)) {
|
|
186
|
+
this.entropyCache.set(spanId, []);
|
|
187
|
+
}
|
|
188
|
+
const history = this.entropyCache.get(spanId);
|
|
189
|
+
|
|
190
|
+
if (history.length === 0) {
|
|
191
|
+
history.push({ thought: currentThought, entropy: 0 });
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Simple Jaccard Similarity approach for stagnation detection
|
|
196
|
+
const getTokens = (str) => new Set(str.toLowerCase().split(/\s+/).filter(t => t.length > 3));
|
|
197
|
+
const currentTokens = getTokens(currentThought);
|
|
198
|
+
|
|
199
|
+
let maxSimilarity = 0;
|
|
200
|
+
for (const prev of history) {
|
|
201
|
+
const prevTokens = getTokens(prev.thought);
|
|
202
|
+
const intersection = new Set([...currentTokens].filter(x => prevTokens.has(x)));
|
|
203
|
+
const union = new Set([...currentTokens, ...prevTokens]);
|
|
204
|
+
const similarity = union.size === 0 ? 0 : intersection.size / union.size;
|
|
205
|
+
if (similarity > maxSimilarity) maxSimilarity = similarity;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
history.push({ thought: currentThought, entropy: maxSimilarity });
|
|
209
|
+
if (history.length > 5) history.shift(); // Sliding window of 5 thoughts
|
|
210
|
+
|
|
211
|
+
return maxSimilarity;
|
|
132
212
|
}
|
|
133
213
|
|
|
134
214
|
/**
|
|
135
215
|
* Internal AUDIT writer.
|
|
136
216
|
*/
|
|
137
|
-
_recordEvent(event, data) {
|
|
217
|
+
async _recordEvent(event, data) {
|
|
138
218
|
const entry = {
|
|
139
219
|
id: crypto.randomUUID(),
|
|
140
220
|
timestamp: new Date().toISOString(),
|
|
@@ -149,7 +229,7 @@ class NexusTracer {
|
|
|
149
229
|
entry.did = this.did;
|
|
150
230
|
// Sign the stringified entry WITHOUT the signature field itself
|
|
151
231
|
const payload = JSON.stringify(entry);
|
|
152
|
-
entry.signature = ztai.signData(this.did, payload);
|
|
232
|
+
entry.signature = await ztai.signData(this.did, payload);
|
|
153
233
|
} catch (err) {
|
|
154
234
|
console.warn(`[NexusTracer] ZTAI signing failed: ${err.message}`);
|
|
155
235
|
}
|
|
@@ -168,8 +248,8 @@ class NexusTracer {
|
|
|
168
248
|
/**
|
|
169
249
|
* Records a FinOps budget decision (Pillar V).
|
|
170
250
|
*/
|
|
171
|
-
recordFinOps(spanId, decision) {
|
|
172
|
-
this._recordEvent('finops_decision', {
|
|
251
|
+
async recordFinOps(spanId, decision) {
|
|
252
|
+
await this._recordEvent('finops_decision', {
|
|
173
253
|
span_id: spanId,
|
|
174
254
|
...decision
|
|
175
255
|
});
|
|
@@ -178,8 +258,8 @@ class NexusTracer {
|
|
|
178
258
|
/**
|
|
179
259
|
* Records a Self-Healing trigger event (Pillar VI).
|
|
180
260
|
*/
|
|
181
|
-
recordSelfHeal(spanId, report) {
|
|
182
|
-
this._recordEvent('self_heal_trigger', {
|
|
261
|
+
async recordSelfHeal(spanId, report) {
|
|
262
|
+
await this._recordEvent('self_heal_trigger', {
|
|
183
263
|
span_id: spanId,
|
|
184
264
|
...report
|
|
185
265
|
});
|
|
@@ -188,7 +268,7 @@ class NexusTracer {
|
|
|
188
268
|
/**
|
|
189
269
|
* Finalize and export the Agentic SBOM (Pillar IV).
|
|
190
270
|
*/
|
|
191
|
-
exportSBOM(outputPath = null) {
|
|
271
|
+
async exportSBOM(outputPath = null) {
|
|
192
272
|
const finalPath = outputPath || path.join(process.cwd(), '.planning', 'MANIFEST.sbom.json');
|
|
193
273
|
const manifest = {
|
|
194
274
|
...this.sbom,
|
|
@@ -203,7 +283,7 @@ class NexusTracer {
|
|
|
203
283
|
}
|
|
204
284
|
fs.writeFileSync(finalPath, JSON.stringify(manifest, null, 2));
|
|
205
285
|
|
|
206
|
-
this._recordEvent('sbom_exported', { path: finalPath });
|
|
286
|
+
await this._recordEvent('sbom_exported', { path: finalPath });
|
|
207
287
|
return finalPath;
|
|
208
288
|
} catch (err) {
|
|
209
289
|
console.error(`[NexusTracer] Failed to export SBOM: ${err.message}`);
|
|
@@ -212,4 +292,9 @@ class NexusTracer {
|
|
|
212
292
|
}
|
|
213
293
|
}
|
|
214
294
|
|
|
215
|
-
|
|
295
|
+
// Global Singleton Instance for easy mesh-wide access
|
|
296
|
+
const globalTracer = new NexusTracer();
|
|
297
|
+
|
|
298
|
+
// Export both the class and the global instance
|
|
299
|
+
module.exports = globalTracer;
|
|
300
|
+
module.exports.NexusTracer = NexusTracer;
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
const crypto = require('crypto');
|
|
8
8
|
|
|
9
|
+
// Simulated System DID for Enclave Proofs (Tier 3)
|
|
10
|
+
const ENCLAVE_PRIVATE_KEY = 'tier3-enclave-secret-key-sim'; // In production, this would be a TEE-bound private key
|
|
11
|
+
const SYSTEM_DID = 'did:mindforge:enclave:0xbeast';
|
|
12
|
+
|
|
9
13
|
class SREManager {
|
|
10
14
|
constructor() {
|
|
11
15
|
this.activeEnclaves = new Map();
|
|
@@ -26,7 +30,8 @@ class SREManager {
|
|
|
26
30
|
startedAt: new Date().toISOString(),
|
|
27
31
|
principal: context.did,
|
|
28
32
|
hasIP: true,
|
|
29
|
-
isolationLevel: 'Hardware-Enclave (Simulated)'
|
|
33
|
+
isolationLevel: 'Hardware-Enclave (Simulated)',
|
|
34
|
+
cumulativeHash: null // Root of the proof chain
|
|
30
35
|
});
|
|
31
36
|
|
|
32
37
|
console.log(`[SRE-INIT] Initialized Sovereign Reason Enclave: ${enclaveId} for ${context.did}`);
|
|
@@ -34,19 +39,68 @@ class SREManager {
|
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
|
-
* Sanitizes a thought chain
|
|
38
|
-
* Ensures that sensitive IP or "zero-visibility" thoughts are isolated.
|
|
42
|
+
* Sanitizes a thought chain and generates a ZK-Proof Compliance Certificate.
|
|
43
|
+
* Ensures that sensitive IP or "zero-visibility" thoughts are isolated while proving audit-eligibility.
|
|
39
44
|
* @param {string} thoughtChain - The raw agentic thought chain.
|
|
40
|
-
* @
|
|
45
|
+
* @param {string} enclaveId - The active enclave ID.
|
|
46
|
+
* @param {Object} policyResult - Whether the content passed internal policy checks.
|
|
47
|
+
* @returns {Object} - ZK-Proof compliance certificate.
|
|
41
48
|
*/
|
|
42
|
-
sanitizeThoughtChain(thoughtChain, enclaveId) {
|
|
43
|
-
if (!this.activeEnclaves.has(enclaveId))
|
|
49
|
+
sanitizeThoughtChain(thoughtChain, enclaveId, policyResult = { passed: true }) {
|
|
50
|
+
if (!this.activeEnclaves.has(enclaveId)) {
|
|
51
|
+
return { status: 'PLAINTEXT', content: thoughtChain };
|
|
52
|
+
}
|
|
44
53
|
|
|
45
|
-
//
|
|
46
|
-
|
|
54
|
+
// v5 Pillar VI: Merkle-style Cumulative Hash Chain
|
|
55
|
+
const enclaveData = this.activeEnclaves.get(enclaveId);
|
|
56
|
+
const prevHash = enclaveData.cumulativeHash;
|
|
47
57
|
const digest = crypto.createHash('sha256').update(thoughtChain).digest('hex');
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
// Generate a simulated ZK-Proof Compliance Certificate
|
|
60
|
+
const proofPayload = {
|
|
61
|
+
enclaveId: enclaveId,
|
|
62
|
+
digest: digest,
|
|
63
|
+
prevHash: prevHash, // Links the chain
|
|
64
|
+
policyPassed: policyResult.passed,
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
principal: enclaveData.principal
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Sign the proof with the Enclave Private Key
|
|
70
|
+
const signature = crypto.createHmac('sha256', ENCLAVE_PRIVATE_KEY)
|
|
71
|
+
.update(JSON.stringify(proofPayload))
|
|
72
|
+
.digest('hex');
|
|
73
|
+
|
|
74
|
+
// Update the cumulative hash for the next block
|
|
75
|
+
const proofHash = crypto.createHash('sha256').update(signature).digest('hex');
|
|
76
|
+
enclaveData.cumulativeHash = proofHash;
|
|
77
|
+
|
|
78
|
+
const certificate = {
|
|
79
|
+
status: 'SRE-ISOLATED',
|
|
80
|
+
proof: proofPayload,
|
|
81
|
+
signature: signature,
|
|
82
|
+
proofHash: proofHash,
|
|
83
|
+
verificationDid: SYSTEM_DID,
|
|
84
|
+
message: `[SRE-ZK-PROOF] Confidential reasoning (sha256:${digest.substring(0, 8)}...) verified by Enclave Auditor.`
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return certificate;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Verifies an SRE Compliance Certificate without seeing the original content.
|
|
92
|
+
*/
|
|
93
|
+
verifyZKProof(certificate) {
|
|
94
|
+
if (certificate.status !== 'SRE-ISOLATED') return false;
|
|
95
|
+
|
|
96
|
+
const expectedSignature = crypto.createHmac('sha256', ENCLAVE_PRIVATE_KEY)
|
|
97
|
+
.update(JSON.stringify(certificate.proof))
|
|
98
|
+
.digest('hex');
|
|
99
|
+
|
|
100
|
+
const isValid = (expectedSignature === certificate.signature);
|
|
101
|
+
const policyPassed = certificate.proof.policyPassed;
|
|
102
|
+
|
|
103
|
+
return isValid && policyPassed;
|
|
50
104
|
}
|
|
51
105
|
|
|
52
106
|
/**
|
|
@@ -83,6 +83,33 @@ class TemporalHindsight {
|
|
|
83
83
|
autoApplyStatus: 'PENDING_SIGNATURE',
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* v5 Pillar III: Proactive Loop Recovery
|
|
89
|
+
* Generates a "Steering Vector" to break agentic Reasoning Stagnation.
|
|
90
|
+
*/
|
|
91
|
+
handleProactiveRecovery(traceId, entropyScore) {
|
|
92
|
+
console.log(`[TemporalHindsight] Proactive Recovery triggered for trace ${traceId} (Entropy: ${entropyScore})`);
|
|
93
|
+
|
|
94
|
+
const steeringVectors = [
|
|
95
|
+
"CRITICAL: Stagnation detected. You have repeated similar reasoning steps 3 times. STOP your current approach and decompose the problem into smaller, independent sub-tasks.",
|
|
96
|
+
"STATIONARY LOOP: Your recent thoughts show high similarity. Change your technical layer—if you were editing code, try running a diagnostic command instead.",
|
|
97
|
+
"REASONING DEADLOCK: Entropy too low. Request human intervention or switch to the 'Architect' persona to re-evaluate the plan.",
|
|
98
|
+
"DIVERGENCE ALERT: Proactive reset. Clear your context window of the last 3 reasoning steps and start fresh from the last successful checkpoint."
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
// Pick a vector based on entropy severity
|
|
102
|
+
const index = Math.min(Math.floor(entropyScore * steeringVectors.length), steeringVectors.length - 1);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
trace_id: traceId,
|
|
107
|
+
event: 'STEERING_VECTOR_GENERATED',
|
|
108
|
+
entropy: entropyScore,
|
|
109
|
+
instruction: steeringVectors[index],
|
|
110
|
+
action: 'INJECT_SYSTEM_PROMPT'
|
|
111
|
+
};
|
|
112
|
+
}
|
|
86
113
|
}
|
|
87
114
|
|
|
88
115
|
module.exports = TemporalHindsight;
|
|
@@ -3,33 +3,97 @@
|
|
|
3
3
|
* Dynamically routes tasks across multiple cloud providers (Vertex, Bedrock, Azure).
|
|
4
4
|
*/
|
|
5
5
|
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
6
9
|
|
|
7
10
|
class CloudBroker {
|
|
8
11
|
constructor(config = {}) {
|
|
9
12
|
this.providers = config.providers || ['anthropic', 'google', 'aws', 'azure'];
|
|
13
|
+
this.statsPath = config.statsPath || path.join(__dirname, 'performance-stats.json');
|
|
14
|
+
this.blacklist = new Map(); // provider -> expiry (Date)
|
|
15
|
+
this.failureWindow = new Map(); // provider:taskType -> count
|
|
10
16
|
this.state = {
|
|
11
17
|
'anthropic': { latency: 450, costMultiplier: 1.0, healthy: true },
|
|
12
18
|
'google': { latency: 600, costMultiplier: 0.85, healthy: true },
|
|
13
19
|
'aws': { latency: 550, costMultiplier: 0.95, healthy: true },
|
|
14
20
|
'azure': { latency: 650, costMultiplier: 1.1, healthy: true }
|
|
15
21
|
};
|
|
22
|
+
this.reloadStats();
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
/**
|
|
19
|
-
*
|
|
20
|
-
|
|
26
|
+
* Loads performance stats from persistent storage and applies decay (0.95 factor).
|
|
27
|
+
*/
|
|
28
|
+
reloadStats() {
|
|
29
|
+
try {
|
|
30
|
+
if (fs.existsSync(this.statsPath)) {
|
|
31
|
+
const raw = JSON.parse(fs.readFileSync(this.statsPath, 'utf8'));
|
|
32
|
+
|
|
33
|
+
// v5 Pillar V: Metrics Decay (Hyper-Enterprise Hardening)
|
|
34
|
+
// Ensure historical data doesn't anchor the model if recent performance shifts.
|
|
35
|
+
this.performanceStats = {};
|
|
36
|
+
for (const [provider, tasks] of Object.entries(raw)) {
|
|
37
|
+
this.performanceStats[provider] = {};
|
|
38
|
+
for (const [task, stats] of Object.entries(tasks)) {
|
|
39
|
+
this.performanceStats[provider][task] = {
|
|
40
|
+
success: stats.success * 0.95,
|
|
41
|
+
failure: stats.failure * 0.95
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
this.performanceStats = {};
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.warn(`[MCA-WARN] Failed to load performance stats: ${e.message}`);
|
|
50
|
+
this.performanceStats = {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Selects the optimal provider based on weighted latency, cost, and historical success.
|
|
56
|
+
* @param {Object} requirements - Task requirements (maxLatency, budgetConstraint, taskType)
|
|
21
57
|
* @returns {string} - Best provider ID
|
|
22
58
|
*/
|
|
23
59
|
getBestProvider(requirements = {}) {
|
|
60
|
+
this.reloadStats(); // Just-In-Time refresh for latest feedback loop data
|
|
61
|
+
const taskType = requirements.taskType || 'default';
|
|
62
|
+
|
|
24
63
|
const scored = Object.entries(this.state)
|
|
25
|
-
.filter(([
|
|
64
|
+
.filter(([id, data]) => {
|
|
65
|
+
// v5 Pillar V: Circuit Breaker Verification
|
|
66
|
+
if (!data.healthy) return false;
|
|
67
|
+
const blacklistExpiry = this.blacklist.get(id);
|
|
68
|
+
if (blacklistExpiry && blacklistExpiry > new Date()) {
|
|
69
|
+
return false; // Circuit is OPEN (Blacklisted)
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
})
|
|
26
73
|
.map(([id, data]) => {
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
|
|
74
|
+
// Calculate Success Probability for this task
|
|
75
|
+
const stats = this.performanceStats[id]?.[taskType] || { success: 1, failure: 0 };
|
|
76
|
+
const totalTasks = stats.success + stats.failure;
|
|
77
|
+
const successProb = totalTasks > 0 ? (stats.success / totalTasks) : 0.5;
|
|
78
|
+
|
|
79
|
+
// Score Calculation (The "Affinity" Algorithm)
|
|
80
|
+
const latencyWeight = 0.2;
|
|
81
|
+
const costWeight = 0.3;
|
|
82
|
+
const affinityWeight = 0.5;
|
|
83
|
+
|
|
84
|
+
const score = (data.latency * latencyWeight) +
|
|
85
|
+
(data.costMultiplier * 1000 * costWeight) +
|
|
86
|
+
((1.0 - successProb) * 2000 * affinityWeight);
|
|
87
|
+
|
|
88
|
+
return { id, score, successProb: successProb.toFixed(2) };
|
|
30
89
|
});
|
|
31
90
|
|
|
32
91
|
scored.sort((a, b) => a.score - b.score);
|
|
92
|
+
|
|
93
|
+
if (scored.length > 0) {
|
|
94
|
+
console.log(`[MCA-ROUTE] Selected provider: ${scored[0].id} (Affinity: ${scored[0].successProb} for '${taskType}')`);
|
|
95
|
+
}
|
|
96
|
+
|
|
33
97
|
return scored[0]?.id || 'anthropic';
|
|
34
98
|
}
|
|
35
99
|
|
|
@@ -53,20 +117,34 @@ class CloudBroker {
|
|
|
53
117
|
|
|
54
118
|
/**
|
|
55
119
|
* Retrieves provider-specific model mapping.
|
|
56
|
-
* @param {string} provider - Provider ID
|
|
57
|
-
* @param {string} modelGroup - e.g., 'sonnet', 'opus', 'haiku'
|
|
58
120
|
*/
|
|
59
121
|
mapToProviderModel(provider, modelGroup) {
|
|
60
122
|
const mappings = {
|
|
61
123
|
'anthropic': { 'sonnet': 'claude-3-5-sonnet', 'opus': 'claude-3-opus', 'haiku': 'claude-3-haiku' },
|
|
62
|
-
'google': { 'sonnet': 'gemini-1.5-pro', '
|
|
63
|
-
'aws': { 'sonnet': 'anthropic.claude-3-5-sonnet-v2:0', '
|
|
64
|
-
'azure': { 'sonnet': 'gpt-4o', '
|
|
124
|
+
'google': { 'sonnet': 'gemini-1.5-pro', 'haiku': 'gemini-1.5-flash' },
|
|
125
|
+
'aws': { 'sonnet': 'anthropic.claude-3-5-sonnet-v2:0', 'haiku': 'anthropic.claude-3-haiku-v1:0' },
|
|
126
|
+
'azure': { 'sonnet': 'gpt-4o', 'haiku': 'gpt-35-turbo' }
|
|
65
127
|
};
|
|
66
128
|
|
|
67
129
|
return mappings[provider]?.[modelGroup] || mappings[provider]?.['sonnet'];
|
|
68
130
|
}
|
|
69
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Records a task failure and manages the circuit breaker.
|
|
134
|
+
*/
|
|
135
|
+
recordFailure(provider, taskType = 'default') {
|
|
136
|
+
const key = `${provider}:${taskType}`;
|
|
137
|
+
const failures = (this.failureWindow.get(key) || 0) + 1;
|
|
138
|
+
this.failureWindow.set(key, failures);
|
|
139
|
+
|
|
140
|
+
if (failures >= 3) {
|
|
141
|
+
const expiry = new Date(Date.now() + 10 * 60 * 1000); // 10 min blacklist
|
|
142
|
+
this.blacklist.set(provider, expiry);
|
|
143
|
+
console.warn(`[MCA-CIRCUIT-OPEN] Provider '${provider}' blacklisted for 10 min due to consecutive failures on '${taskType}'.`);
|
|
144
|
+
this.failureWindow.set(key, 0); // Reset window upon blacklisting
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
70
148
|
/**
|
|
71
149
|
* Hardening: Simulate provider failures to verify Fallback Protocol.
|
|
72
150
|
*/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"anthropic": {
|
|
3
|
+
"refactor": { "success": 45, "failure": 2 },
|
|
4
|
+
"test": { "success": 30, "failure": 1 },
|
|
5
|
+
"architect": { "success": 12, "failure": 0 }
|
|
6
|
+
},
|
|
7
|
+
"google": {
|
|
8
|
+
"refactor": { "success": 25, "failure": 8 },
|
|
9
|
+
"test": { "success": 50, "failure": 2 },
|
|
10
|
+
"architect": { "success": 8, "failure": 4 }
|
|
11
|
+
},
|
|
12
|
+
"aws": {
|
|
13
|
+
"refactor": { "success": 20, "failure": 5 },
|
|
14
|
+
"test": { "success": 15, "failure": 5 },
|
|
15
|
+
"architect": { "success": 5, "failure": 2 }
|
|
16
|
+
},
|
|
17
|
+
"azure": {
|
|
18
|
+
"refactor": { "success": 10, "failure": 10 },
|
|
19
|
+
"test": { "success": 20, "failure": 5 },
|
|
20
|
+
"architect": { "success": 3, "failure": 5 }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindForge v5.10.0 — AgRevOps Governance Debt Monitor
|
|
3
|
+
* Calculates Security Health Score and Governance Debt.
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
class DebtMonitor {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.auditPath = path.join(process.cwd(), '.planning', 'AUDIT.jsonl');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Monitor governance debt and security health.
|
|
17
|
+
* @param {Object} metrics - From MetricsAggregator
|
|
18
|
+
*/
|
|
19
|
+
monitor(metrics) {
|
|
20
|
+
const auditEntries = metrics.auditEntries || [];
|
|
21
|
+
|
|
22
|
+
// 1. Identify high-risk events
|
|
23
|
+
const criticalFindings = auditEntries.filter(e => e.event === 'security_finding' && e.severity === 'critical');
|
|
24
|
+
const tier3Approvals = auditEntries.filter(e => e.event === 'approval_granted' && e.tier === 3);
|
|
25
|
+
const policyBypasses = auditEntries.filter(e => e.event === 'policy_bypass');
|
|
26
|
+
|
|
27
|
+
// 2. Calculate Health Score (starts at 100)
|
|
28
|
+
let score = 100;
|
|
29
|
+
score -= (criticalFindings.length * 10);
|
|
30
|
+
score -= (tier3Approvals.length * 5);
|
|
31
|
+
score -= (policyBypasses.length * 15);
|
|
32
|
+
|
|
33
|
+
const healthScore = Math.max(0, score);
|
|
34
|
+
|
|
35
|
+
// 3. Determine status
|
|
36
|
+
let status = 'Excellent';
|
|
37
|
+
if (healthScore < 90) status = 'Good';
|
|
38
|
+
if (healthScore < 75) status = 'Warning';
|
|
39
|
+
if (healthScore < 50) status = 'Critical';
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
security_health_score: healthScore,
|
|
43
|
+
governance_status: status,
|
|
44
|
+
critical_findings: criticalFindings.length,
|
|
45
|
+
tier3_approvals: tier3Approvals.length,
|
|
46
|
+
policy_bypasses: policyBypasses.length,
|
|
47
|
+
debt_level: this.getDebtLevel(healthScore),
|
|
48
|
+
timestamp: new Date().toISOString()
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getDebtLevel(score) {
|
|
53
|
+
if (score >= 95) return 'Minimal';
|
|
54
|
+
if (score >= 80) return 'Managing';
|
|
55
|
+
if (score >= 60) return 'Moderate';
|
|
56
|
+
return 'High';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = new DebtMonitor();
|