progmune-runtime 2.1.6 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/README.md +108 -468
  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 +710 -0
  306. package/package.json +74 -7
  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,475 @@
1
+ "use strict";
2
+ /**
3
+ * P5: Verification Intelligence — the 5th paradigm shift.
4
+ *
5
+ * Moves Progmune from a Pattern Matcher to a Verification Decision Engine.
6
+ *
7
+ * The core question changes from:
8
+ * "Does this code violate protocol X?"
9
+ * to:
10
+ * "Should I alert on this? Why? Why not? What did I learn?"
11
+ *
12
+ * Architecture:
13
+ *
14
+ * Verification → Decision (alert? suppress?) → FP detected →
15
+ * Classify FP reason → Profile context → Adjust rule confidence →
16
+ * → Next time: better decision
17
+ *
18
+ * This closes the loop that turns every false positive into
19
+ * Verification Intelligence.
20
+ *
21
+ * FP Taxonomy (why did we wrongly alert?):
22
+ * FP-1: RULE_TOO_BROAD — Rule matches too many patterns (overfitting to clean seqs)
23
+ * FP-2: CONTEXT_MISMATCH — Rule is valid but wrong context (e.g., internal/init code)
24
+ * FP-3: NAMESPACE_LEAK — Rule from one namespace applied to another
25
+ * FP-4: ORDER_INSENSITIVE — Rule requires strict ordering but code is order-flexible
26
+ * FP-5: INCOMPLETE_RULE — Rule is too specific (missing valid alternative paths)
27
+ * FP-6: DOMAIN_IRRELEVANT — Rule is technically correct but irrelevant to this domain
28
+ * FP-7: LEGACY_COMPAT — Code follows legacy pattern that protocol doesn't cover
29
+ */
30
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ var desc = Object.getOwnPropertyDescriptor(m, k);
33
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
34
+ desc = { enumerable: true, get: function() { return m[k]; } };
35
+ }
36
+ Object.defineProperty(o, k2, desc);
37
+ }) : (function(o, m, k, k2) {
38
+ if (k2 === undefined) k2 = k;
39
+ o[k2] = m[k];
40
+ }));
41
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
42
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
43
+ }) : function(o, v) {
44
+ o["default"] = v;
45
+ });
46
+ var __importStar = (this && this.__importStar) || (function () {
47
+ var ownKeys = function(o) {
48
+ ownKeys = Object.getOwnPropertyNames || function (o) {
49
+ var ar = [];
50
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
51
+ return ar;
52
+ };
53
+ return ownKeys(o);
54
+ };
55
+ return function (mod) {
56
+ if (mod && mod.__esModule) return mod;
57
+ var result = {};
58
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
59
+ __setModuleDefault(result, mod);
60
+ return result;
61
+ };
62
+ })();
63
+ Object.defineProperty(exports, "__esModule", { value: true });
64
+ exports.VerificationIntelligence = exports.FP_REASON_LABELS = void 0;
65
+ exports.getVerificationIntelligence = getVerificationIntelligence;
66
+ exports.formatVILearningReport = formatVILearningReport;
67
+ const fs = __importStar(require("fs"));
68
+ const path = __importStar(require("path"));
69
+ exports.FP_REASON_LABELS = {
70
+ RULE_TOO_BROAD: {
71
+ label: "Rule too broad",
72
+ fix: "Narrow the rule by adding more specific pre/post states",
73
+ },
74
+ CONTEXT_MISMATCH: {
75
+ label: "Context mismatch",
76
+ fix: "Add context filter — not all call sites require the same protocol",
77
+ },
78
+ NAMESPACE_LEAK: {
79
+ label: "Namespace leak",
80
+ fix: "Restrict rule to its namespace; don't cross-apply",
81
+ },
82
+ ORDER_INSENSITIVE: {
83
+ label: "Order insensitive",
84
+ fix: "Relax ordering constraint — this protocol allows flexible ordering",
85
+ },
86
+ INCOMPLETE_RULE: {
87
+ label: "Incomplete rule",
88
+ fix: "Add missing alternative paths to the rule definition",
89
+ },
90
+ DOMAIN_IRRELEVANT: {
91
+ label: "Domain irrelevant",
92
+ fix: "Exclude this domain/codebase from this rule",
93
+ },
94
+ LEGACY_COMPAT: {
95
+ label: "Legacy compatibility",
96
+ fix: "Add legacy pattern as an accepted alternative",
97
+ },
98
+ };
99
+ // ═══════════════════════════════════════════════════════════════
100
+ // Verification Decision Engine
101
+ // ═══════════════════════════════════════════════════════════════
102
+ const VI_DIR = ".progmune_corpus/verification-intelligence";
103
+ class VerificationIntelligence {
104
+ constructor() {
105
+ this.ruleConfidences = new Map();
106
+ this.fpRecords = [];
107
+ this.contextFilters = new Map(); // rule → excluded contexts
108
+ this.load();
109
+ }
110
+ /**
111
+ * Make a verification decision: should we alert on this rule match?
112
+ *
113
+ * This REPLACES the binary valid/invalid with a calibrated decision.
114
+ */
115
+ decide(ruleName, protocol, context) {
116
+ const key = `${protocol}:${ruleName}`;
117
+ let rc = this.ruleConfidences.get(key);
118
+ if (!rc) {
119
+ // New rule — start with high confidence
120
+ rc = {
121
+ ruleName,
122
+ protocol,
123
+ initialConfidence: 0.9,
124
+ currentConfidence: 0.9,
125
+ totalAlerts: 0,
126
+ truePositives: 0,
127
+ falsePositives: 0,
128
+ suppressionThreshold: 0.3,
129
+ suppressed: false,
130
+ fpHistory: [],
131
+ lastAdjusted: new Date().toISOString(),
132
+ };
133
+ this.ruleConfidences.set(key, rc);
134
+ }
135
+ // Check context filters
136
+ if (this.isContextFiltered(ruleName, context)) {
137
+ return {
138
+ alert: false,
139
+ confidence: 0,
140
+ reason: `Rule ${ruleName} suppressed by context filter`,
141
+ triggeredRules: [],
142
+ suppressedRules: [ruleName],
143
+ recommendation: "SUPPRESS",
144
+ };
145
+ }
146
+ // Check if rule is suppressed (confidence too low)
147
+ if (rc.suppressed || rc.currentConfidence < rc.suppressionThreshold) {
148
+ return {
149
+ alert: false,
150
+ confidence: rc.currentConfidence,
151
+ reason: `Rule ${ruleName} suppressed (confidence ${(rc.currentConfidence * 100).toFixed(0)}% < threshold ${(rc.suppressionThreshold * 100).toFixed(0)}%)`,
152
+ triggeredRules: [],
153
+ suppressedRules: [ruleName],
154
+ recommendation: "SUPPRESS",
155
+ };
156
+ }
157
+ // Determine recommendation level based on confidence
158
+ let recommendation;
159
+ if (rc.currentConfidence >= 0.8)
160
+ recommendation = "BLOCK";
161
+ else if (rc.currentConfidence >= 0.6)
162
+ recommendation = "WARN";
163
+ else if (rc.currentConfidence >= 0.4)
164
+ recommendation = "INFO";
165
+ else
166
+ recommendation = "SUPPRESS";
167
+ return {
168
+ alert: true,
169
+ confidence: rc.currentConfidence,
170
+ reason: `Rule ${ruleName} triggered with ${(rc.currentConfidence * 100).toFixed(0)}% confidence (${rc.truePositives} TP, ${rc.falsePositives} FP)`,
171
+ triggeredRules: [ruleName],
172
+ suppressedRules: [],
173
+ recommendation,
174
+ };
175
+ }
176
+ /**
177
+ * Record a false positive and adjust rule confidence DOWN.
178
+ *
179
+ * This is the core learning mechanism: every FP reduces confidence,
180
+ * eventually suppressing the rule if it's too noisy.
181
+ */
182
+ recordFP(params) {
183
+ const key = `${params.protocol}:${params.ruleName}`;
184
+ let rc = this.ruleConfidences.get(key);
185
+ const record = {
186
+ id: `FP-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`,
187
+ timestamp: new Date().toISOString(),
188
+ repo: params.repo,
189
+ protocol: params.protocol,
190
+ sequence: params.sequence,
191
+ triggeredRules: [params.ruleName],
192
+ reason: params.reason,
193
+ context: params.context || {},
194
+ action: this.determineAction(params.reason),
195
+ labeledBy: params.labeledBy || "auto",
196
+ confidenceDelta: 0,
197
+ };
198
+ // Create rule if it doesn't exist yet
199
+ if (!rc) {
200
+ rc = {
201
+ ruleName: params.ruleName,
202
+ protocol: params.protocol,
203
+ initialConfidence: 0.9,
204
+ currentConfidence: 0.9,
205
+ totalAlerts: 0,
206
+ truePositives: 0,
207
+ falsePositives: 0,
208
+ suppressionThreshold: 0.3,
209
+ suppressed: false,
210
+ fpHistory: [],
211
+ lastAdjusted: new Date().toISOString(),
212
+ };
213
+ this.ruleConfidences.set(key, rc);
214
+ }
215
+ // Adjust confidence
216
+ rc.falsePositives++;
217
+ rc.totalAlerts++;
218
+ // Confidence decay: each FP reduces confidence by a factor
219
+ // New confidence = TP / (TP + FP) with Laplace smoothing
220
+ const effectiveTP = rc.truePositives + 1; // Laplace prior
221
+ const effectiveFP = rc.falsePositives + 1;
222
+ const oldConf = rc.currentConfidence;
223
+ rc.currentConfidence = effectiveTP / (effectiveTP + effectiveFP);
224
+ record.confidenceDelta = rc.currentConfidence - oldConf;
225
+ // Suppress if too noisy
226
+ if (rc.currentConfidence < rc.suppressionThreshold && rc.falsePositives >= 5) {
227
+ rc.suppressed = true;
228
+ }
229
+ rc.fpHistory.push(record.id);
230
+ rc.lastAdjusted = record.timestamp;
231
+ this.ruleConfidences.set(key, rc);
232
+ this.fpRecords.push(record);
233
+ this.save();
234
+ return record;
235
+ }
236
+ /**
237
+ * Record a true positive — confirms the rule is working.
238
+ */
239
+ recordTP(ruleName, protocol) {
240
+ const key = `${protocol}:${ruleName}`;
241
+ let rc = this.ruleConfidences.get(key);
242
+ if (!rc) {
243
+ rc = {
244
+ ruleName, protocol,
245
+ initialConfidence: 0.9, currentConfidence: 0.9,
246
+ totalAlerts: 0, truePositives: 0, falsePositives: 0,
247
+ suppressionThreshold: 0.3, suppressed: false,
248
+ fpHistory: [], lastAdjusted: new Date().toISOString(),
249
+ };
250
+ }
251
+ rc.truePositives++;
252
+ rc.totalAlerts++;
253
+ // Confidence boost from TP
254
+ const effectiveTP = rc.truePositives;
255
+ const effectiveFP = rc.falsePositives + 1; // Laplace
256
+ rc.currentConfidence = effectiveTP / (effectiveTP + effectiveFP);
257
+ // Un-suppress if confidence recovers
258
+ if (rc.suppressed && rc.currentConfidence >= rc.suppressionThreshold + 0.1) {
259
+ rc.suppressed = false;
260
+ }
261
+ rc.lastAdjusted = new Date().toISOString();
262
+ this.ruleConfidences.set(key, rc);
263
+ this.save();
264
+ }
265
+ /**
266
+ * Auto-classify a false positive based on sequence and rule characteristics.
267
+ */
268
+ autoClassifyFP(params) {
269
+ const { ruleName, sequence, context } = params;
270
+ // Heuristic 1: Context mismatch (test/init code) — most common FP source
271
+ if (context?.isTestCode || context?.isInitCode) {
272
+ return "CONTEXT_MISMATCH";
273
+ }
274
+ // Heuristic 2: Legacy/deprecated patterns — check BEFORE short-sequence heuristic
275
+ if (sequence.some(fn => /legacy|deprecated|old_|_v1|_compat/i.test(fn))) {
276
+ return "LEGACY_COMPAT";
277
+ }
278
+ // Heuristic 3: Internal/private functions (start with _ or contain "internal")
279
+ if (sequence.some(fn => fn.startsWith("_") || fn.includes("internal"))) {
280
+ return "DOMAIN_IRRELEVANT";
281
+ }
282
+ // Heuristic 4: Very long sequences (10+) → RULE_TOO_BROAD
283
+ if (sequence.length >= 10) {
284
+ return "RULE_TOO_BROAD";
285
+ }
286
+ // Heuristic 5: Short sequence with no resource management → RULE_TOO_BROAD
287
+ if (sequence.length <= 3 && !sequence.some(fn => /init|open|close|free|alloc|create|destroy/i.test(fn))) {
288
+ return "RULE_TOO_BROAD";
289
+ }
290
+ return "RULE_TOO_BROAD"; // Default
291
+ }
292
+ /**
293
+ * Get all rules that should currently be suppressed.
294
+ */
295
+ getSuppressedRules() {
296
+ return [...this.ruleConfidences.values()]
297
+ .filter(rc => rc.suppressed || rc.currentConfidence < rc.suppressionThreshold)
298
+ .sort((a, b) => a.currentConfidence - b.currentConfidence);
299
+ }
300
+ /**
301
+ * Get the FP learning report — what have we learned?
302
+ */
303
+ getFPLearningReport() {
304
+ const byReason = {};
305
+ const byRule = {};
306
+ for (const fp of this.fpRecords) {
307
+ byReason[fp.reason] = (byReason[fp.reason] || 0) + 1;
308
+ const ruleKey = `${fp.protocol}:${fp.triggeredRules[0]}`;
309
+ byRule[ruleKey] = (byRule[ruleKey] || 0) + 1;
310
+ }
311
+ const allConfidences = [...this.ruleConfidences.values()];
312
+ const avgConfidence = allConfidences.length > 0
313
+ ? allConfidences.reduce((s, rc) => s + rc.currentConfidence, 0) / allConfidences.length
314
+ : 0;
315
+ const topFPRules = Object.entries(byRule)
316
+ .sort((a, b) => b[1] - a[1])
317
+ .slice(0, 10)
318
+ .map(([rule, fps]) => {
319
+ const rc = this.ruleConfidences.get(rule);
320
+ return { rule, fps, confidence: rc?.currentConfidence || 0 };
321
+ });
322
+ return {
323
+ totalFPs: this.fpRecords.length,
324
+ byReason,
325
+ byRule,
326
+ suppressedRules: this.getSuppressedRules().length,
327
+ avgConfidence,
328
+ topFPRules,
329
+ };
330
+ }
331
+ // ═════════════════════════════════════════════════════════════
332
+ // Context Filters
333
+ // ═════════════════════════════════════════════════════════════
334
+ isContextFiltered(ruleName, context) {
335
+ if (!context)
336
+ return false;
337
+ const filter = this.contextFilters.get(ruleName);
338
+ if (!filter)
339
+ return false;
340
+ if (context.isTestCode && filter.has("test"))
341
+ return true;
342
+ if (context.isInitCode && filter.has("init"))
343
+ return true;
344
+ if (context.isInternal && filter.has("internal"))
345
+ return true;
346
+ return false;
347
+ }
348
+ addContextFilter(ruleName, filterType) {
349
+ if (!this.contextFilters.has(ruleName)) {
350
+ this.contextFilters.set(ruleName, new Set());
351
+ }
352
+ this.contextFilters.get(ruleName).add(filterType);
353
+ this.save();
354
+ }
355
+ // ═════════════════════════════════════════════════════════════
356
+ // Helpers
357
+ // ═════════════════════════════════════════════════════════════
358
+ determineAction(reason) {
359
+ switch (reason) {
360
+ case "CONTEXT_MISMATCH": return "context_filter_added";
361
+ case "NAMESPACE_LEAK": return "namespace_restricted";
362
+ case "RULE_TOO_BROAD":
363
+ case "INCOMPLETE_RULE": return "rule_adjusted";
364
+ case "DOMAIN_IRRELEVANT":
365
+ case "LEGACY_COMPAT": return "exception_added";
366
+ default: return "deferred";
367
+ }
368
+ }
369
+ // ═════════════════════════════════════════════════════════════
370
+ // Persistence
371
+ // ═════════════════════════════════════════════════════════════
372
+ load() {
373
+ const dir = path.resolve(process.cwd(), VI_DIR);
374
+ if (!fs.existsSync(dir))
375
+ return;
376
+ try {
377
+ const confFile = path.join(dir, "rule-confidences.json");
378
+ if (fs.existsSync(confFile)) {
379
+ const data = JSON.parse(fs.readFileSync(confFile, "utf-8"));
380
+ for (const [key, val] of Object.entries(data)) {
381
+ this.ruleConfidences.set(key, val);
382
+ }
383
+ }
384
+ const fpFile = path.join(dir, "fp-records.json");
385
+ if (fs.existsSync(fpFile)) {
386
+ this.fpRecords = JSON.parse(fs.readFileSync(fpFile, "utf-8"));
387
+ }
388
+ const filterFile = path.join(dir, "context-filters.json");
389
+ if (fs.existsSync(filterFile)) {
390
+ const data = JSON.parse(fs.readFileSync(filterFile, "utf-8"));
391
+ for (const [key, val] of Object.entries(data)) {
392
+ this.contextFilters.set(key, new Set(val));
393
+ }
394
+ }
395
+ }
396
+ catch { /* start fresh */ }
397
+ }
398
+ save() {
399
+ const dir = path.resolve(process.cwd(), VI_DIR);
400
+ if (!fs.existsSync(dir))
401
+ fs.mkdirSync(dir, { recursive: true });
402
+ const confObj = {};
403
+ for (const [key, val] of this.ruleConfidences) {
404
+ confObj[key] = val;
405
+ }
406
+ fs.writeFileSync(path.join(dir, "rule-confidences.json"), JSON.stringify(confObj, null, 2));
407
+ // Only save last 1000 FP records to avoid file bloat
408
+ const recent = this.fpRecords.slice(-1000);
409
+ fs.writeFileSync(path.join(dir, "fp-records.json"), JSON.stringify(recent, null, 2));
410
+ const filterObj = {};
411
+ for (const [key, val] of this.contextFilters) {
412
+ filterObj[key] = [...val];
413
+ }
414
+ fs.writeFileSync(path.join(dir, "context-filters.json"), JSON.stringify(filterObj, null, 2));
415
+ }
416
+ }
417
+ exports.VerificationIntelligence = VerificationIntelligence;
418
+ // ═══════════════════════════════════════════════════════════════
419
+ // Singleton
420
+ // ═══════════════════════════════════════════════════════════════
421
+ let _vi = null;
422
+ function getVerificationIntelligence() {
423
+ if (!_vi)
424
+ _vi = new VerificationIntelligence();
425
+ return _vi;
426
+ }
427
+ // ═══════════════════════════════════════════════════════════════
428
+ // Report Formatter
429
+ // ═══════════════════════════════════════════════════════════════
430
+ function formatVILearningReport() {
431
+ const vi = getVerificationIntelligence();
432
+ const report = vi.getFPLearningReport();
433
+ const suppressed = vi.getSuppressedRules();
434
+ const lines = [];
435
+ lines.push("");
436
+ lines.push("╔══════════════════════════════════════════════════════════════╗");
437
+ lines.push("║ Verification Intelligence — Learning Report ║");
438
+ lines.push("╠══════════════════════════════════════════════════════════════╣");
439
+ lines.push(`║ FP Records: ${String(report.totalFPs).padStart(5)} | Suppressed Rules: ${String(report.suppressedRules).padStart(3)} | Avg Confidence: ${(report.avgConfidence * 100).toFixed(0)}% ║`);
440
+ lines.push("╚══════════════════════════════════════════════════════════════╝");
441
+ lines.push("");
442
+ if (report.totalFPs === 0) {
443
+ lines.push(" No false positives recorded yet.");
444
+ lines.push(" The engine will learn as verification runs across repos.");
445
+ lines.push("");
446
+ return lines.join("\n");
447
+ }
448
+ // FP by reason
449
+ lines.push("── FP by Reason ──");
450
+ for (const [reason, count] of Object.entries(report.byReason).sort((a, b) => b[1] - a[1])) {
451
+ const label = exports.FP_REASON_LABELS[reason]?.label || reason;
452
+ const bar = "█".repeat(Math.min(30, count));
453
+ lines.push(` ${label.padEnd(25)} ${String(count).padStart(4)} ${bar}`);
454
+ }
455
+ lines.push("");
456
+ // Top noisy rules
457
+ if (report.topFPRules.length > 0) {
458
+ lines.push("── Top Noisy Rules ──");
459
+ for (const r of report.topFPRules.slice(0, 5)) {
460
+ const conf = (r.confidence * 100).toFixed(0);
461
+ const status = r.confidence < 0.3 ? "🔇 SUPPRESSED" : r.confidence < 0.6 ? "⚠️ LOW" : "✓ OK";
462
+ lines.push(` ${r.rule.padEnd(35)} ${String(r.fps).padStart(3)} FPs conf=${conf}% ${status}`);
463
+ }
464
+ lines.push("");
465
+ }
466
+ // Suppressed rules
467
+ if (suppressed.length > 0) {
468
+ lines.push("── Suppressed Rules ──");
469
+ for (const rc of suppressed) {
470
+ lines.push(` 🔇 ${rc.protocol}:${rc.ruleName} — ${rc.falsePositives} FPs, confidence ${(rc.currentConfidence * 100).toFixed(0)}%`);
471
+ }
472
+ lines.push("");
473
+ }
474
+ return lines.join("\n");
475
+ }