progmune-runtime 2.1.6 → 3.2.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.
Files changed (356) hide show
  1. package/README.md +119 -461
  2. package/dist/ablation-study.js +144 -0
  3. package/dist/ablation-study.test.js +18 -0
  4. package/dist/action-runtime.js +3 -1
  5. package/dist/active-learning.js +211 -0
  6. package/dist/analytics.js +139 -0
  7. package/dist/asset-factory.js +309 -0
  8. package/dist/asset-growth.js +244 -0
  9. package/dist/asset-promotion.js +382 -0
  10. package/dist/asset-quality.js +550 -0
  11. package/dist/audit/business-translator.js +285 -0
  12. package/dist/audit/cli.js +66 -0
  13. package/dist/audit/formatters/html.js +379 -0
  14. package/dist/audit/formatters/json.js +11 -0
  15. package/dist/audit/formatters/markdown.js +192 -0
  16. package/dist/audit/formatters/terminal.js +189 -0
  17. package/dist/audit/index.js +25 -0
  18. package/dist/audit/report-builder.js +318 -0
  19. package/dist/audit/types.js +8 -0
  20. package/dist/audit.js +3 -3
  21. package/dist/auto-benchmark-generator.js +137 -0
  22. package/dist/auto-benchmark-generator.test.js +45 -0
  23. package/dist/auto-protocol-synthesizer.js +362 -0
  24. package/dist/auto-protocol-synthesizer.test.js +82 -0
  25. package/dist/autonomous-patch.js +175 -0
  26. package/dist/autonomous-patch.test.js +128 -0
  27. package/dist/badge/badge-server.js +98 -0
  28. package/dist/behavior-miner.js +442 -0
  29. package/dist/belief-layer.js +475 -0
  30. package/dist/benchmark-count.js +5 -0
  31. package/dist/benchmark-generator.js +211 -0
  32. package/dist/benchmark-harness.js +201 -0
  33. package/dist/benchmark-pass-rate.js +7 -0
  34. package/dist/benchmark-report.js +8 -3
  35. package/dist/benchmark-save.js +14 -1
  36. package/dist/bootstrap-validation.js +197 -0
  37. package/dist/bootstrap-validation.test.js +51 -0
  38. package/dist/branch-ledger.js +1 -1
  39. package/dist/capability-gap.js +130 -0
  40. package/dist/certify-html.js +351 -0
  41. package/dist/certify.js +326 -0
  42. package/dist/check.js +4 -4
  43. package/dist/compliance-miner.js +447 -0
  44. package/dist/continuous-benchmark.js +194 -0
  45. package/dist/continuous-benchmark.test.js +116 -0
  46. package/dist/corpus-stats.js +173 -0
  47. package/dist/counterfactual-engine.js +288 -0
  48. package/dist/coverage-dashboard.js +109 -0
  49. package/dist/coverage-system.test.js +205 -0
  50. package/dist/cross-repo-precision.js +352 -0
  51. package/dist/cve-benchmark.js +180 -0
  52. package/dist/cve-benchmark.test.js +28 -0
  53. package/dist/cve-collector.js +73 -0
  54. package/dist/data-quality.js +141 -0
  55. package/dist/decision-engine.js +388 -0
  56. package/dist/derive-metadata.js +250 -0
  57. package/dist/difficulty-active.test.js +198 -0
  58. package/dist/difficulty-map.js +244 -0
  59. package/dist/discovery-analytics.js +125 -0
  60. package/dist/discovery-model.js +149 -0
  61. package/dist/discovery-optimize.test.js +199 -0
  62. package/dist/discovery-trace.js +276 -0
  63. package/dist/discovery-trace.test.js +97 -0
  64. package/dist/emitter.js +83 -1
  65. package/dist/enterprise-dashboard.js +405 -0
  66. package/dist/eval-hardening.js +297 -0
  67. package/dist/eval-hardening.test.js +85 -0
  68. package/dist/evaluation-campaign.js +359 -0
  69. package/dist/evaluation-campaign.test.js +181 -0
  70. package/dist/evidence-growth.js +143 -0
  71. package/dist/evidence-repository.js +209 -0
  72. package/dist/evidence-system.js +441 -0
  73. package/dist/execute.js +15 -7
  74. package/dist/experimental/software-physics.js +291 -0
  75. package/dist/experimental/state-inference.js +516 -0
  76. package/dist/experimental/unsupervised-physics.js +230 -0
  77. package/dist/extract-ir-python.js +54 -7
  78. package/dist/extract-ir.js +376 -12
  79. package/dist/failure-collector.js +2 -2
  80. package/dist/failure-corpus.js +322 -9
  81. package/dist/feedback.js +16 -5
  82. package/dist/feedback.test.js +49 -0
  83. package/dist/file-lock.js +1 -1
  84. package/dist/flywheel-batch.js +292 -0
  85. package/dist/frameworks/express-cli.js +237 -0
  86. package/dist/frameworks/express-detector.js +445 -0
  87. package/dist/frameworks/express-detector.test.js +206 -0
  88. package/dist/frameworks/index.js +30 -0
  89. package/dist/frameworks/nestjs-detector.js +302 -0
  90. package/dist/frameworks/trpc-detector.js +161 -0
  91. package/dist/frameworks/version-awareness.js +179 -0
  92. package/dist/function-synonyms.js +164 -0
  93. package/dist/function-synonyms.test.js +68 -0
  94. package/dist/generalization.test.js +352 -0
  95. package/dist/goal-annotator.js +113 -0
  96. package/dist/goal-planner.js +563 -0
  97. package/dist/gold-cve.js +164 -0
  98. package/dist/gold-cve.test.js +104 -0
  99. package/dist/gold-quality.js +206 -0
  100. package/dist/gold-tiers.js +241 -0
  101. package/dist/governance-dashboard.js +327 -0
  102. package/dist/graph-viz.js +240 -0
  103. package/dist/guided-frontier.js +195 -0
  104. package/dist/hierarchical-planner.js +148 -0
  105. package/dist/identifier-parser.js +260 -0
  106. package/dist/immune-metrics.js +93 -0
  107. package/dist/immune-receiver.js +158 -0
  108. package/dist/immune-reporter.js +1 -1
  109. package/dist/improvement-orchestrator.js +206 -0
  110. package/dist/inject-p0-vocabulary.js +300 -0
  111. package/dist/intent-parser.js +218 -0
  112. package/dist/invariant-algebra.js +476 -0
  113. package/dist/invariant-calculus.js +533 -0
  114. package/dist/ir-utils.js +70 -0
  115. package/dist/ir-utils.test.js +50 -0
  116. package/dist/knowledge-api.js +312 -0
  117. package/dist/knowledge-evolution.js +452 -0
  118. package/dist/knowledge-explorer.js +506 -0
  119. package/dist/knowledge-flywheel.js +274 -0
  120. package/dist/knowledge-governance.js +338 -0
  121. package/dist/knowledge-governance.test.js +150 -0
  122. package/dist/knowledge-graph.js +181 -0
  123. package/dist/knowledge-guided-synth.js +246 -0
  124. package/dist/knowledge-loop.test.js +77 -0
  125. package/dist/knowledge-object.js +316 -0
  126. package/dist/knowledge-package.js +98 -0
  127. package/dist/kpi-dashboard.js +561 -0
  128. package/dist/l3-cross-function.js +280 -0
  129. package/dist/learning-ranker.js +148 -0
  130. package/dist/learning-ranker.test.js +291 -0
  131. package/dist/ledger/accountability.js +322 -0
  132. package/dist/ledger/chain-builder.js +185 -0
  133. package/dist/ledger/cli.js +222 -0
  134. package/dist/ledger/index.js +13 -0
  135. package/dist/ledger/signatures.js +193 -0
  136. package/dist/ledger/types.js +9 -0
  137. package/dist/llm.js +74 -3
  138. package/dist/load-benchmarks.js +8 -3
  139. package/dist/logger.js +66 -0
  140. package/dist/logger.test.js +37 -0
  141. package/dist/logistic-reward.js +339 -0
  142. package/dist/logistic-reward.test.js +180 -0
  143. package/dist/macro-graph.js +193 -0
  144. package/dist/macro-repair.js +183 -0
  145. package/dist/mcp-server.mjs +1202 -483
  146. package/dist/memory-layer.js +42 -5
  147. package/dist/multi-repo-precision.js +422 -0
  148. package/dist/name-free-protocol.js +425 -0
  149. package/dist/name-free-protocol.test.js +170 -0
  150. package/dist/name-scrambling.js +138 -0
  151. package/dist/name-scrambling.test.js +16 -0
  152. package/dist/p3-observability.test.js +281 -0
  153. package/dist/p5-orchestrator.test.js +225 -0
  154. package/dist/pairwise-preference.js +294 -0
  155. package/dist/pairwise-preference.test.js +140 -0
  156. package/dist/planner-constraints.js +104 -0
  157. package/dist/planner-prompts.js +155 -0
  158. package/dist/planner-telemetry.js +415 -0
  159. package/dist/planner-trace.js +214 -0
  160. package/dist/planner.js +162 -167
  161. package/dist/plsb/artifact.js +116 -0
  162. package/dist/plsb/cli.js +71 -0
  163. package/dist/plsb/index.js +19 -0
  164. package/dist/plsb/leaderboard.js +249 -0
  165. package/dist/plsb/report-md.js +156 -0
  166. package/dist/plsb/schema.js +179 -0
  167. package/dist/plsb-benchmark.js +284 -0
  168. package/dist/plsb-benchmark.test.js +119 -0
  169. package/dist/policy/cli.js +134 -0
  170. package/dist/policy/engine.js +333 -0
  171. package/dist/policy/index.js +12 -0
  172. package/dist/policy/types.js +59 -0
  173. package/dist/policy-miner.js +505 -0
  174. package/dist/precision-analyze.js +229 -0
  175. package/dist/precision-benchmark.js +147 -0
  176. package/dist/precision-label-c.js +134 -0
  177. package/dist/precision-label.js +193 -0
  178. package/dist/precision-report-c.js +149 -0
  179. package/dist/precision-report.js +246 -0
  180. package/dist/progmune-status.js +108 -0
  181. package/dist/proof-engine.js +479 -0
  182. package/dist/proof-provenance.js +315 -0
  183. package/dist/protocol-coverage.js +294 -0
  184. package/dist/protocol-detector.js +1189 -0
  185. package/dist/protocol-embedding-expanded.js +297 -0
  186. package/dist/protocol-embedding-expanded.test.js +97 -0
  187. package/dist/protocol-embedding.js +195 -0
  188. package/dist/protocol-embedding.test.js +82 -0
  189. package/dist/protocol-extractor-v2.js +354 -0
  190. package/dist/protocol-extractor-v2.test.js +140 -0
  191. package/dist/protocol-extractor.js +310 -0
  192. package/dist/protocol-extractor.test.js +113 -0
  193. package/dist/protocol-foundation.js +322 -0
  194. package/dist/protocol-foundation.test.js +163 -0
  195. package/dist/protocol-frontier.js +243 -0
  196. package/dist/protocol-frontier.test.js +92 -0
  197. package/dist/protocol-gap-analyzer.js +228 -0
  198. package/dist/protocol-gap-analyzer.test.js +49 -0
  199. package/dist/protocol-invariants.js +276 -0
  200. package/dist/protocol-invariants.test.js +111 -0
  201. package/dist/protocol-knowledge.js +464 -0
  202. package/dist/protocol-miner.js +343 -0
  203. package/dist/protocol-mining.js +207 -0
  204. package/dist/protocol-mining.test.js +37 -0
  205. package/dist/protocol-registry.js +1 -1
  206. package/dist/protocol-security-benchmark.js +222 -0
  207. package/dist/protocol-vulnerability.js +257 -0
  208. package/dist/protocol-vulnerability.test.js +60 -0
  209. package/dist/python-benchmark.js +120 -0
  210. package/dist/python-emitter.js +163 -45
  211. package/dist/python-protocol-extractor.js +187 -0
  212. package/dist/python-protocol-extractor.test.js +116 -0
  213. package/dist/realworld-benchmark.js +646 -0
  214. package/dist/realworld-benchmark.test.js +36 -0
  215. package/dist/repair-arch.test.js +411 -0
  216. package/dist/repair-evolution.test.js +454 -0
  217. package/dist/repair-executor.js +719 -0
  218. package/dist/repair-proposal.js +4 -4
  219. package/dist/repair-ranker.js +141 -0
  220. package/dist/repair-strategies.js +419 -0
  221. package/dist/repair-taxonomy.js +234 -0
  222. package/dist/repair-types.js +12 -0
  223. package/dist/repo-evaluator.js +250 -0
  224. package/dist/repo-evaluator.test.js +128 -0
  225. package/dist/resource-abstraction.js +242 -0
  226. package/dist/resource-detector.js +211 -0
  227. package/dist/result.test.js +43 -0
  228. package/dist/reward-system.js +411 -0
  229. package/dist/reward-system.test.js +175 -0
  230. package/dist/risk-model.js +215 -0
  231. package/dist/rule-miner.js +234 -7
  232. package/dist/rule-specificity.js +254 -0
  233. package/dist/runtime-types.js +27 -0
  234. package/dist/scaffold.js +208 -0
  235. package/dist/scale-collector.test.js +101 -0
  236. package/dist/scale-trajectory-collector.js +128 -0
  237. package/dist/sdk.js +250 -0
  238. package/dist/search-planner.js +4 -41
  239. package/dist/semantic-snapshot.js +1 -1
  240. package/dist/semantic-topology.js +121 -0
  241. package/dist/semantic-trace.js +310 -317
  242. package/dist/sequence-extractor.js +343 -0
  243. package/dist/skill-library.js +245 -0
  244. package/dist/skill-planner.test.js +189 -0
  245. package/dist/software-physics.js +291 -0
  246. package/dist/software-physics.test.js +81 -0
  247. package/dist/ssg-precision.js +478 -0
  248. package/dist/ssg-validator.js +71 -21
  249. package/dist/state-inference-doubleblind.test.js +160 -0
  250. package/dist/state-inference.js +516 -0
  251. package/dist/state-inference.test.js +115 -0
  252. package/dist/state-machine-fingerprint.js +345 -0
  253. package/dist/state-machine-fingerprint.test.js +120 -0
  254. package/dist/state-miner.js +386 -0
  255. package/dist/state-name-inference.js +213 -0
  256. package/dist/state-name-inference.test.js +69 -0
  257. package/dist/strategy-planner.js +262 -96
  258. package/dist/strategy-planner.test.js +135 -0
  259. package/dist/telemetry-analytics.test.js +402 -0
  260. package/dist/terminal-format.js +68 -0
  261. package/dist/terminal-format.test.js +83 -0
  262. package/dist/topology-factory.js +196 -0
  263. package/dist/topology-representation.js +242 -0
  264. package/dist/topology-representation.test.js +27 -0
  265. package/dist/trajectory-augmentation.js +254 -0
  266. package/dist/trajectory-augmentation.test.js +63 -0
  267. package/dist/trajectory-corpus.js +440 -0
  268. package/dist/trajectory-corpus.test.js +32 -0
  269. package/dist/trajectory-feedback.test.js +116 -0
  270. package/dist/transition-synthesizer.js +286 -0
  271. package/dist/transition-synthesizer.test.js +123 -0
  272. package/dist/trust/api-semantic-mapper.js +809 -0
  273. package/dist/trust/call-graph-propagator.js +225 -0
  274. package/dist/trust/cli.js +122 -0
  275. package/dist/trust/compliance-scorer.js +283 -0
  276. package/dist/trust/confidence-calculator.js +261 -0
  277. package/dist/trust/engine.js +1145 -0
  278. package/dist/trust/explainability.js +85 -0
  279. package/dist/trust/formatters/ci.js +42 -0
  280. package/dist/trust/formatters/json.js +11 -0
  281. package/dist/trust/formatters/terminal.js +152 -0
  282. package/dist/trust/index.js +39 -0
  283. package/dist/trust/phase1-verify.js +171 -0
  284. package/dist/trust/protocol-domain-validator.js +697 -0
  285. package/dist/trust/score-calculator.js +282 -0
  286. package/dist/trust/ssg-bridge.js +641 -0
  287. package/dist/trust/ssg-bridge.test.js +269 -0
  288. package/dist/trust/types.js +67 -0
  289. package/dist/trust/violation-trace.js +335 -0
  290. package/dist/trust-api.js +179 -0
  291. package/dist/trust-calibration.js +279 -0
  292. package/dist/unknown-protocol-discovery.js +339 -0
  293. package/dist/unknown-protocol-discovery.test.js +102 -0
  294. package/dist/unsupervised-physics.js +230 -0
  295. package/dist/unsupervised-physics.test.js +95 -0
  296. package/dist/utils.test.js +37 -0
  297. package/dist/validator.js +187 -10
  298. package/dist/verification-intelligence.js +475 -0
  299. package/dist/verify-api.js +432 -0
  300. package/dist/vi-impact-report.js +293 -0
  301. package/dist/wl-fingerprint.js +162 -0
  302. package/dist/wl-fingerprint.test.js +130 -0
  303. package/dist/zeroshot-strategy.js +139 -0
  304. package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
  305. package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +721 -0
  306. package/package.json +73 -6
  307. package/protocols.json +1956 -50
  308. package/.dockerignore +0 -14
  309. package/.mcp.json +0 -11
  310. package/.progmune_allowlist +0 -50
  311. package/.test_report/test_report.md +0 -87
  312. package/Dockerfile +0 -9
  313. package/FAQ.md +0 -167
  314. package/WHITEPAPER.md +0 -540
  315. package/demo-project/auth.ts +0 -55
  316. package/demo-project/tsconfig.json +0 -8
  317. package/dist/acl-breakdown.js +0 -13
  318. package/dist/all-sessions.js +0 -11
  319. package/dist/antibody-stats.js +0 -11
  320. package/dist/branch-tree-count.js +0 -14
  321. package/dist/common-fixpath.js +0 -12
  322. package/dist/constraint-types.js +0 -12
  323. package/dist/exec-metrics.js +0 -11
  324. package/dist/failure-report.js +0 -11
  325. package/dist/fast-path-hits.js +0 -13
  326. package/dist/fingerprint-list.js +0 -15
  327. package/dist/gen-history-log.js +0 -13
  328. package/dist/heatmap-data.js +0 -11
  329. package/dist/recent-session.js +0 -12
  330. package/dist/svl-distribution.js +0 -11
  331. package/dist/terminal-status.js +0 -11
  332. package/dist/token-savings.js +0 -11
  333. package/dist/total-repairs.js +0 -12
  334. package/dist/unresolved-count.js +0 -12
  335. package/dist/valid-fingerprints.js +0 -13
  336. package/dist/verify-ledgers.js +0 -11
  337. package/docs/whitepaper-style.css +0 -77
  338. package/docs/whitepaper-v2.1.md +0 -609
  339. package/docs/whitepaper-v2.2.md +0 -1064
  340. package/docs/whitepaper-v2.2.pdf +0 -0
  341. package/fly.toml +0 -31
  342. package/public/dashboard.html +0 -119
  343. package/server/hub.js +0 -116
  344. package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
  345. package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
  346. package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
  347. package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
  348. package/test/replay-golden.ts +0 -84
  349. package/test_benchmark.js +0 -165
  350. package/test_comprehensive.mjs +0 -638
  351. package/test_concurrency.js +0 -129
  352. package/test_ir_robustness.js +0 -85
  353. package/test_semantic_contracts.js +0 -269
  354. package/test_ssg_stress.js +0 -156
  355. package/test_svl3.js +0 -58
  356. package/tsconfig.json +0 -17
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * P5.4: Continuous Benchmark Expansion Tests
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const vitest_1 = require("vitest");
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const continuous_benchmark_1 = require("./continuous-benchmark");
43
+ const knowledge_governance_1 = require("./knowledge-governance");
44
+ const skill_library_1 = require("./skill-library");
45
+ const planner_telemetry_1 = require("./planner-telemetry");
46
+ const CB_DIR = path.resolve(__dirname, "..", "test-continuous-benchmark");
47
+ process.env.PROGMUNE_PROJECT_DIR = CB_DIR;
48
+ fs.mkdirSync(CB_DIR, { recursive: true });
49
+ fs.mkdirSync(path.join(CB_DIR, ".progmune_corpus", "telemetry"), { recursive: true });
50
+ fs.mkdirSync(path.join(CB_DIR, ".progmune_corpus", "knowledge"), { recursive: true });
51
+ fs.mkdirSync(path.join(CB_DIR, ".progmune_corpus", "skills"), { recursive: true });
52
+ (0, vitest_1.describe)("Continuous Benchmark Expansion", () => {
53
+ (0, vitest_1.it)("generates benchmarks from approved patches", () => {
54
+ const store = new knowledge_governance_1.KnowledgePatchStore(path.join(CB_DIR, ".progmune_corpus", "knowledge", `cb-patches-${Date.now()}.json`));
55
+ // Approve a patch
56
+ const patch = store.propose({
57
+ from: "FILE_OPEN", to: "FILE_DIRTY", action: "open_file → write_file",
58
+ protocol: "FileProtocol", confidence: 1.0, evidenceCount: 10, examples: ["test"],
59
+ validation: { benchmarkSupport: 10, trajectorySupport: 10, contradictionCount: 0, status: "verified" },
60
+ });
61
+ store.approve(patch.id, { top1Before: 0.5, top1After: 0.6, top3Before: 0.7, top3After: 0.8 });
62
+ const cases = (0, continuous_benchmark_1.generateBenchmarksFromPatches)(store);
63
+ (0, vitest_1.expect)(cases.length).toBeGreaterThanOrEqual(1);
64
+ (0, vitest_1.expect)(cases[0].source).toBe("patch");
65
+ });
66
+ (0, vitest_1.it)("generates benchmarks from skills", () => {
67
+ const rules = new Map();
68
+ rules.set("open_file", { pre_states: [], post_states: ["FILE_OPEN"] });
69
+ rules.set("write_file", { pre_states: ["FILE_OPEN"], post_states: [] });
70
+ rules.set("close_file", { pre_states: ["FILE_OPEN"], post_states: [], invalidate: ["FILE_OPEN"] });
71
+ const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(CB_DIR, ".progmune_corpus", "telemetry", `cb-skills-${Date.now()}.jsonl`));
72
+ // Seed with high-confidence file skill
73
+ for (let i = 0; i < 15; i++) {
74
+ const a = ["open_file", "write_file", "close_file"];
75
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", a, "resource_leak");
76
+ const id = telemetry.recordDecision({
77
+ goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak",
78
+ candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions: a, explanation: "full" }],
79
+ selectedCandidateId: fp,
80
+ });
81
+ telemetry.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, timestamp: Date.now() });
82
+ }
83
+ const lib = new skill_library_1.SkillLibrary();
84
+ lib.learn(telemetry, rules);
85
+ (0, vitest_1.expect)(lib.size).toBeGreaterThanOrEqual(1);
86
+ const cases = (0, continuous_benchmark_1.generateBenchmarksFromSkills)(lib);
87
+ (0, vitest_1.expect)(cases.length).toBeGreaterThanOrEqual(1);
88
+ (0, vitest_1.expect)(cases[0].source).toBe("skill");
89
+ // Resource cleanup variant should also be generated
90
+ (0, vitest_1.expect)(cases.some(c => c.violationType === "resource_leak")).toBe(true);
91
+ });
92
+ (0, vitest_1.it)("runs continuous benchmark pipeline", async () => {
93
+ const rules = new Map();
94
+ rules.set("open_file", { pre_states: [], post_states: ["FILE_OPEN"] });
95
+ rules.set("write_file", { pre_states: ["FILE_OPEN"], post_states: [] });
96
+ rules.set("close_file", { pre_states: ["FILE_OPEN"], post_states: [], invalidate: ["FILE_OPEN"] });
97
+ const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(CB_DIR, ".progmune_corpus", "telemetry", `cb-full-${Date.now()}.jsonl`));
98
+ for (let i = 0; i < 20; i++) {
99
+ const a = ["open_file", "write_file", "close_file"];
100
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", a, "resource_leak");
101
+ const id = telemetry.recordDecision({
102
+ goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak",
103
+ candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions: a, explanation: "full" }],
104
+ selectedCandidateId: fp,
105
+ });
106
+ telemetry.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, timestamp: Date.now() });
107
+ }
108
+ const lib = new skill_library_1.SkillLibrary();
109
+ lib.learn(telemetry, rules);
110
+ const store = new knowledge_governance_1.KnowledgePatchStore(path.join(CB_DIR, ".progmune_corpus", "knowledge", `cb-run-${Date.now()}.json`));
111
+ const report = await (0, continuous_benchmark_1.runContinuousBenchmark)(store, lib, path.join(CB_DIR, "expanded-benchmarks"));
112
+ (0, vitest_1.expect)(report.generatedCases).toBeGreaterThanOrEqual(2);
113
+ (0, vitest_1.expect)(report.sourceBreakdown.skills).toBeGreaterThanOrEqual(1);
114
+ (0, continuous_benchmark_1.printContinuousBenchmarkReport)(report);
115
+ }, 60000);
116
+ });
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ /**
3
+ * P0: Corpus Quality Dashboard
4
+ *
5
+ * Reads all FailureRecordV2 files from .progmune_corpus/trajectories/
6
+ * and outputs quality metrics as terminal table + JSON report.
7
+ *
8
+ * Usage:
9
+ * npx ts-node src/corpus-stats.ts
10
+ * npx ts-node src/corpus-stats.ts --json
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const failure_corpus_1 = require("./failure-corpus");
14
+ // ═══════════════════════════════════════════════════════════════
15
+ // Data loading
16
+ // ═══════════════════════════════════════════════════════════════
17
+ function loadAllTrajectories() {
18
+ return (0, failure_corpus_1.loadTrajectories)();
19
+ }
20
+ // ═══════════════════════════════════════════════════════════════
21
+ // Metrics computation
22
+ // ═══════════════════════════════════════════════════════════════
23
+ function jaccardSimilarity(a, b) {
24
+ const sa = new Set(a), sb = new Set(b);
25
+ const intersection = [...sa].filter(x => sb.has(x)).length;
26
+ const union = new Set([...sa, ...sb]).size;
27
+ return union === 0 ? 0 : intersection / union;
28
+ }
29
+ function computeStats(trajectories) {
30
+ const violations = trajectories.filter(t => t.result === "violation");
31
+ // Duplication: fraction of pairs with trajectory similarity > 0.9
32
+ let duplicatePairs = 0;
33
+ let totalPairs = 0;
34
+ for (let i = 0; i < violations.length; i++) {
35
+ for (let j = i + 1; j < violations.length; j++) {
36
+ totalPairs++;
37
+ if (jaccardSimilarity(violations[i].trajectory, violations[j].trajectory) > 0.9) {
38
+ duplicatePairs++;
39
+ }
40
+ }
41
+ }
42
+ // Repair stats: count repair trajectories
43
+ const repairs = trajectories.filter(t => t.result === "repair");
44
+ const totalAttempts = repairs.length;
45
+ const acceptedAttempts = repairs.filter(t => t.successRate > 0.5).length;
46
+ const successfulRepairs = repairs.filter(t => t.successRate > 0.8).length;
47
+ // Violation type counts
48
+ const byViolationType = {};
49
+ for (const t of violations) {
50
+ const vt = t.violation?.type || "other";
51
+ byViolationType[vt] = (byViolationType[vt] || 0) + 1;
52
+ }
53
+ // Protocol counts
54
+ const byProtocol = {};
55
+ for (const t of trajectories) {
56
+ byProtocol[t.protocol] = (byProtocol[t.protocol] || 0) + 1;
57
+ }
58
+ // Context feature combinations
59
+ const byContextFeature = {};
60
+ for (const t of trajectories) {
61
+ const key = [
62
+ `depth=${t.context.nestingDepth}`,
63
+ t.context.exceptionHandled ? "try" : "no-try",
64
+ t.context.insideLoop ? "loop" : "no-loop",
65
+ ].join(" ");
66
+ byContextFeature[key] = (byContextFeature[key] || 0) + 1;
67
+ }
68
+ // Top violation × context patterns
69
+ const patternCounts = {};
70
+ for (const t of violations) {
71
+ const vt = t.violation?.type || "other";
72
+ const ctx = t.context;
73
+ const key = `${vt} | depth=${ctx.nestingDepth} ${ctx.exceptionHandled ? "try" : "no-try"} ${ctx.insideLoop ? "loop" : "no-loop"}`;
74
+ patternCounts[key] = (patternCounts[key] || 0) + 1;
75
+ }
76
+ const topPatterns = Object.entries(patternCounts)
77
+ .sort((a, b) => b[1] - a[1])
78
+ .slice(0, 10)
79
+ .map(([p, c]) => {
80
+ const [violationType, ...rest] = p.split(" | ");
81
+ return { violationType, context: rest.join(" | "), count: c };
82
+ });
83
+ const timestamps = trajectories.map(f => f.timestamp).sort();
84
+ return {
85
+ totalFailures: trajectories.length,
86
+ dateRange: {
87
+ earliest: timestamps[0] || "N/A",
88
+ latest: timestamps[timestamps.length - 1] || "N/A",
89
+ },
90
+ byViolationType,
91
+ byProtocol,
92
+ byContextFeature,
93
+ duplicationRate: totalPairs > 0 ? duplicatePairs / totalPairs : 0,
94
+ repairAcceptanceRate: totalAttempts > 0 ? acceptedAttempts / totalAttempts : 0,
95
+ repairSuccessRate: totalAttempts > 0 ? successfulRepairs / totalAttempts : 0,
96
+ totalRepairAttempts: totalAttempts,
97
+ avgPatternSuccessRate: trajectories.length > 0
98
+ ? trajectories.reduce((s, t) => s + t.successRate, 0) / trajectories.length
99
+ : 0,
100
+ topPatterns,
101
+ };
102
+ }
103
+ // ═══════════════════════════════════════════════════════════════
104
+ // Output
105
+ // ═══════════════════════════════════════════════════════════════
106
+ function formatPercent(v) {
107
+ return `${(v * 100).toFixed(1)}%`;
108
+ }
109
+ function printTable(stats, breakdown) {
110
+ console.log("\n╔══════════════════════════════════════════════╗");
111
+ console.log("║ Trajectory Corpus Dashboard (Schema v1) ║");
112
+ console.log("╚══════════════════════════════════════════════╝");
113
+ console.log(`\n📊 Total trajectories: ${breakdown.total}`);
114
+ console.log(` ✅ Success: ${breakdown.success} ❌ Violation: ${breakdown.violation} 🔧 Repair: ${breakdown.repair} ⭐ Optimal: ${breakdown.optimal}`);
115
+ console.log(`📅 Date range: ${stats.dateRange.earliest} → ${stats.dateRange.latest}`);
116
+ // Violation distribution
117
+ console.log("\n── Violation Types ──");
118
+ const vtEntries = Object.entries(stats.byViolationType).sort((a, b) => b[1] - a[1]);
119
+ for (const [type, count] of vtEntries) {
120
+ const bar = "█".repeat(Math.round(count / Math.max(...vtEntries.map(e => e[1])) * 30));
121
+ console.log(` ${type.padEnd(24)} ${String(count).padStart(4)} ${bar}`);
122
+ }
123
+ // Protocol distribution
124
+ console.log("\n── Protocols ──");
125
+ for (const [proto, count] of Object.entries(stats.byProtocol).sort((a, b) => b[1] - a[1])) {
126
+ console.log(` ${proto.padEnd(20)} ${count}`);
127
+ }
128
+ // Quality metrics
129
+ console.log("\n── Quality Metrics ──");
130
+ const rows = [
131
+ ["Duplication rate", formatPercent(stats.duplicationRate), stats.duplicationRate < 0.2 ? "✅" : "⚠️ >20%"],
132
+ ["Repair acceptance", formatPercent(stats.repairAcceptanceRate), stats.repairAcceptanceRate > 0.4 ? "✅" : "⚠️ <40%"],
133
+ ["Repair success", formatPercent(stats.repairSuccessRate), stats.repairSuccessRate > 0.8 ? "✅" : "⚠️ <80%"],
134
+ ["Total repair attempts", String(stats.totalRepairAttempts), ""],
135
+ ["Avg pattern success rate", formatPercent(stats.avgPatternSuccessRate), ""],
136
+ ];
137
+ for (const [metric, value, flag] of rows) {
138
+ console.log(` ${(metric + ":").padEnd(26)} ${value.padEnd(8)} ${flag}`);
139
+ }
140
+ // Top patterns
141
+ if (stats.topPatterns.length > 0) {
142
+ console.log("\n── Top Violation × Context Patterns ──");
143
+ for (const p of stats.topPatterns) {
144
+ console.log(` ${p.violationType.padEnd(24)} ${p.context.padEnd(30)} x${p.count}`);
145
+ }
146
+ }
147
+ // Context features
148
+ console.log("\n── Context Features ──");
149
+ for (const [feat, count] of Object.entries(stats.byContextFeature).sort((a, b) => b[1] - a[1])) {
150
+ console.log(` ${feat.padEnd(30)} ${count}`);
151
+ }
152
+ console.log();
153
+ }
154
+ // ═══════════════════════════════════════════════════════════════
155
+ // Main
156
+ // ═══════════════════════════════════════════════════════════════
157
+ async function main() {
158
+ const useJson = process.argv.includes("--json");
159
+ const trajectories = loadAllTrajectories();
160
+ const breakdown = (0, failure_corpus_1.corpusTrajectoryStats)();
161
+ if (trajectories.length === 0) {
162
+ console.error("✅ Trajectory corpus is empty — run validation to start collecting.");
163
+ process.exit(0);
164
+ }
165
+ const stats = computeStats(trajectories);
166
+ if (useJson) {
167
+ console.log(JSON.stringify({ stats, breakdown }, null, 2));
168
+ }
169
+ else {
170
+ printTable(stats, breakdown);
171
+ }
172
+ }
173
+ main();
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+ /**
3
+ * P2: Counterfactual Repair Engine (V3)
4
+ *
5
+ * When validation fails, this engine:
6
+ * 1. Searches Failure Corpus v2 for similar violation patterns
7
+ * 2. BFS-searches the SSG for alternative legal state transition paths
8
+ * 3. Ranks alternatives by: historical success rate → path length → reward weights
9
+ * 4. Returns top-3 with human-readable explanations
10
+ *
11
+ * This is V3's killer feature: "告诉你三条修法"
12
+ *
13
+ * Architecture (refactored):
14
+ * Strategies (repair-strategies.ts) → Candidates → Ranker (repair-ranker.ts) → Top-3
15
+ *
16
+ * @requires VALIDATION_FAILURE @produces REPAIR_ALTERNATIVES
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.deduplicateCandidates = deduplicateCandidates;
53
+ exports.getRankerStatus = getRankerStatus;
54
+ exports.suggestAlternatives = suggestAlternatives;
55
+ exports.formatAlternatives = formatAlternatives;
56
+ const fs = __importStar(require("fs"));
57
+ const path = __importStar(require("path"));
58
+ const zeroshot_strategy_1 = require("./zeroshot-strategy");
59
+ const repair_strategies_1 = require("./repair-strategies");
60
+ const repair_ranker_1 = require("./repair-ranker");
61
+ const learning_ranker_1 = require("./learning-ranker");
62
+ const planner_telemetry_1 = require("./planner-telemetry");
63
+ const logistic_reward_1 = require("./logistic-reward");
64
+ // ═══════════════════════════════════════════════════════════════
65
+ // Cross-source evidence merge
66
+ // ═══════════════════════════════════════════════════════════════
67
+ /**
68
+ * Deduplicate candidates by action signature, merging evidence sources.
69
+ *
70
+ * When the same repair path (e.g., "close_file") comes from
71
+ * corpus + protocol + antibody, all three sources are recorded
72
+ * in `evidenceSources`. This merged candidate has higher credibility
73
+ * than any single-source candidate.
74
+ *
75
+ * This is a key input feature for the future Reward Model (P4).
76
+ */
77
+ function deduplicateCandidates(candidates) {
78
+ const groups = new Map();
79
+ for (const c of candidates) {
80
+ const key = c.actions
81
+ .map(a => (a.kind === "call" ? a.function : a.kind))
82
+ .join("→");
83
+ const existing = groups.get(key);
84
+ if (existing) {
85
+ // Merge: combine evidence sources and take max evidence count
86
+ const existingSources = existing.evidenceSources || [existing.source];
87
+ const newSource = c.source;
88
+ if (!existingSources.includes(newSource)) {
89
+ existingSources.push(newSource);
90
+ }
91
+ existing.evidenceSources = existingSources;
92
+ existing.evidence = Math.max(existing.evidence || 0, c.evidence || 0);
93
+ // Merge metadata: highest historicalSuccessRate wins
94
+ if (c.metadata?.historicalSuccessRate !== undefined &&
95
+ (existing.metadata?.historicalSuccessRate === undefined ||
96
+ c.metadata.historicalSuccessRate > existing.metadata.historicalSuccessRate)) {
97
+ existing.metadata = { ...existing.metadata, ...c.metadata };
98
+ }
99
+ }
100
+ else {
101
+ c.evidenceSources = [c.source];
102
+ groups.set(key, c);
103
+ }
104
+ }
105
+ return [...groups.values()];
106
+ }
107
+ // ═══════════════════════════════════════════════════════════════
108
+ // P7.3: Ranker Factory — env-var-driven ranker selection
109
+ // ═══════════════════════════════════════════════════════════════
110
+ let _activeLearningRanker = null;
111
+ let _rankerType = "heuristic";
112
+ let _modelWeight = 0.3;
113
+ let _modelSampleCount = 0;
114
+ let _rankerStartTime = 0;
115
+ /** Get (or create) the LearningRanker singleton with pre-trained model. */
116
+ function getActiveLearningRanker() {
117
+ if (_activeLearningRanker)
118
+ return _activeLearningRanker;
119
+ _rankerType = "learning";
120
+ _rankerStartTime = Date.now();
121
+ _modelWeight = parseFloat(process.env.PROGMUNE_MODEL_WEIGHT || "0.3");
122
+ const baseRanker = (0, repair_ranker_1.createLinearRanker)();
123
+ const telemetry = new planner_telemetry_1.PlannerTelemetry();
124
+ // Try to load pre-trained reward model from models/
125
+ let rewardModel;
126
+ try {
127
+ const modelPath = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "models", "reward-model.json");
128
+ if (fs.existsSync(modelPath)) {
129
+ const data = JSON.parse(fs.readFileSync(modelPath, "utf-8"));
130
+ rewardModel = logistic_reward_1.LogisticRewardModel.importWeights(data);
131
+ }
132
+ }
133
+ catch {
134
+ // No pre-trained model → fall back to telemetry-only learning
135
+ }
136
+ _modelSampleCount = (rewardModel ? rewardModel.sampleCount : 0);
137
+ _activeLearningRanker = new learning_ranker_1.LearningRanker(baseRanker, telemetry, { baseWeight: 0.7, feedbackWeight: 0.3, minSamples: 5 }, rewardModel, _modelWeight);
138
+ return _activeLearningRanker;
139
+ }
140
+ /** Return the current ranker status and metrics. */
141
+ function getRankerStatus() {
142
+ return {
143
+ type: _rankerType,
144
+ modelWeight: _rankerType === "learning" ? _modelWeight : 0,
145
+ modelSamples: _rankerType === "learning" ? _modelSampleCount : 0,
146
+ uptimeSeconds: _rankerStartTime > 0 ? Math.round((Date.now() - _rankerStartTime) / 1000) : 0,
147
+ };
148
+ }
149
+ // ═══════════════════════════════════════════════════════════════
150
+ // Public API
151
+ // ═══════════════════════════════════════════════════════════════
152
+ /**
153
+ * Generate the top-3 counterfactual repair alternatives for a violation.
154
+ *
155
+ * This is V3's killer feature: "告诉你三条修法"
156
+ *
157
+ * Internally delegates to Strategy → Candidate → Ranker pipeline.
158
+ */
159
+ async function suggestAlternatives(params) {
160
+ // 1. Build search context
161
+ const ctx = {
162
+ protocol: params.protocol || "default",
163
+ currentState: (params.currentState?.length ?? 0) > 0
164
+ ? params.currentState
165
+ : params.violation.currentStates || [],
166
+ targetState: (params.targetState?.length ?? 0) > 0
167
+ ? params.targetState
168
+ : (params.violation.requiredStates?.length ?? 0) > 0
169
+ ? params.violation.requiredStates
170
+ : [], // Keep empty to trigger cleanup path — don't fake COMPLETED
171
+ violationType: params.violation.violatedConstraint || "protocol_violation",
172
+ constraints: params.constraints || [],
173
+ rules: params.rules || new Map(),
174
+ goal: params.goal,
175
+ };
176
+ // 2. Run all strategies to collect candidates (no scoring in strategies)
177
+ const strategies = (0, repair_strategies_1.createDefaultStrategies)();
178
+ const allCandidates = [];
179
+ for (const strategy of strategies) {
180
+ allCandidates.push(...strategy.search(ctx));
181
+ }
182
+ // P8.3: If no candidates found, try ZeroShotStrategy
183
+ if (allCandidates.length === 0) {
184
+ const zeroShot = new zeroshot_strategy_1.ZeroShotStrategy();
185
+ allCandidates.push(...zeroShot.search(ctx));
186
+ }
187
+ // 3. Deduplicate by action signature, merge evidence sources
188
+ const uniqueCandidates = deduplicateCandidates(allCandidates);
189
+ if (uniqueCandidates.length === 0)
190
+ return [];
191
+ // 4. Extract features and rank
192
+ const maxActions = Math.max(...uniqueCandidates.map(c => c.actions.length), 8);
193
+ const features = uniqueCandidates.map(c => (0, repair_ranker_1.extractFeatures)(c, ctx, { maxActions }));
194
+ // P7.3: Ranker selection via PROGMUNE_RANKER env var
195
+ // "learning" → LearningRanker with pre-trained reward model
196
+ // "heuristic" (default) → LinearRanker with goalMatch weights
197
+ const rankerType = process.env.PROGMUNE_RANKER || "heuristic";
198
+ let ranked;
199
+ if (rankerType === "learning") {
200
+ const learner = getActiveLearningRanker();
201
+ ranked = learner.rank(uniqueCandidates, features, {
202
+ protocol: ctx.protocol,
203
+ violationType: ctx.violationType,
204
+ });
205
+ }
206
+ else {
207
+ const ranker = (0, repair_ranker_1.createLinearRanker)();
208
+ ranked = ranker.rankOverall(uniqueCandidates, features);
209
+ }
210
+ // 5. Map back to CounterfactualAlternative (backward-compat)
211
+ const top3 = ranked.slice(0, 3);
212
+ const alternatives = top3.map((c, i) => {
213
+ // Re-extract features for the final ranked position
214
+ const f = features[uniqueCandidates.indexOf(c)] ||
215
+ (0, repair_ranker_1.extractFeatures)(c, ctx, { maxActions });
216
+ // Score: use LearningRanker score if available, otherwise compute from LinearRanker
217
+ const score = c.score !== undefined
218
+ ? c.score
219
+ : (0, repair_ranker_1.createLinearRanker)().score(f);
220
+ return {
221
+ rank: i + 1,
222
+ description: c.explanation,
223
+ fixPath: c.actions
224
+ .filter(a => a.kind === "call")
225
+ .map(a => a.function),
226
+ targetState: ctx.targetState,
227
+ score,
228
+ source: c.source === "protocol" ? "ssg_bfs" : c.source,
229
+ historicalSuccessRate: f.historicalSuccessRate,
230
+ corpusEvidenceCount: f.corpusEvidence,
231
+ satisfiedConstraints: ctx.constraints
232
+ .filter(cn => (cn.type === "safety" || cn.type === "security") &&
233
+ c.actions.length <= 5)
234
+ .map(cn => cn.description),
235
+ repairStrategy: c.metadata?.source,
236
+ };
237
+ });
238
+ return alternatives;
239
+ }
240
+ /**
241
+ * Format alternatives as human-readable text (for LLM prompts or CLI output).
242
+ */
243
+ function formatAlternatives(alternatives) {
244
+ if (alternatives.length === 0)
245
+ return "未找到修复方案。";
246
+ const lines = [];
247
+ for (const alt of alternatives) {
248
+ const badge = alt.source === "corpus"
249
+ ? "📊 历史数据"
250
+ : alt.source === "ssg_bfs"
251
+ ? "🔍 协议搜索"
252
+ : alt.source === "antibody"
253
+ ? "🛡️ 抗体规则"
254
+ : "🤖 LLM";
255
+ lines.push(`方案 ${alt.rank}: ${alt.description}`);
256
+ lines.push(` 路径: ${alt.fixPath.join(" → ")}`);
257
+ lines.push(` 置信度: ${(alt.score * 100).toFixed(0)}% | ${badge}`);
258
+ if (alt.historicalSuccessRate > 0) {
259
+ lines.push(` 历史成功率: ${(alt.historicalSuccessRate * 100).toFixed(0)}% (${alt.corpusEvidenceCount} 案例)`);
260
+ }
261
+ if (alt.satisfiedConstraints.length > 0) {
262
+ lines.push(` 满足约束: ${alt.satisfiedConstraints.join(", ")}`);
263
+ }
264
+ }
265
+ return lines.join("\n");
266
+ }
267
+ // ═══════════════════════════════════════════════════════════════
268
+ // CLI
269
+ // ═══════════════════════════════════════════════════════════════
270
+ if (require.main === module) {
271
+ const testViolation = {
272
+ svl: 4,
273
+ violatedConstraint: "protocol_violation",
274
+ actionIndex: 1,
275
+ currentStates: ["Open"],
276
+ requiredStates: ["Closed"],
277
+ description: "文件未关闭",
278
+ };
279
+ suggestAlternatives({
280
+ violation: testViolation,
281
+ protocol: "FileProtocol",
282
+ currentState: ["Open"],
283
+ targetState: ["Closed"],
284
+ constraints: [{ type: "safety", value: 0.8, description: "安全写入" }],
285
+ }).then(alts => {
286
+ console.log(formatAlternatives(alts));
287
+ });
288
+ }