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,149 @@
1
+ "use strict";
2
+ /**
3
+ * P4.5+: Discovery Reward Model
4
+ *
5
+ * Predicts P(candidate_exists | goal, protocol, violation) rather than
6
+ * P(accepted | candidate). This is the signal that should drive
7
+ * Guided Frontier — not "how likely is this path to be accepted?"
8
+ * but "how likely is a path through this state to even be found?"
9
+ *
10
+ * Training data: benchmark attributions (foundCandidate = 1 - missingCandidate)
11
+ * Features: protocol, violation type, state context
12
+ *
13
+ * When 57% of failures are missing_candidate, the most valuable signal
14
+ * for search guidance is discoverability, not acceptability.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.DiscoveryModel = void 0;
18
+ exports.generateDiscoverabilityReport = generateDiscoverabilityReport;
19
+ exports.printDiscoverabilityReport = printDiscoverabilityReport;
20
+ function sigmoid(z) {
21
+ if (z > 20)
22
+ return 1.0;
23
+ if (z < -20)
24
+ return 0.0;
25
+ return 1.0 / (1.0 + Math.exp(-z));
26
+ }
27
+ // ═══════════════════════════════════════════════════════════════
28
+ // Discovery Model
29
+ // ═══════════════════════════════════════════════════════════════
30
+ const KNOWN_PROTOCOLS = ["FileProtocol", "AuthProtocol", "DBProtocol", "IRProtocol", "_global"];
31
+ const KNOWN_VIOLATIONS = ["resource_leak", "missing_prerequisite", "illegal_state_transition"];
32
+ function featuresToArray(f) {
33
+ const protoBits = KNOWN_PROTOCOLS.map(p => f.protocol === p ? 1.0 : 0.0);
34
+ const violBits = KNOWN_VIOLATIONS.map(v => f.violationType === v ? 1.0 : 0.0);
35
+ return [
36
+ f.isResourceLeak,
37
+ f.isMissingPrereq,
38
+ f.isIllegalState,
39
+ f.currentStateCount / 10,
40
+ ...protoBits,
41
+ ...violBits,
42
+ ];
43
+ }
44
+ const FEATURE_DIM = 4 + KNOWN_PROTOCOLS.length + KNOWN_VIOLATIONS.length; // 4 + 5 + 3 = 12
45
+ class DiscoveryModel {
46
+ constructor(weights, bias) {
47
+ this.weights = weights || new Array(FEATURE_DIM).fill(0);
48
+ this.bias = bias || 0;
49
+ this.trained = weights !== undefined;
50
+ this.trainedSamples = 0;
51
+ }
52
+ get isTrained() { return this.trained; }
53
+ get sampleCount() { return this.trainedSamples; }
54
+ /** Predict probability that a candidate exists for this context. */
55
+ predict(features) {
56
+ return sigmoid(this.score(featuresToArray(features)));
57
+ }
58
+ score(x) {
59
+ return x.reduce((s, v, i) => s + this.weights[i] * v, 0) + this.bias;
60
+ }
61
+ // ── Training ──
62
+ static samplesFromAttributions(attributed) {
63
+ return attributed.map(a => ({
64
+ features: {
65
+ protocol: a.protocol,
66
+ violationType: a.violationType,
67
+ isResourceLeak: a.violationType === "resource_leak" ? 1 : 0,
68
+ isMissingPrereq: a.violationType === "missing_prerequisite" ? 1 : 0,
69
+ isIllegalState: a.violationType === "illegal_state_transition" ? 1 : 0,
70
+ currentStateCount: 1,
71
+ },
72
+ label: a.failureReason !== "missing_candidate" ? 1 : 0,
73
+ goal: a.goal,
74
+ }));
75
+ }
76
+ static train(samples, learningRate = 0.01, epochs = 100) {
77
+ if (samples.length < 10)
78
+ return new DiscoveryModel();
79
+ let w = new Array(FEATURE_DIM).fill(0).map(() => (Math.random() - 0.5) * 0.1);
80
+ let b = 0.0;
81
+ for (let epoch = 0; epoch < epochs; epoch++) {
82
+ const shuffled = [...samples].sort(() => Math.random() - 0.5);
83
+ for (const sample of shuffled) {
84
+ const x = featuresToArray(sample.features);
85
+ const z = w.reduce((s, wi, i) => s + wi * x[i], 0) + b;
86
+ const p = sigmoid(z);
87
+ const error = p - sample.label;
88
+ for (let i = 0; i < FEATURE_DIM; i++) {
89
+ w[i] -= learningRate * error * x[i];
90
+ }
91
+ b -= learningRate * error;
92
+ }
93
+ }
94
+ const model = new DiscoveryModel(w, b);
95
+ model.trained = true;
96
+ model.trainedSamples = samples.length;
97
+ return model;
98
+ }
99
+ /** Feature importance for interpretability. */
100
+ featureImportance() {
101
+ const names = [
102
+ "isResourceLeak", "isMissingPrereq", "isIllegalState", "stateCount",
103
+ ...KNOWN_PROTOCOLS.map(p => `proto:${p}`),
104
+ ...KNOWN_VIOLATIONS.map(v => `viol:${v}`),
105
+ ];
106
+ return names.map((name, i) => ({ name, weight: this.weights[i] }))
107
+ .sort((a, b) => Math.abs(b.weight) - Math.abs(a.weight));
108
+ }
109
+ }
110
+ exports.DiscoveryModel = DiscoveryModel;
111
+ /**
112
+ * Generate a discoverability report: which protocol/violation combinations
113
+ * are least likely to have candidates found?
114
+ */
115
+ function generateDiscoverabilityReport(model) {
116
+ const predictions = [];
117
+ for (const proto of KNOWN_PROTOCOLS) {
118
+ for (const viol of KNOWN_VIOLATIONS) {
119
+ const features = {
120
+ protocol: proto,
121
+ violationType: viol,
122
+ isResourceLeak: viol === "resource_leak" ? 1 : 0,
123
+ isMissingPrereq: viol === "missing_prerequisite" ? 1 : 0,
124
+ isIllegalState: viol === "illegal_state_transition" ? 1 : 0,
125
+ currentStateCount: 1,
126
+ };
127
+ const discoverability = model.predict(features);
128
+ predictions.push({
129
+ protocol: proto,
130
+ violationType: viol,
131
+ discoverability,
132
+ priority: 1 - discoverability,
133
+ });
134
+ }
135
+ }
136
+ return predictions.sort((a, b) => b.priority - a.priority);
137
+ }
138
+ function printDiscoverabilityReport(predictions) {
139
+ console.log("\n─── Discoverability Report ───");
140
+ console.log("Protocol Violation Discover Priority");
141
+ console.log("─────────────────────────────────────────────────────────────");
142
+ for (const p of predictions.slice(0, 10)) {
143
+ const disc = (p.discoverability * 100).toFixed(0).padStart(4);
144
+ const pri = (p.priority * 100).toFixed(0).padStart(4);
145
+ const icon = p.priority > 0.5 ? "🔴" : p.priority > 0.3 ? "🟡" : "🟢";
146
+ console.log(` ${p.protocol.padEnd(16)} ${p.violationType.padEnd(22)} ${disc}% ${pri}% ${icon}`);
147
+ }
148
+ console.log();
149
+ }
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ /**
3
+ * P4.5-4.7: Guided Frontier + Macro Mining + Discovery Analytics 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 guided_frontier_1 = require("./guided-frontier");
43
+ const macro_repair_1 = require("./macro-repair");
44
+ const discovery_analytics_1 = require("./discovery-analytics");
45
+ const planner_telemetry_1 = require("./planner-telemetry");
46
+ function mergeProtocolRules(...maps) {
47
+ const m = new Map();
48
+ for (const mp of maps)
49
+ for (const [k, v] of mp)
50
+ m.set(k, v);
51
+ return m;
52
+ }
53
+ const fileRules = new Map([
54
+ ["open_file", { pre_states: [], post_states: ["FILE_OPEN"] }],
55
+ ["write_file", { pre_states: ["FILE_OPEN"], post_states: [] }],
56
+ ["close_file", { pre_states: ["FILE_OPEN"], post_states: [], invalidate: ["FILE_OPEN"] }],
57
+ ]);
58
+ const authRules = new Map([
59
+ ["verify_password", { pre_states: ["UNAUTHENTICATED"], post_states: ["PASSWORD_VERIFIED"] }],
60
+ ["generate_jwt", { pre_states: ["PASSWORD_VERIFIED"], post_states: ["TOKEN_ISSUED"], invalidate: ["PASSWORD_VERIFIED"] }],
61
+ ["create_session", { pre_states: ["TOKEN_ISSUED"], post_states: ["SESSION_ACTIVE"], invalidate: ["TOKEN_ISSUED"] }],
62
+ ["logout", { pre_states: ["SESSION_ACTIVE"], post_states: ["UNAUTHENTICATED"], invalidate: ["SESSION_ACTIVE"] }],
63
+ ]);
64
+ const dbRules = new Map([
65
+ ["connect_db", { pre_states: [], post_states: ["DB_CONNECTED"] }],
66
+ ["query_db", { pre_states: ["DB_CONNECTED"], post_states: [] }],
67
+ ["disconnect_db", { pre_states: ["DB_CONNECTED"], post_states: [], invalidate: ["DB_CONNECTED"] }],
68
+ ]);
69
+ const OPT_DIR = path.resolve(__dirname, "..", "test-discovery-optimize");
70
+ process.env.PROGMUNE_PROJECT_DIR = OPT_DIR;
71
+ fs.mkdirSync(OPT_DIR, { recursive: true });
72
+ fs.mkdirSync(path.join(OPT_DIR, ".progmune_corpus", "telemetry"), { recursive: true });
73
+ function seedHighAcceptanceTelemetry(n) {
74
+ const t = new planner_telemetry_1.PlannerTelemetry(path.join(OPT_DIR, ".progmune_corpus", "telemetry", `opt-${Date.now()}.jsonl`));
75
+ // Pattern: "open_file → write_file → close_file" accepted 90% of the time
76
+ for (let i = 0; i < n; i++) {
77
+ const actions = ["open_file", "write_file", "close_file"];
78
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", actions, "resource_leak");
79
+ const id = t.recordDecision({
80
+ goal: "safely write config file",
81
+ protocol: "FileProtocol", violationType: "resource_leak",
82
+ candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions, explanation: "full sequence" }],
83
+ selectedCandidateId: fp,
84
+ cost: { latencyMs: 3 + Math.random() * 5 },
85
+ });
86
+ const accepted = Math.random() < 0.9;
87
+ t.recordFeedback(id, {
88
+ decision: accepted ? "accepted" : "rejected",
89
+ executionResult: accepted ? { success: true, violations: [] } : { success: false, violations: ["resource_leak"] },
90
+ timestamp: Date.now(),
91
+ });
92
+ }
93
+ // Auth pattern: accepted 85%
94
+ for (let i = 0; i < n; i++) {
95
+ const actions = ["verify_password", "generate_jwt", "create_session"];
96
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("AuthProtocol", actions, "missing_prerequisite");
97
+ const id = t.recordDecision({
98
+ goal: "authenticate user",
99
+ protocol: "AuthProtocol", violationType: "missing_prerequisite",
100
+ candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions, explanation: "auth flow" }],
101
+ selectedCandidateId: fp,
102
+ });
103
+ const accepted = Math.random() < 0.85;
104
+ t.recordFeedback(id, {
105
+ decision: accepted ? "accepted" : "rejected",
106
+ executionResult: accepted ? { success: true, violations: [] } : undefined,
107
+ timestamp: Date.now(),
108
+ });
109
+ }
110
+ return t;
111
+ }
112
+ (0, vitest_1.describe)("P4.5 Reward-Guided Frontier", () => {
113
+ (0, vitest_1.it)("guided search finds paths with priority ordering", () => {
114
+ const rules = mergeProtocolRules(authRules, fileRules, dbRules);
115
+ const paths = (0, guided_frontier_1.guidedSearch)(rules, ["UNAUTHENTICATED"], ["SESSION_ACTIVE"]);
116
+ (0, vitest_1.expect)(paths.length).toBeGreaterThan(0);
117
+ // Should find auth path
118
+ const hasAuth = paths.some(p => p.actions.includes("verify_password") && p.actions.includes("generate_jwt"));
119
+ (0, vitest_1.expect)(hasAuth).toBe(true);
120
+ // Paths should be sorted by priority (descending)
121
+ for (let i = 1; i < paths.length; i++) {
122
+ (0, vitest_1.expect)(paths[i - 1].priority).toBeGreaterThanOrEqual(paths[i].priority);
123
+ }
124
+ });
125
+ (0, vitest_1.it)("multi-start finds paths from different initial states", () => {
126
+ const rules = mergeProtocolRules(fileRules, authRules);
127
+ const paths = (0, guided_frontier_1.guidedSearchMulti)(rules, [
128
+ ["FILE_OPEN"],
129
+ ["UNAUTHENTICATED"],
130
+ ], ["SESSION_ACTIVE"]);
131
+ (0, vitest_1.expect)(paths.length).toBeGreaterThan(0);
132
+ // Should include paths from both starting points
133
+ (0, vitest_1.expect)(paths.every(p => p.found)).toBe(true);
134
+ });
135
+ });
136
+ (0, vitest_1.describe)("P4.6 Macro Repair Mining", () => {
137
+ (0, vitest_1.it)("mines high-acceptance patterns from telemetry", () => {
138
+ const telemetry = seedHighAcceptanceTelemetry(50);
139
+ const macros = (0, macro_repair_1.mineMacroRepairs)(telemetry, 0.7, 3);
140
+ (0, vitest_1.expect)(macros.length).toBeGreaterThanOrEqual(1);
141
+ // File repair pattern should be mined
142
+ const fileMacro = macros.find(m => m.protocol === "FileProtocol");
143
+ (0, vitest_1.expect)(fileMacro).toBeDefined();
144
+ (0, vitest_1.expect)(fileMacro.acceptanceRate).toBeGreaterThan(0.7);
145
+ (0, vitest_1.expect)(fileMacro.actions).toEqual(["open_file", "write_file", "close_file"]);
146
+ (0, macro_repair_1.printMacroReport)(macros);
147
+ });
148
+ (0, vitest_1.it)("persists and loads macros", () => {
149
+ const telemetry = seedHighAcceptanceTelemetry(60);
150
+ const mined = (0, macro_repair_1.mineMacroRepairs)(telemetry, 0.7, 3);
151
+ const fp = (0, macro_repair_1.saveMacroRepairs)(mined);
152
+ (0, vitest_1.expect)(fs.existsSync(fp)).toBe(true);
153
+ const loaded = (0, macro_repair_1.loadMacroRepairs)();
154
+ (0, vitest_1.expect)(loaded.length).toBeGreaterThanOrEqual(mined.length);
155
+ });
156
+ (0, vitest_1.it)("filters out low-frequency patterns", () => {
157
+ const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(OPT_DIR, ".progmune_corpus", "telemetry", `lowfreq-${Date.now()}.jsonl`));
158
+ // Only 2 samples — below minFrequency=3
159
+ for (let i = 0; i < 2; i++) {
160
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"], "resource_leak");
161
+ const id = telemetry.recordDecision({
162
+ goal: "test", protocol: "FileProtocol",
163
+ candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions: ["close_file"], explanation: "close" }],
164
+ selectedCandidateId: fp,
165
+ });
166
+ telemetry.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, timestamp: Date.now() });
167
+ }
168
+ const macros = (0, macro_repair_1.mineMacroRepairs)(telemetry, 0.7, 3);
169
+ (0, vitest_1.expect)(macros.length).toBe(0); // not enough frequency
170
+ });
171
+ });
172
+ (0, vitest_1.describe)("P4.7 Discovery Analytics", () => {
173
+ (0, vitest_1.it)("computes discovery metrics from attributions", () => {
174
+ const attributed = [
175
+ { caseId: "c1", goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak", expectedRepair: ["close_file"], candidatesReturned: 2, rank: 1, failureReason: "success" },
176
+ { caseId: "c2", goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak", expectedRepair: ["close_file"], candidatesReturned: 1, rank: null, failureReason: "bad_ranking" },
177
+ { caseId: "c3", goal: "authenticate", protocol: "AuthProtocol", violationType: "missing_prerequisite", expectedRepair: ["generate_jwt"], candidatesReturned: 0, rank: null, failureReason: "missing_candidate" },
178
+ { caseId: "c4", goal: "logout user", protocol: "AuthProtocol", violationType: "illegal_state_transition", expectedRepair: ["logout"], candidatesReturned: 0, rank: null, failureReason: "missing_candidate" },
179
+ ];
180
+ const metrics = (0, discovery_analytics_1.computeDiscoveryMetrics)(attributed);
181
+ (0, vitest_1.expect)(metrics.totalCases).toBe(4);
182
+ (0, vitest_1.expect)(metrics.overall).toBe(0.5); // 2/4 discovered
183
+ // FileProtocol: 2/2 discovered
184
+ (0, vitest_1.expect)(metrics.byProtocol["FileProtocol"]).toBe(1.0);
185
+ // AuthProtocol: 0/2 discovered
186
+ (0, vitest_1.expect)(metrics.byProtocol["AuthProtocol"]).toBe(0);
187
+ // resource_leak: 2/2, missing_prerequisite: 0/1, illegal_state_transition: 0/1
188
+ (0, vitest_1.expect)(metrics.byViolation["resource_leak"]).toBe(1.0);
189
+ (0, vitest_1.expect)(metrics.byViolation["missing_prerequisite"]).toBe(0);
190
+ });
191
+ (0, vitest_1.it)("generates full analytics report", async () => {
192
+ const telemetry = seedHighAcceptanceTelemetry(30);
193
+ const report = await (0, discovery_analytics_1.generateFullAnalyticsReport)(telemetry);
194
+ (0, vitest_1.expect)(report.discovery.totalCases).toBeGreaterThanOrEqual(49);
195
+ (0, vitest_1.expect)(report.macroCount).toBeGreaterThanOrEqual(1);
196
+ (0, vitest_1.expect)(report.topMacros.length).toBeGreaterThanOrEqual(1);
197
+ (0, discovery_analytics_1.printDiscoveryDashboard)(report);
198
+ });
199
+ });
@@ -0,0 +1,276 @@
1
+ "use strict";
2
+ /**
3
+ * P3.24-27: Search Trace + Bridge Learning + Discovery Benchmark + Replay
4
+ *
5
+ * P3.24: Record WHY candidates are missing. Decompose 57% missing_candidate
6
+ * into missing_action, missing_transition, depth_limit, bridge_missing.
7
+ *
8
+ * P3.25: Protocol Bridge Learning — cross-protocol state bridges.
9
+ * Auth → File → DB → IR → Queue. Frontier BFS across protocols.
10
+ *
11
+ * P3.26: Discovery Benchmark — three-tier metric:
12
+ * DiscoveryRate (any correct candidate?) → Ranking (Top-1/Top-3) → Execution.
13
+ *
14
+ * P3.27: Counterfactual Replay — off-policy evaluation.
15
+ * Replay historical decisions with new ranker/frontier, compare acceptance.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.traceSearch = traceSearch;
19
+ exports.decomposeMissingCandidate = decomposeMissingCandidate;
20
+ exports.computeDiscoveryReport = computeDiscoveryReport;
21
+ exports.printDiscoveryReport = printDiscoveryReport;
22
+ exports.evaluateOffPolicy = evaluateOffPolicy;
23
+ exports.printReplayEvaluation = printReplayEvaluation;
24
+ exports.learnProtocolBridges = learnProtocolBridges;
25
+ const protocol_coverage_1 = require("./protocol-coverage");
26
+ /**
27
+ * Trace a frontier search and classify WHY candidates are missing.
28
+ */
29
+ function traceSearch(rules, currentStates, targetStates, expectedRepair, strategy = "frontier", goal, maxDepth = 6) {
30
+ const trace = {
31
+ strategy, goal,
32
+ expandedNodes: [], prunedNodes: [], deadEnds: [],
33
+ maxDepthReached: 0, candidateGenerated: false, candidateCount: 0,
34
+ };
35
+ const visited = new Set();
36
+ const queue = [
37
+ { states: new Set(currentStates), actions: [], depth: 0 },
38
+ ];
39
+ visited.add([...currentStates].sort().join(","));
40
+ while (queue.length > 0) {
41
+ const { states, actions, depth } = queue.shift();
42
+ trace.maxDepthReached = Math.max(trace.maxDepthReached, depth);
43
+ if (depth >= maxDepth) {
44
+ trace.deadEnds.push({ node: [...states].join(","), reason: "depth_limit" });
45
+ continue;
46
+ }
47
+ let anyRuleApplied = false;
48
+ for (const [fn, rule] of rules) {
49
+ const preOk = rule.pre_states.length === 0 || rule.pre_states.every(p => states.has(p));
50
+ if (!preOk)
51
+ continue;
52
+ anyRuleApplied = true;
53
+ const next = new Set(states);
54
+ if (rule.invalidate)
55
+ rule.invalidate.forEach(s => next.delete(s));
56
+ for (const post of rule.post_states)
57
+ next.add(post);
58
+ const key = [...next].sort().join(",");
59
+ if (visited.has(key))
60
+ continue;
61
+ visited.add(key);
62
+ trace.expandedNodes.push(fn);
63
+ const newActions = [...actions, fn];
64
+ // Check if this reaches the expected repair
65
+ if (expectedRepair.every(fn => newActions.includes(fn))) {
66
+ trace.candidateGenerated = true;
67
+ trace.candidateCount++;
68
+ }
69
+ queue.push({ states: next, actions: newActions, depth: depth + 1 });
70
+ }
71
+ if (!anyRuleApplied && depth > 0) {
72
+ trace.deadEnds.push({ node: [...states].join(","), reason: "precondition_failed" });
73
+ }
74
+ }
75
+ // Classify missing candidates by analyzing dead ends
76
+ for (const fn of expectedRepair) {
77
+ if (!rules.has(fn)) {
78
+ trace.deadEnds.push({ node: fn, reason: "missing_action" });
79
+ }
80
+ }
81
+ return trace;
82
+ }
83
+ /**
84
+ * Decompose a search failure into root causes.
85
+ */
86
+ function decomposeMissingCandidate(traces) {
87
+ const result = {
88
+ total: traces.length,
89
+ missingAction: 0,
90
+ missingTransition: 0,
91
+ depthLimit: 0,
92
+ bridgeMissing: 0,
93
+ preconditionFailed: 0,
94
+ };
95
+ for (const t of traces) {
96
+ if (t.candidateGenerated)
97
+ continue;
98
+ for (const de of t.deadEnds) {
99
+ switch (de.reason) {
100
+ case "missing_action":
101
+ result.missingAction++;
102
+ break;
103
+ case "missing_transition":
104
+ result.missingTransition++;
105
+ break;
106
+ case "depth_limit":
107
+ result.depthLimit++;
108
+ break;
109
+ case "bridge_missing":
110
+ result.bridgeMissing++;
111
+ break;
112
+ case "precondition_failed":
113
+ result.preconditionFailed++;
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ return result;
119
+ }
120
+ function computeDiscoveryReport(results) {
121
+ const total = results.length;
122
+ const discovered = results.filter(r => r.discovery).length;
123
+ const top1 = results.filter(r => r.top1Hit).length;
124
+ const top3 = results.filter(r => r.top3Hit).length;
125
+ const avgCand = results.reduce((s, r) => s + r.candidateCount, 0) / Math.max(1, total);
126
+ // Aggregate decompositions
127
+ const allTraces = results
128
+ .filter(r => !r.discovery && r.decomposition)
129
+ .map(r => r.decomposition);
130
+ const merged = {
131
+ total: allTraces.length,
132
+ missingAction: allTraces.reduce((s, d) => s + d.missingAction, 0),
133
+ missingTransition: allTraces.reduce((s, d) => s + d.missingTransition, 0),
134
+ depthLimit: allTraces.reduce((s, d) => s + d.depthLimit, 0),
135
+ bridgeMissing: allTraces.reduce((s, d) => s + d.bridgeMissing, 0),
136
+ preconditionFailed: allTraces.reduce((s, d) => s + d.preconditionFailed, 0),
137
+ };
138
+ return {
139
+ cases: total,
140
+ discoveryRate: total > 0 ? discovered / total : 0,
141
+ top3Rate: total > 0 ? top3 / total : 0,
142
+ top1Rate: total > 0 ? top1 / total : 0,
143
+ avgCandidates: avgCand,
144
+ gapBreakdown: merged,
145
+ };
146
+ }
147
+ function printDiscoveryReport(report) {
148
+ console.log("\n╔════════════════════════════════════════════════════╗");
149
+ console.log("║ Discovery Benchmark ║");
150
+ console.log("╚════════════════════════════════════════════════════╝\n");
151
+ const dr = (report.discoveryRate * 100).toFixed(0);
152
+ const t1 = (report.top1Rate * 100).toFixed(0);
153
+ const t3 = (report.top3Rate * 100).toFixed(0);
154
+ console.log(`Cases: ${report.cases}`);
155
+ console.log(`Discovery Rate: ${dr}% (any correct candidate found)`);
156
+ console.log(`Top-3 Accuracy: ${t3}%`);
157
+ console.log(`Top-1 Accuracy: ${t1}%`);
158
+ console.log(`Avg Candidates: ${report.avgCandidates.toFixed(1)}`);
159
+ console.log();
160
+ if (report.gapBreakdown.total > 0) {
161
+ console.log("─── Missing Candidate Decomposition ───");
162
+ const g = report.gapBreakdown;
163
+ console.log(` missing_action: ${g.missingAction}`);
164
+ console.log(` missing_transition: ${g.missingTransition}`);
165
+ console.log(` depth_limit: ${g.depthLimit}`);
166
+ console.log(` bridge_missing: ${g.bridgeMissing}`);
167
+ console.log(` precondition_failed: ${g.preconditionFailed}`);
168
+ console.log();
169
+ }
170
+ const discoveryGap = report.discoveryRate - report.top1Rate;
171
+ if (discoveryGap > 0.15) {
172
+ console.log(` ⚠️ Discovery→Top1 gap: ${(discoveryGap * 100).toFixed(0)}% — ranking is the bottleneck`);
173
+ }
174
+ else if (report.discoveryRate < 0.5) {
175
+ console.log(` ⚠️ Discovery < 50% — candidate generation is the bottleneck`);
176
+ }
177
+ console.log();
178
+ }
179
+ /**
180
+ * Off-policy evaluation: compare old system vs new system.
181
+ *
182
+ * Given historical decisions (what was proposed, what was accepted),
183
+ * and a new candidate generator, compute how the new system would
184
+ * have performed on the same decisions.
185
+ */
186
+ function evaluateOffPolicy(decisions, newCandidateGenerator, matchFn = (c, a) => a.every(fn => c.includes(fn))) {
187
+ let baselineAccepted = 0;
188
+ let newAccepted = 0;
189
+ for (const d of decisions) {
190
+ // Baseline: was the accepted candidate in the original proposals?
191
+ if (d.acceptedActions) {
192
+ const baseMatch = d.candidates.some(c => matchFn(c, d.acceptedActions));
193
+ if (baseMatch)
194
+ baselineAccepted++;
195
+ }
196
+ // New: would the new generator have found the accepted candidate?
197
+ const newCandidates = newCandidateGenerator(d.goal, d.protocol);
198
+ if (d.acceptedActions && newCandidates.some(c => matchFn(c, d.acceptedActions))) {
199
+ newAccepted++;
200
+ }
201
+ }
202
+ const total = decisions.length;
203
+ return {
204
+ totalDecisions: total,
205
+ baselineAccepted,
206
+ baselineRate: total > 0 ? baselineAccepted / total : 0,
207
+ newAccepted,
208
+ newRate: total > 0 ? newAccepted / total : 0,
209
+ delta: total > 0 ? (newAccepted - baselineAccepted) / total : 0,
210
+ improvement: newAccepted > baselineAccepted,
211
+ };
212
+ }
213
+ function printReplayEvaluation(eval_) {
214
+ console.log("\n╔════════════════════════════════════════════════════╗");
215
+ console.log("║ Counterfactual Replay (Off-Policy) ║");
216
+ console.log("╚════════════════════════════════════════════════════╝\n");
217
+ const base = (eval_.baselineRate * 100).toFixed(1);
218
+ const nw = (eval_.newRate * 100).toFixed(1);
219
+ const delta = (eval_.delta * 100).toFixed(1);
220
+ const sign = eval_.delta > 0 ? "+" : "";
221
+ console.log(`Decisions Replayed: ${eval_.totalDecisions}`);
222
+ console.log(`Baseline (old): ${base}% (${eval_.baselineAccepted}/${eval_.totalDecisions})`);
223
+ console.log(`New System: ${nw}% (${eval_.newAccepted}/${eval_.totalDecisions})`);
224
+ console.log(`Δ: ${sign}${delta}%`);
225
+ console.log();
226
+ if (eval_.improvement) {
227
+ console.log(` ✅ New system outperforms baseline by ${sign}${delta}%`);
228
+ }
229
+ else if (eval_.delta === 0) {
230
+ console.log(" ═ No change. New system matches baseline.");
231
+ }
232
+ else {
233
+ console.log(` ❌ New system regresses by ${sign}${delta}%`);
234
+ }
235
+ console.log();
236
+ }
237
+ /**
238
+ * Learn cross-protocol bridges from benchmark failures.
239
+ *
240
+ * When a benchmark expects auth → file → db chains, but the
241
+ * protocols are isolated, infer bridges connecting them.
242
+ */
243
+ function learnProtocolBridges(crossProtocolFailures) {
244
+ const defs = (0, protocol_coverage_1.loadDefaultProtocolDefinitions)();
245
+ const protoRules = new Map(defs.map(p => [p.name, p.rules]));
246
+ const bridges = [];
247
+ const bridgeCounts = new Map();
248
+ for (const f of crossProtocolFailures) {
249
+ // Determine which protocols are involved
250
+ const involved = new Set();
251
+ for (const fn of f.expectedRepair) {
252
+ for (const [name, rules] of protoRules) {
253
+ if (rules.has(fn))
254
+ involved.add(name);
255
+ }
256
+ }
257
+ const protoList = [...involved];
258
+ for (let i = 0; i < protoList.length - 1; i++) {
259
+ const from = protoList[i];
260
+ const to = protoList[i + 1];
261
+ const key = `${from}→${to}`;
262
+ bridgeCounts.set(key, (bridgeCounts.get(key) || 0) + 1);
263
+ }
264
+ }
265
+ const maxCount = Math.max(1, ...[...bridgeCounts.values()]);
266
+ for (const [key, count] of bridgeCounts) {
267
+ const [from, to] = key.split("→");
268
+ bridges.push({
269
+ fromProtocol: from, toProtocol: to,
270
+ viaState: "COMPLETED", targetState: "INIT",
271
+ confidence: count / maxCount,
272
+ evidenceCount: count,
273
+ });
274
+ }
275
+ return bridges.sort((a, b) => b.confidence - a.confidence);
276
+ }