progmune-runtime 2.0.4 → 2.1.1
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/.mcp.json +11 -0
- package/.progmune_allowlist +50 -0
- package/.test_report/test_report.md +87 -0
- package/Dockerfile +2 -10
- package/FAQ.md +167 -0
- package/README.md +108 -54
- package/demo-project/auth.ts +55 -0
- package/demo-project/tsconfig.json +8 -0
- package/dist/ab-stats.js +11 -0
- package/dist/acl-breakdown.js +13 -0
- package/dist/action-runtime.js +1 -0
- package/dist/all-sessions.js +11 -0
- package/dist/antibody-stats.js +11 -0
- package/dist/audit.js +222 -0
- package/dist/benchmark-count.js +7 -0
- package/dist/benchmark-full.js +17 -0
- package/dist/benchmark-pass-rate.js +54 -0
- package/dist/benchmark-report.js +67 -0
- package/dist/benchmark-save.js +62 -0
- package/dist/benchmark-status.js +15 -0
- package/dist/branch-ledger.js +393 -0
- package/dist/branch-tree-count.js +14 -0
- package/dist/check.js +506 -0
- package/dist/common-fixpath.js +12 -0
- package/dist/constraint-types.js +12 -0
- package/dist/deterministic-replay.js +283 -0
- package/dist/emitter.js +143 -12
- package/dist/exec-metrics.js +11 -0
- package/dist/execute.js +251 -0
- package/dist/extract-ir.js +592 -5
- package/dist/failure-collector.js +163 -0
- package/dist/failure-corpus.js +507 -35
- package/dist/failure-report.js +11 -0
- package/dist/failures.js +11 -0
- package/dist/fast-path-hits.js +13 -0
- package/dist/feedback.js +10 -3
- package/dist/file-lock.js +82 -0
- package/dist/find-session.js +10 -0
- package/dist/fingerprint-list.js +15 -0
- package/dist/gen-history-log.js +13 -0
- package/dist/generate.js +2 -1
- package/dist/generate_500.js +4 -2
- package/dist/genome.js +11 -0
- package/dist/heatmap-data.js +11 -0
- package/dist/heatmap.js +11 -0
- package/dist/immune-reporter.js +34 -22
- package/dist/ir-utils.js +18 -0
- package/dist/learned.js +11 -0
- package/dist/ledger-registry.js +252 -0
- package/dist/llm.js +46 -2
- package/dist/load-benchmarks.js +47 -0
- package/dist/main.js +2 -1
- package/dist/mcp-server.mjs +445 -43
- package/dist/memory-layer.js +54 -13
- package/dist/metrics.js +11 -0
- package/dist/obs-web.js +561 -0
- package/dist/p0_ssg_demo.js +255 -40
- package/dist/planner.js +996 -80
- package/dist/protocol-registry.js +112 -0
- package/dist/recent-session.js +12 -0
- package/dist/repair-proposal.js +363 -0
- package/dist/runtime-invariants.js +170 -0
- package/dist/runtime-types.js +117 -0
- package/dist/runtime.js +1 -0
- package/dist/search-planner.js +39 -9
- package/dist/semantic-snapshot.js +157 -0
- package/dist/semantic-trace.js +1497 -0
- package/dist/semantic-validator.js +3 -2
- package/dist/semantic_guard_test.js +2 -1
- package/dist/session-utils.js +19 -0
- package/dist/sessions.js +11 -0
- package/dist/ssg-validator.js +666 -20
- package/dist/svl-distribution.js +11 -0
- package/dist/terminal-status.js +11 -0
- package/dist/test_failure_corpus.js +3 -1
- package/dist/token-savings.js +11 -0
- package/dist/total-repairs.js +12 -0
- package/dist/unresolved-count.js +12 -0
- package/dist/utils.js +2 -0
- package/dist/valid-fingerprints.js +13 -0
- package/dist/validator.js +118 -60
- package/dist/verify-fps.js +11 -0
- package/dist/verify-ledgers.js +11 -0
- package/docs/whitepaper-style.css +77 -0
- package/docs/whitepaper-v2.1.md +609 -0
- package/docs/whitepaper-v2.2.md +1064 -0
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +1 -1
- package/package.json +13 -4
- package/protocols.json +131 -11
- package/public/dashboard.html +119 -0
- package/server/hub.js +84 -12
- package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
- package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
- package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
- package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
- package/test/replay-golden.ts +84 -0
- package/test_benchmark.js +165 -0
- package/test_comprehensive.mjs +638 -0
- package/test_concurrency.js +129 -0
- package/test_ir_robustness.js +85 -0
- package/test_semantic_contracts.js +269 -0
- package/test_ssg_stress.js +156 -0
- package/test_svl3.js +58 -0
- package/tsconfig.json +1 -1
- package/.env.example +0 -3
- package/.progmune_memory/episodic.json +0 -186
- package/.progmune_memory/fingerprints.json +0 -7
- package/.progmune_memory/opt_in.json +0 -4
- package/immune_hub_data/2026-05-14.json +0 -50
package/dist/failure-corpus.js
CHANGED
|
@@ -33,81 +33,553 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.saveCheckpoint = saveCheckpoint;
|
|
37
|
+
exports.loadCheckpoint = loadCheckpoint;
|
|
38
|
+
exports.clearCheckpoint = clearCheckpoint;
|
|
36
39
|
exports.recordFailure = recordFailure;
|
|
40
|
+
exports.recordSession = recordSession;
|
|
37
41
|
exports.getAllFailures = getAllFailures;
|
|
38
42
|
exports.getFailuresBySVL = getFailuresBySVL;
|
|
39
43
|
exports.getTopFailurePatterns = getTopFailurePatterns;
|
|
44
|
+
exports.getFailureGenome = getFailureGenome;
|
|
45
|
+
exports.getAllSessions = getAllSessions;
|
|
46
|
+
exports.getLearnedPatterns = getLearnedPatterns;
|
|
47
|
+
exports.queryAntibodies = queryAntibodies;
|
|
48
|
+
exports.getSemanticHeatmap = getSemanticHeatmap;
|
|
49
|
+
exports.getAntibodyStats = getAntibodyStats;
|
|
40
50
|
exports.generateCandidateRules = generateCandidateRules;
|
|
41
51
|
const fs = __importStar(require("fs"));
|
|
42
52
|
const path = __importStar(require("path"));
|
|
43
|
-
const
|
|
53
|
+
const file_lock_1 = require("./file-lock");
|
|
54
|
+
// 优先使用 PROGMUNE_PROJECT_DIR(由 MCP 服务器在调用时设置),确保多项目隔离
|
|
55
|
+
const projectDir = process.env.PROGMUNE_PROJECT_DIR || process.cwd();
|
|
56
|
+
const CORPUS_DIR = process.env.PROGMUNE_CORPUS_DIR
|
|
57
|
+
|| path.resolve(projectDir, ".progmune_corpus");
|
|
58
|
+
const SESSIONS_DIR = path.join(CORPUS_DIR, "sessions");
|
|
59
|
+
const CHECKPOINT_DIR = path.join(CORPUS_DIR, "checkpoints");
|
|
44
60
|
function ensureDir(dir) {
|
|
45
61
|
if (!fs.existsSync(dir))
|
|
46
62
|
fs.mkdirSync(dir, { recursive: true });
|
|
47
63
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
function checkpointPath(intent) {
|
|
65
|
+
// 用 intent 的稳定 hash 作为文件名,避免特殊字符
|
|
66
|
+
const hash = Buffer.from(intent).toString("base64").replace(/[/+=]/g, "_").slice(0, 32);
|
|
67
|
+
return path.join(CHECKPOINT_DIR, `ckpt_${hash}.json`);
|
|
68
|
+
}
|
|
69
|
+
/** Save planner checkpoint for crash recovery. */
|
|
70
|
+
function saveCheckpoint(intent, data) {
|
|
71
|
+
ensureDir(CHECKPOINT_DIR);
|
|
72
|
+
const cp = {
|
|
73
|
+
...data,
|
|
74
|
+
intent,
|
|
57
75
|
timestamp: new Date().toISOString(),
|
|
58
76
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
fs.writeFileSync(checkpointPath(intent), JSON.stringify(cp, null, 2));
|
|
78
|
+
}
|
|
79
|
+
/** Load a previously saved planner checkpoint. */
|
|
80
|
+
function loadCheckpoint(intent) {
|
|
81
|
+
try {
|
|
82
|
+
const raw = fs.readFileSync(checkpointPath(intent), "utf-8");
|
|
83
|
+
return JSON.parse(raw);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Clear a saved planner checkpoint. */
|
|
90
|
+
function clearCheckpoint(intent) {
|
|
91
|
+
try {
|
|
92
|
+
fs.unlinkSync(checkpointPath(intent));
|
|
93
|
+
}
|
|
94
|
+
catch { }
|
|
63
95
|
}
|
|
96
|
+
/** Record a constraint violation to the failure corpus. */
|
|
97
|
+
function recordFailure(record) {
|
|
98
|
+
(0, file_lock_1.withLock)("failure-corpus", () => {
|
|
99
|
+
ensureDir(CORPUS_DIR);
|
|
100
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
101
|
+
const dateDir = path.join(CORPUS_DIR, date);
|
|
102
|
+
ensureDir(dateDir);
|
|
103
|
+
const seqFile = path.join(CORPUS_DIR, ".seq");
|
|
104
|
+
let seq = 0;
|
|
105
|
+
try {
|
|
106
|
+
seq = parseInt(fs.readFileSync(seqFile, 'utf-8'), 10);
|
|
107
|
+
}
|
|
108
|
+
catch { }
|
|
109
|
+
seq++;
|
|
110
|
+
fs.writeFileSync(seqFile, String(seq));
|
|
111
|
+
const id = `fail_${Date.now()}_${seq}`;
|
|
112
|
+
const fullRecord = {
|
|
113
|
+
...record,
|
|
114
|
+
id,
|
|
115
|
+
timestamp: new Date().toISOString(),
|
|
116
|
+
plannerAttempt: record.plannerAttempt || 1,
|
|
117
|
+
plannerRetryTotal: record.plannerRetryTotal || 1,
|
|
118
|
+
};
|
|
119
|
+
const filename = `${id}.json`;
|
|
120
|
+
fs.writeFileSync(path.join(dateDir, filename), JSON.stringify(fullRecord, null, 2));
|
|
121
|
+
console.error(`[FailureCorpus] ${record.violatedSVL} | 尝试 ${record.plannerAttempt}/${record.plannerRetryTotal} | ${id}`);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/** 记录一个完整的意图会话(支持 ExecutionSession 和旧 IntentSession) */
|
|
125
|
+
/**
|
|
126
|
+
* 保存执行会话(含所有尝试、违规、状态转移)。
|
|
127
|
+
* @protocol namespace=dev_pipeline pre_states=["CODE_EMITTED"] post_states=["SESSION_RECORDED"] invalidate=["CODE_EMITTED"]
|
|
128
|
+
*/
|
|
129
|
+
/** @requires EXECUTION_DATA @produces SESSION_ID */
|
|
130
|
+
/** @requires EXECUTION_DATA @produces SESSION_ID */
|
|
131
|
+
function recordSession(session) {
|
|
132
|
+
ensureDir(SESSIONS_DIR);
|
|
133
|
+
const sessionId = session.sessionId || `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
134
|
+
// 检测新格式:ExecutionSession has .attempts[0]?.violations
|
|
135
|
+
const isExecutionSession = session.attempts?.length > 0 && session.attempts[0].violations;
|
|
136
|
+
if (isExecutionSession) {
|
|
137
|
+
// 新格式:直接保存 ExecutionSession
|
|
138
|
+
const fullSession = { ...session, sessionId };
|
|
139
|
+
fs.writeFileSync(path.join(SESSIONS_DIR, `${sessionId}.json`), JSON.stringify(fullSession, null, 2));
|
|
140
|
+
// 为每个违规的 attempt 记录到 failure corpus(向后兼容)
|
|
141
|
+
for (const attempt of fullSession.attempts) {
|
|
142
|
+
for (const violation of attempt.violations) {
|
|
143
|
+
const svlStr = `SVL-${violation.svl}`;
|
|
144
|
+
const blockingFn = attempt.generatedActions[violation.actionIndex];
|
|
145
|
+
recordFailure({
|
|
146
|
+
intent: fullSession.intent,
|
|
147
|
+
projectFunctions: [],
|
|
148
|
+
violatedSVL: svlStr,
|
|
149
|
+
constraintType: violation.violatedConstraint,
|
|
150
|
+
actionSequence: attempt.generatedActions,
|
|
151
|
+
errorDetail: violation.description,
|
|
152
|
+
ssgState: violation.currentStates,
|
|
153
|
+
ssgFixPath: violation.fixPath,
|
|
154
|
+
ssgMissingFunctions: violation.missingStates,
|
|
155
|
+
plannerAttempt: attempt.attemptNumber,
|
|
156
|
+
plannerRetryTotal: fullSession.attempts.length,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return sessionId;
|
|
161
|
+
}
|
|
162
|
+
// 旧格式:兼容保存
|
|
163
|
+
const fullSession = { ...session, sessionId };
|
|
164
|
+
fs.writeFileSync(path.join(SESSIONS_DIR, `${sessionId}.json`), JSON.stringify(fullSession, null, 2));
|
|
165
|
+
return sessionId;
|
|
166
|
+
}
|
|
167
|
+
/** @requires FAILURE_CORPUS @produces FAILURE_LIST */
|
|
64
168
|
function getAllFailures() {
|
|
65
169
|
const records = [];
|
|
66
170
|
if (!fs.existsSync(CORPUS_DIR))
|
|
67
171
|
return records;
|
|
68
|
-
const dirs = fs.readdirSync(CORPUS_DIR);
|
|
172
|
+
const dirs = fs.readdirSync(CORPUS_DIR).filter(d => d !== 'sessions');
|
|
69
173
|
for (const dir of dirs) {
|
|
70
174
|
const dirPath = path.join(CORPUS_DIR, dir);
|
|
71
175
|
if (!fs.statSync(dirPath).isDirectory())
|
|
72
176
|
continue;
|
|
73
|
-
const
|
|
74
|
-
for (const file of files) {
|
|
177
|
+
for (const file of fs.readdirSync(dirPath)) {
|
|
75
178
|
if (file.endsWith(".json")) {
|
|
76
|
-
|
|
77
|
-
|
|
179
|
+
try {
|
|
180
|
+
records.push(JSON.parse(fs.readFileSync(path.join(dirPath, file), "utf-8")));
|
|
181
|
+
}
|
|
182
|
+
catch { }
|
|
78
183
|
}
|
|
79
184
|
}
|
|
80
185
|
}
|
|
81
186
|
return records;
|
|
82
187
|
}
|
|
188
|
+
/** @requires FAILURE_LIST @produces FILTERED_FAILURES */
|
|
83
189
|
function getFailuresBySVL(level) {
|
|
84
190
|
return getAllFailures().filter(r => r.violatedSVL === level);
|
|
85
191
|
}
|
|
192
|
+
/** @requires FAILURE_LIST @produces FAILURE_PATTERNS */
|
|
86
193
|
function getTopFailurePatterns(limit = 5) {
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
for (const r of all) {
|
|
194
|
+
const groups = new Map();
|
|
195
|
+
for (const r of getAllFailures()) {
|
|
90
196
|
const key = `${r.violatedSVL}:${r.constraintType}`;
|
|
91
|
-
|
|
197
|
+
const entry = groups.get(key) || { count: 0, examples: [] };
|
|
198
|
+
entry.count++;
|
|
199
|
+
if (entry.examples.length < 3)
|
|
200
|
+
entry.examples.push(r.intent);
|
|
201
|
+
groups.set(key, entry);
|
|
92
202
|
}
|
|
93
|
-
return [...
|
|
94
|
-
.map(([pattern,
|
|
203
|
+
return [...groups.entries()]
|
|
204
|
+
.map(([pattern, entry]) => ({ pattern, count: entry.count, examples: entry.examples }))
|
|
95
205
|
.sort((a, b) => b.count - a.count)
|
|
96
206
|
.slice(0, limit);
|
|
97
207
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
208
|
+
/** 构建 AI 失败基因组 —— 按失效模式分组的完整画像 */
|
|
209
|
+
/** Get failure genome statistics: total failures, SVL distribution, constraint types, top patterns.
|
|
210
|
+
* @tags failure, statistics, genome, audit
|
|
211
|
+
*/
|
|
212
|
+
/** Get failure genome statistics: total failures by SVL, constraint type, and fix path. */
|
|
213
|
+
/** @requires FAILURE_DATA @produces FAILURE_GENOME */
|
|
214
|
+
/** @requires FAILURE_DATA @produces FAILURE_GENOME */
|
|
215
|
+
function getFailureGenome() {
|
|
216
|
+
const sessions = getAllSessions();
|
|
217
|
+
const bySVL = { "SVL-1": 0, "SVL-2": 0, "SVL-3": 0, "SVL-4": 0 };
|
|
218
|
+
const byConstraint = {};
|
|
219
|
+
const patternCounts = new Map();
|
|
220
|
+
const fixPathCounts = new Map();
|
|
221
|
+
let totalViolations = 0;
|
|
222
|
+
let totalRetries = 0;
|
|
223
|
+
let resolvedSessions = 0;
|
|
224
|
+
for (const s of sessions) {
|
|
225
|
+
const sessionRetries = s.attempts.filter(a => a.outcome !== "success").length;
|
|
226
|
+
totalRetries += sessionRetries;
|
|
227
|
+
if (s.resolved)
|
|
228
|
+
resolvedSessions++;
|
|
229
|
+
for (const a of s.attempts) {
|
|
230
|
+
for (const v of a.violations) {
|
|
231
|
+
totalViolations++;
|
|
232
|
+
const svlKey = `SVL-${v.svl}`;
|
|
233
|
+
bySVL[svlKey] = (bySVL[svlKey] || 0) + 1;
|
|
234
|
+
const ct = v.violatedConstraint || "unknown";
|
|
235
|
+
byConstraint[ct] = (byConstraint[ct] || 0) + 1;
|
|
236
|
+
// Pattern grouping
|
|
237
|
+
const patternKey = `${svlKey}:${ct}`;
|
|
238
|
+
const entry = patternCounts.get(patternKey) || { count: 0, examples: [] };
|
|
239
|
+
entry.count++;
|
|
240
|
+
if (entry.examples.length < 3)
|
|
241
|
+
entry.examples.push(s.intent);
|
|
242
|
+
patternCounts.set(patternKey, entry);
|
|
243
|
+
if (v.fixPath && v.fixPath.length > 0) {
|
|
244
|
+
const key = `${svlKey}:${v.fixPath.join("→")}`;
|
|
245
|
+
fixPathCounts.set(key, (fixPathCounts.get(key) || 0) + 1);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const topPatterns = [...patternCounts.entries()]
|
|
251
|
+
.map(([pattern, entry]) => ({ pattern, count: entry.count, examples: entry.examples }))
|
|
252
|
+
.sort((a, b) => b.count - a.count)
|
|
253
|
+
.slice(0, 5);
|
|
254
|
+
const commonFixPaths = [...fixPathCounts.entries()]
|
|
255
|
+
.map(([key, count]) => {
|
|
256
|
+
const [violation, ...rest] = key.split(":");
|
|
257
|
+
return { violation, fixPath: rest.join(":").split("→"), count };
|
|
258
|
+
})
|
|
259
|
+
.sort((a, b) => b.count - a.count)
|
|
260
|
+
.slice(0, 10);
|
|
261
|
+
return {
|
|
262
|
+
totalFailures: totalViolations,
|
|
263
|
+
bySVL,
|
|
264
|
+
byConstraintType: byConstraint,
|
|
265
|
+
topPatterns,
|
|
266
|
+
commonFixPaths,
|
|
267
|
+
averageRetriesToSuccess: totalViolations > 0 ? Math.round((totalRetries / totalViolations) * 10) / 10 : 0,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/** 获取所有意图会话(归一化为 ExecutionSession[]) */
|
|
271
|
+
/** Load all execution sessions from the corpus directory.
|
|
272
|
+
* @tags session, corpus, audit, history
|
|
273
|
+
*/
|
|
274
|
+
/** @requires SESSION_DATA @produces SESSION_LIST */
|
|
275
|
+
/** @requires SESSION_CORPUS @produces SESSION_LIST */
|
|
276
|
+
/** @requires SESSION_CORPUS @produces SESSION_LIST */
|
|
277
|
+
/** @requires SESSION_CORPUS @produces SESSION_LIST */
|
|
278
|
+
function getAllSessions() {
|
|
279
|
+
const sessions = [];
|
|
280
|
+
if (!fs.existsSync(SESSIONS_DIR))
|
|
281
|
+
return sessions;
|
|
282
|
+
for (const file of fs.readdirSync(SESSIONS_DIR)) {
|
|
283
|
+
if (file.endsWith(".json")) {
|
|
284
|
+
try {
|
|
285
|
+
const raw = JSON.parse(fs.readFileSync(path.join(SESSIONS_DIR, file), "utf-8"));
|
|
286
|
+
sessions.push(normalizeSession(raw));
|
|
287
|
+
}
|
|
288
|
+
catch { }
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return sessions;
|
|
292
|
+
}
|
|
293
|
+
/** 检测并归一化新旧两种会话格式 */
|
|
294
|
+
function normalizeSession(raw) {
|
|
295
|
+
// 新格式:attempts[0] 有 violations 字段
|
|
296
|
+
if (raw.attempts?.length > 0 && raw.attempts[0].violations) {
|
|
297
|
+
return raw;
|
|
298
|
+
}
|
|
299
|
+
// 旧 IntentSession 格式 → 上转
|
|
300
|
+
return convertOldSession(raw);
|
|
301
|
+
}
|
|
302
|
+
/** 将旧 IntentSession 转换为 ExecutionSession */
|
|
303
|
+
function convertOldSession(old) {
|
|
304
|
+
const attempts = (old.attempts || []).map((sa, i) => ({
|
|
305
|
+
id: `${old.sessionId}_att_${i + 1}`,
|
|
306
|
+
sessionId: old.sessionId,
|
|
307
|
+
attemptNumber: sa.plannerAttempt || i + 1,
|
|
308
|
+
inputIntent: old.intent,
|
|
309
|
+
plannerSeed: old.sessionId,
|
|
310
|
+
constraintSnapshotId: old.snapshotId || "",
|
|
311
|
+
generatedActions: sa.actionSequence || [],
|
|
312
|
+
transitions: [],
|
|
313
|
+
violations: [{
|
|
314
|
+
svl: parseInt((sa.violatedSVL || "SVL-1").split("-")[1]),
|
|
315
|
+
violatedConstraint: sa.constraintType || "unknown",
|
|
316
|
+
actionIndex: 0,
|
|
317
|
+
currentStates: sa.ssgState,
|
|
318
|
+
missingStates: sa.ssgMissingFunctions,
|
|
319
|
+
fixPath: sa.ssgFixPath,
|
|
320
|
+
description: sa.errorDetail || "",
|
|
321
|
+
}],
|
|
322
|
+
outcome: "constraint_violation",
|
|
323
|
+
timestamp: new Date(old.timestamp).getTime(),
|
|
324
|
+
llmCallCount: 1,
|
|
325
|
+
durationMs: 0,
|
|
326
|
+
}));
|
|
327
|
+
return {
|
|
328
|
+
sessionId: old.sessionId,
|
|
329
|
+
intent: old.intent,
|
|
330
|
+
attempts,
|
|
331
|
+
successfulAttempt: old.resolved && old.successfulAlternative
|
|
332
|
+
? {
|
|
333
|
+
id: `${old.sessionId}_success`,
|
|
334
|
+
sessionId: old.sessionId,
|
|
335
|
+
attemptNumber: old.totalRetries + 1,
|
|
336
|
+
inputIntent: old.intent,
|
|
337
|
+
plannerSeed: old.sessionId,
|
|
338
|
+
constraintSnapshotId: old.snapshotId || "",
|
|
339
|
+
generatedActions: old.successfulAlternative,
|
|
340
|
+
transitions: [],
|
|
341
|
+
violations: [],
|
|
342
|
+
outcome: "success",
|
|
343
|
+
timestamp: new Date(old.timestamp).getTime(),
|
|
344
|
+
llmCallCount: old.totalRetries,
|
|
345
|
+
durationMs: 0,
|
|
346
|
+
}
|
|
347
|
+
: undefined,
|
|
348
|
+
resolved: old.resolved,
|
|
349
|
+
snapshotId: old.snapshotId,
|
|
350
|
+
startedAt: new Date(old.timestamp).getTime(),
|
|
351
|
+
endedAt: new Date(old.timestamp).getTime(),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function computeACL(count, distinctIntents, resolvedRate) {
|
|
355
|
+
const acl4Count = parseInt(process.env.PROGMUNE_ACL4_COUNT || "10", 10);
|
|
356
|
+
const acl4Intents = parseInt(process.env.PROGMUNE_ACL4_INTENTS || "5", 10);
|
|
357
|
+
const acl3Count = parseInt(process.env.PROGMUNE_ACL3_COUNT || "4", 10);
|
|
358
|
+
const acl3Intents = parseInt(process.env.PROGMUNE_ACL3_INTENTS || "3", 10);
|
|
359
|
+
const acl2Count = parseInt(process.env.PROGMUNE_ACL2_COUNT || "2", 10);
|
|
360
|
+
if (count >= acl4Count && distinctIntents >= acl4Intents)
|
|
361
|
+
return "ACL-4";
|
|
362
|
+
if (count >= acl3Count || distinctIntents >= acl3Intents)
|
|
363
|
+
return "ACL-3";
|
|
364
|
+
if (count >= acl2Count)
|
|
365
|
+
return "ACL-2";
|
|
366
|
+
return "ACL-1";
|
|
367
|
+
}
|
|
368
|
+
/** Get antibody patterns learned from failure history. */
|
|
369
|
+
/** @requires FAILURE_HISTORY @produces LEARNED_PATTERNS */
|
|
370
|
+
function getLearnedPatterns() {
|
|
371
|
+
const sessions = getAllSessions();
|
|
372
|
+
const agg = new Map();
|
|
373
|
+
for (const s of sessions) {
|
|
374
|
+
for (const a of s.attempts) {
|
|
375
|
+
// Extract SSG violations from Attempt.violations
|
|
376
|
+
for (const v of a.violations) {
|
|
377
|
+
if (!v.fixPath || v.fixPath.length === 0)
|
|
378
|
+
continue;
|
|
379
|
+
if (v.svl !== 4)
|
|
380
|
+
continue; // only SVL-4 has fix paths
|
|
381
|
+
const violatedLabel = `SVL-${v.svl}`;
|
|
382
|
+
const missingKey = (v.missingStates || ["unknown"]).join(",");
|
|
383
|
+
const signature = `${violatedLabel}:${missingKey}`;
|
|
384
|
+
const existing = agg.get(signature);
|
|
385
|
+
const ts = new Date(s.startedAt).toISOString();
|
|
386
|
+
if (existing) {
|
|
387
|
+
existing.count++;
|
|
388
|
+
existing.intents.add(s.intent);
|
|
389
|
+
if (s.resolved)
|
|
390
|
+
existing.resolvedCount++;
|
|
391
|
+
if (ts > existing.lastSeen)
|
|
392
|
+
existing.lastSeen = ts;
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
agg.set(signature, {
|
|
396
|
+
violation: `${violatedLabel}: ${(v.missingStates || ["unknown"]).join(", ")}`,
|
|
397
|
+
fixPath: v.fixPath,
|
|
398
|
+
count: 1,
|
|
399
|
+
intents: new Set([s.intent]),
|
|
400
|
+
resolvedCount: s.resolved ? 1 : 0,
|
|
401
|
+
firstSeen: ts,
|
|
402
|
+
lastSeen: ts,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
104
406
|
}
|
|
105
|
-
|
|
106
|
-
|
|
407
|
+
}
|
|
408
|
+
const patterns = [];
|
|
409
|
+
for (const [signature, data] of agg) {
|
|
410
|
+
const distinctCount = data.intents.size;
|
|
411
|
+
const resolvedRate = data.count > 0 ? Math.round((data.resolvedCount / data.count) * 100) / 100 : 0;
|
|
412
|
+
patterns.push({
|
|
413
|
+
signature,
|
|
414
|
+
violation: data.violation,
|
|
415
|
+
fixPath: data.fixPath,
|
|
416
|
+
occurrenceCount: data.count,
|
|
417
|
+
distinctIntents: [...data.intents],
|
|
418
|
+
resolvedRate,
|
|
419
|
+
antibodyLevel: computeACL(data.count, distinctCount, resolvedRate),
|
|
420
|
+
firstSeen: data.firstSeen,
|
|
421
|
+
lastSeen: data.lastSeen,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
patterns.sort((a, b) => b.occurrenceCount - a.occurrenceCount);
|
|
425
|
+
return { failureToFix: patterns };
|
|
426
|
+
}
|
|
427
|
+
/** 查询匹配当前意图的高置信度抗体(ACL-3+),用于推理层免疫加速 */
|
|
428
|
+
/** Query antibody registry for matching repair patterns. */
|
|
429
|
+
/** @requires FAILURE_SIGNATURE @produces ANTIBODY_MATCH */
|
|
430
|
+
function queryAntibodies(intent, minACL = "ACL-3") {
|
|
431
|
+
const { failureToFix } = getLearnedPatterns();
|
|
432
|
+
const aclRank = { "ACL-1": 1, "ACL-2": 2, "ACL-3": 3, "ACL-4": 4 };
|
|
433
|
+
const minRank = aclRank[minACL];
|
|
434
|
+
const intentLower = intent.toLowerCase();
|
|
435
|
+
const intentWords = new Set(intentLower.split(/[\s,,、]+|(?<=[一-鿿])(?=[一-鿿])/).filter(w => w.length > 0));
|
|
436
|
+
return failureToFix
|
|
437
|
+
.filter(p => aclRank[p.antibodyLevel] >= minRank)
|
|
438
|
+
.filter(p => p.fixPath && p.fixPath.length > 0)
|
|
439
|
+
.map(p => {
|
|
440
|
+
// 计算意图相似度
|
|
441
|
+
let overlapScore = 0;
|
|
442
|
+
for (const di of p.distinctIntents) {
|
|
443
|
+
const diWords = new Set(di.toLowerCase().split(/[\s,,、]+|(?<=[一-鿿])(?=[一-鿿])/).filter(w => w.length > 0));
|
|
444
|
+
const intersection = [...intentWords].filter(w => diWords.has(w)).length;
|
|
445
|
+
const union = new Set([...intentWords, ...diWords]).size;
|
|
446
|
+
overlapScore = Math.max(overlapScore, union > 0 ? intersection / union : 0);
|
|
107
447
|
}
|
|
108
|
-
|
|
109
|
-
|
|
448
|
+
return { ...p, _score: overlapScore };
|
|
449
|
+
})
|
|
450
|
+
.filter(p => p._score >= 0.2) // 至少 20% 的 Jaccard 相似度
|
|
451
|
+
.sort((a, b) => b._score - a._score);
|
|
452
|
+
}
|
|
453
|
+
/** 语义热力图:哪些协议/层最脆弱,约束如何聚类 */
|
|
454
|
+
/** Get semantic heatmap showing fragile protocols and SVL hotspots. */
|
|
455
|
+
/** @requires FAILURE_DATA @produces HEATMAP */
|
|
456
|
+
/** @requires FAILURE_HEATMAP @produces HEATMAP_DATA */
|
|
457
|
+
function getSemanticHeatmap() {
|
|
458
|
+
const sessions = getAllSessions();
|
|
459
|
+
// Count total violations from sessions
|
|
460
|
+
let totalViolations = 0;
|
|
461
|
+
const svlCounts = {};
|
|
462
|
+
const funcCounts = new Map();
|
|
463
|
+
for (const s of sessions) {
|
|
464
|
+
for (const a of s.attempts) {
|
|
465
|
+
for (const v of a.violations) {
|
|
466
|
+
totalViolations++;
|
|
467
|
+
const svlKey = `SVL-${v.svl}`;
|
|
468
|
+
svlCounts[svlKey] = (svlCounts[svlKey] || 0) + 1;
|
|
469
|
+
// Fragile protocols: extract blocked function from description
|
|
470
|
+
const blockedMatch = v.description.match(/(\w+)\s*(要求|requires|blocked|不允许|不合法)/);
|
|
471
|
+
const fn = blockedMatch ? blockedMatch[1] : (a.generatedActions.find(x => x.kind === "call")?.function || "unknown");
|
|
472
|
+
const existing = funcCounts.get(fn);
|
|
473
|
+
if (existing) {
|
|
474
|
+
existing.count++;
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
funcCounts.set(fn, { count: 1, svl: svlKey });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
110
480
|
}
|
|
111
481
|
}
|
|
482
|
+
const total = totalViolations || 1;
|
|
483
|
+
const fragileProtocols = [...funcCounts.entries()]
|
|
484
|
+
.map(([fn, data]) => ({ function: fn, violationCount: data.count, svl: data.svl }))
|
|
485
|
+
.sort((a, b) => b.violationCount - a.violationCount)
|
|
486
|
+
.slice(0, 10);
|
|
487
|
+
// SVL hotspots
|
|
488
|
+
const svlHotspots = [];
|
|
489
|
+
for (const [svl, count] of Object.entries(svlCounts)) {
|
|
490
|
+
svlHotspots.push({ svl, count, percentage: Math.round((count / total) * 100) });
|
|
491
|
+
}
|
|
492
|
+
svlHotspots.sort((a, b) => b.count - a.count);
|
|
493
|
+
// Constraint clusters: which anomaly types co-occur in the same session
|
|
494
|
+
const constraintClusters = [];
|
|
495
|
+
for (const s of sessions) {
|
|
496
|
+
if (s.attempts.length < 2)
|
|
497
|
+
continue;
|
|
498
|
+
const types = [...new Set(s.attempts.flatMap(a => a.violations.map(v => v.violatedConstraint)))].filter(Boolean).sort();
|
|
499
|
+
if (types.length >= 2) {
|
|
500
|
+
constraintClusters.push({ constraints: types, count: s.attempts.length, intent: s.intent });
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
constraintClusters.sort((a, b) => b.count - a.count);
|
|
504
|
+
// High friction intents: which tasks require the most adaptations
|
|
505
|
+
const highFrictionIntents = sessions
|
|
506
|
+
.map(s => ({
|
|
507
|
+
intent: s.intent,
|
|
508
|
+
adaptationCount: s.attempts.filter(a => a.outcome !== "success").length,
|
|
509
|
+
anomalyTypes: [...new Set(s.attempts.flatMap(a => a.violations.map(v => v.violatedConstraint)))].filter(Boolean),
|
|
510
|
+
}))
|
|
511
|
+
.sort((a, b) => b.adaptationCount - a.adaptationCount)
|
|
512
|
+
.slice(0, 8);
|
|
513
|
+
return { fragileProtocols, svlHotspots, constraintClusters, highFrictionIntents };
|
|
514
|
+
}
|
|
515
|
+
/** 抗体效能统计:量化免疫加速节省的 LLM 调用和 token */
|
|
516
|
+
/** Get antibody efficacy statistics: hits by level, tokens saved, top signatures.
|
|
517
|
+
* @tags antibody, immune, statistics, efficiency
|
|
518
|
+
*/
|
|
519
|
+
/** @requires ANTIBODY_DATA @produces ANTIBODY_STATS */
|
|
520
|
+
/** @requires ANTIBODY_DATA @produces ANTIBODY_STATS */
|
|
521
|
+
function getAntibodyStats() {
|
|
522
|
+
const sessions = getAllSessions();
|
|
523
|
+
let totalHits = 0;
|
|
524
|
+
let fastPathHits = 0;
|
|
525
|
+
let injectedHintHits = 0;
|
|
526
|
+
let totalLLMCallsSaved = 0;
|
|
527
|
+
let totalTokensSaved = 0;
|
|
528
|
+
const byLevel = {};
|
|
529
|
+
const sigMap = new Map();
|
|
530
|
+
for (const s of sessions) {
|
|
531
|
+
for (const a of s.attempts) {
|
|
532
|
+
const hit = a.antibodyHit;
|
|
533
|
+
if (!hit)
|
|
534
|
+
continue;
|
|
535
|
+
totalHits++;
|
|
536
|
+
if (hit.action === "fast_path")
|
|
537
|
+
fastPathHits++;
|
|
538
|
+
else if (hit.action === "injected_hint")
|
|
539
|
+
injectedHintHits++;
|
|
540
|
+
totalLLMCallsSaved += hit.llmCallsSaved || 0;
|
|
541
|
+
totalTokensSaved += hit.estimatedTokensSaved || 0;
|
|
542
|
+
const level = hit.level || "ACL-1";
|
|
543
|
+
const lb = byLevel[level] || { hits: 0, llmSaved: 0, tokensSaved: 0 };
|
|
544
|
+
lb.hits++;
|
|
545
|
+
lb.llmSaved += hit.llmCallsSaved || 0;
|
|
546
|
+
lb.tokensSaved += hit.estimatedTokensSaved || 0;
|
|
547
|
+
byLevel[level] = lb;
|
|
548
|
+
const sig = hit.signature || "unknown";
|
|
549
|
+
const se = sigMap.get(sig) || { hits: 0, similarities: [] };
|
|
550
|
+
se.hits++;
|
|
551
|
+
se.similarities.push(hit.similarityScore || 0);
|
|
552
|
+
sigMap.set(sig, se);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
const topSignatures = [...sigMap.entries()]
|
|
556
|
+
.map(([signature, d]) => ({
|
|
557
|
+
signature,
|
|
558
|
+
hits: d.hits,
|
|
559
|
+
avgSimilarity: Math.round((d.similarities.reduce((a, b) => a + b, 0) / d.similarities.length) * 100) / 100,
|
|
560
|
+
}))
|
|
561
|
+
.sort((a, b) => b.hits - a.hits)
|
|
562
|
+
.slice(0, 10);
|
|
563
|
+
return { totalHits, fastPathHits, injectedHintHits, totalLLMCallsSaved, totalTokensSaved, byLevel, topSignatures };
|
|
564
|
+
}
|
|
565
|
+
/** Generate candidate immune rules from failure patterns. */
|
|
566
|
+
function generateCandidateRules() {
|
|
567
|
+
const genome = getFailureGenome();
|
|
568
|
+
const rules = [];
|
|
569
|
+
// SVL-4 修复路径
|
|
570
|
+
const ssgFixes = genome.commonFixPaths.filter(f => f.violation === 'SVL-4');
|
|
571
|
+
if (ssgFixes.length > 0) {
|
|
572
|
+
const top = ssgFixes[0];
|
|
573
|
+
rules.push(`SSG 修复规则: 当检测到协议违规时,优先尝试调用 ${top.fixPath.join(' → ')}。`);
|
|
574
|
+
}
|
|
575
|
+
if (genome.bySVL["SVL-1"] > genome.bySVL["SVL-4"]) {
|
|
576
|
+
rules.push("SVL-1 是最高频失效模式——建议强化 IR 提取的符号覆盖度。");
|
|
577
|
+
}
|
|
578
|
+
if (genome.bySVL["SVL-4"] > 0) {
|
|
579
|
+
rules.push("SVL-4 协议违规建议:为关键函数添加 @protocol JSDoc 注解。");
|
|
580
|
+
}
|
|
581
|
+
if (genome.averageRetriesToSuccess > 2) {
|
|
582
|
+
rules.push(`平均需要 ${genome.averageRetriesToSuccess} 次重试才能成功——考虑优化 Planner 路径排序。`);
|
|
583
|
+
}
|
|
112
584
|
return rules;
|
|
113
585
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343206982_0y8gk timestamp=2026-06-01T19:46:48.561Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 382 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const genome = (0, failure_corpus_1.getFailureGenome)();
|
|
9
|
+
return genome;
|
|
10
|
+
}
|
|
11
|
+
main();
|
package/dist/failures.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780345916092_sn5tt timestamp=2026-06-01T20:31:57.612Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 390 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const failures = (0, failure_corpus_1.getAllFailures)();
|
|
9
|
+
return failures;
|
|
10
|
+
}
|
|
11
|
+
main();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343852770_0srir timestamp=2026-06-01T19:57:34.249Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 395 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const stats = (0, failure_corpus_1.getAntibodyStats)();
|
|
9
|
+
const body = getBody();
|
|
10
|
+
const methods = getMethods();
|
|
11
|
+
return stats;
|
|
12
|
+
}
|
|
13
|
+
main();
|
package/dist/feedback.js
CHANGED
|
@@ -39,17 +39,23 @@ exports.getFunctionSuccessRate = getFunctionSuccessRate;
|
|
|
39
39
|
exports.recordRun = recordRun;
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
|
+
const file_lock_1 = require("./file-lock");
|
|
42
43
|
const FEEDBACK_PATH = path.resolve(__dirname, "../feedback.json");
|
|
44
|
+
/** @requires CORPUS @produces FEEDBACK_DATA */
|
|
43
45
|
function loadFeedback() {
|
|
44
46
|
if (!fs.existsSync(FEEDBACK_PATH))
|
|
45
47
|
return [];
|
|
46
48
|
return JSON.parse(fs.readFileSync(FEEDBACK_PATH, "utf-8"));
|
|
47
49
|
}
|
|
50
|
+
/** @requires FEEDBACK_EVENT @produces FEEDBACK_ID */
|
|
48
51
|
function saveFeedback(record) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
(0, file_lock_1.withLock)("feedback.json", () => {
|
|
53
|
+
const data = loadFeedback();
|
|
54
|
+
data.push(record);
|
|
55
|
+
fs.writeFileSync(FEEDBACK_PATH, JSON.stringify(data, null, 2));
|
|
56
|
+
});
|
|
52
57
|
}
|
|
58
|
+
/** @requires FUNCTION_NAME @produces SUCCESS_RATE */
|
|
53
59
|
function getFunctionSuccessRate(funcName) {
|
|
54
60
|
const records = loadFeedback();
|
|
55
61
|
const funcRecords = records.filter(r => r.functionName === funcName);
|
|
@@ -58,6 +64,7 @@ function getFunctionSuccessRate(funcName) {
|
|
|
58
64
|
const successCount = funcRecords.filter(r => r.success).length;
|
|
59
65
|
return successCount / funcRecords.length;
|
|
60
66
|
}
|
|
67
|
+
/** @requires EXECUTION_DATA @produces RUN_ID */
|
|
61
68
|
function recordRun(intent, actions, success, error) {
|
|
62
69
|
for (const action of actions) {
|
|
63
70
|
if (action.kind === "call") {
|