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,533 @@
1
+ "use strict";
2
+ /**
3
+ * Progmune V5 — Invariant Calculus
4
+ * =================================
5
+ * 将不变量从 JSON 记录提升为可证明、可组合、可验证的数学对象。
6
+ *
7
+ * 核心理念:
8
+ * V4 回答: "能推导出新不变量吗?" → Closure 实现了传递闭包
9
+ * V5 回答: "能证明每个不变量吗?" → 每个不变量携带自己的 Proof Object
10
+ *
11
+ * 新增能力:
12
+ * 1. Proof Objects — 每个不变量附带推导链
13
+ * 2. Minimal Basis — 自动消除冗余规则,只保留生成基
14
+ * 3. Contradiction Detection — 检测逻辑冲突
15
+ * 4. Dependency Graph — 不变量之间的依赖 DAG
16
+ * 5. Counterexample Generation — 验证失败时构造反例
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.runCalculus = runCalculus;
53
+ const fs = __importStar(require("fs"));
54
+ const path = __importStar(require("path"));
55
+ // ══════════════════════════════════════════════
56
+ // L0: LOGIC TYPE CLASSIFICATION
57
+ // ══════════════════════════════════════════════
58
+ /**
59
+ * Classify an invariant into its logical type.
60
+ *
61
+ * REQUIRES: "A ⇒ B" — A requires B to have been satisfied before entering A.
62
+ * e.g. "production ⇒ paid" = must have paid before production.
63
+ * Transitive: if A⇒B and B⇒C, then A⇒C.
64
+ *
65
+ * FORBIDS: "¬(A → B)" — cannot directly transition from A to B.
66
+ * e.g. "¬(shipped → pending)" = cannot go backwards.
67
+ * NOT transitive. A forbidding B and B forbidding C does NOT
68
+ * imply A forbids C. These are local edge constraints.
69
+ *
70
+ * TERMINAL: "A ⇒ ¬∃ next" — once in A, no further transitions exist.
71
+ * e.g. "completed is terminal" = cannot leave completed state.
72
+ *
73
+ * UNIQUE: "|payments| ≤ 1" — cardinality constraint.
74
+ *
75
+ * INITIAL: "∀ entity: initial_state = A" — only one valid starting state.
76
+ */
77
+ function classifyLogicType(inv) {
78
+ const pred = (inv.rawPredicate || inv.predicate || "").toLowerCase();
79
+ const desc = (inv.description || "").toLowerCase();
80
+ if (pred.includes("¬∃ next") || pred.includes("terminal") || desc.includes("终态")) {
81
+ return "TERMINAL";
82
+ }
83
+ if (pred.includes("¬(") && pred.includes("→")) {
84
+ return "FORBIDS";
85
+ }
86
+ if (pred.includes("≤ 1") || pred.includes("unique") || pred.includes("at most one") || desc.includes("唯一")) {
87
+ return "UNIQUE";
88
+ }
89
+ if (pred.includes("initial_state") || desc.includes("起始") || desc.includes("初始")) {
90
+ return "INITIAL";
91
+ }
92
+ // Default: "A ⇒ B" with actual different atoms = prerequisite
93
+ return "REQUIRES";
94
+ }
95
+ // ══════════════════════════════════════════════
96
+ // L1: PROOF OBJECT CONSTRUCTION
97
+ // ══════════════════════════════════════════════
98
+ /**
99
+ * Build a proof object for each invariant.
100
+ *
101
+ * A proof is a derivation chain from premises to conclusion.
102
+ * - Axioms (premises): invariants that were mined directly from code/state machines.
103
+ * They have no derivation — they are assumed true based on evidence.
104
+ * - Derived invariants: those obtained by applying inference rules to axioms.
105
+ * Their proof references the premises and the rule used.
106
+ */
107
+ function buildProofObjects(invariants, closures) {
108
+ const certified = [];
109
+ const idCounter = { value: 10000 };
110
+ // ── Step 1: Mark all mined invariants as axioms ──
111
+ for (const inv of invariants) {
112
+ const logicType = classifyLogicType(inv);
113
+ const proof = {
114
+ invariantId: inv.id,
115
+ statement: inv.rawPredicate || inv.predicate,
116
+ steps: [{
117
+ rule: "premise",
118
+ from: [],
119
+ to: inv.id,
120
+ description: `Mined from ${inv.source || "code analysis"} [type: ${logicType}]`,
121
+ }],
122
+ premises: [inv.id],
123
+ isAxiom: true,
124
+ confidence: inv.confidence || 50,
125
+ logicType,
126
+ };
127
+ certified.push({
128
+ id: inv.id,
129
+ description: inv.description,
130
+ predicate: inv.rawPredicate || inv.predicate,
131
+ domain: inv.domain || "unknown",
132
+ confidence: inv.confidence || 50,
133
+ proof,
134
+ dependsOn: [],
135
+ dependedOnBy: [],
136
+ logicType,
137
+ });
138
+ }
139
+ // ── Step 2: Mark closure-derived invariants with their derivation chain ──
140
+ for (const closureInv of closures) {
141
+ const sourceDesc = closureInv.source || "";
142
+ // Parse premises from source string like "closure: pending⇒production + production⇒paid"
143
+ const premiseMatch = sourceDesc.match(/closure:\s*(\w+⇒\w+)\s*\+\s*(\w+⇒\w+)/);
144
+ // Closure-derived invariants inherit REQUIRES type (transitivity only applies to prerequisites)
145
+ const proof = {
146
+ invariantId: closureInv.id,
147
+ statement: closureInv.rawPredicate || closureInv.predicate || "",
148
+ steps: [{
149
+ rule: "transitivity",
150
+ from: premiseMatch
151
+ ? [findInvariantId(certified, premiseMatch[1]), findInvariantId(certified, premiseMatch[2])].filter(Boolean)
152
+ : [],
153
+ to: closureInv.id,
154
+ description: closureInv.description || `Derived via transitive closure`,
155
+ }],
156
+ premises: premiseMatch
157
+ ? [findInvariantId(certified, premiseMatch[1]), findInvariantId(certified, premiseMatch[2])].filter(Boolean)
158
+ : [],
159
+ isAxiom: false,
160
+ confidence: closureInv.confidence || 50,
161
+ logicType: "REQUIRES", // Closure only derives REQUIRES invariants
162
+ };
163
+ const certInv = {
164
+ id: closureInv.id,
165
+ description: closureInv.description || "",
166
+ predicate: closureInv.rawPredicate || closureInv.predicate || "",
167
+ domain: closureInv.domain || "unknown",
168
+ confidence: closureInv.confidence || 50,
169
+ proof,
170
+ dependsOn: proof.premises,
171
+ dependedOnBy: [],
172
+ logicType: "REQUIRES",
173
+ };
174
+ certified.push(certInv);
175
+ // Update dependedOnBy on premises
176
+ for (const premId of proof.premises) {
177
+ const prem = certified.find(c => c.id === premId);
178
+ if (prem && !prem.dependedOnBy.includes(certInv.id)) {
179
+ prem.dependedOnBy.push(certInv.id);
180
+ }
181
+ }
182
+ }
183
+ return certified;
184
+ }
185
+ /** Find an invariant ID by its predicate string */
186
+ function findInvariantId(invariants, predicate) {
187
+ const norm = (s) => s.replace(/\s+/g, "").toLowerCase();
188
+ const target = norm(predicate);
189
+ for (const inv of invariants) {
190
+ if (norm(inv.predicate) === target || norm(inv.predicate).includes(target)) {
191
+ return inv.id;
192
+ }
193
+ }
194
+ return null;
195
+ }
196
+ // ══════════════════════════════════════════════
197
+ // L2: DEPENDENCY GRAPH
198
+ // ══════════════════════════════════════════════
199
+ /**
200
+ * Build the dependency DAG from certified invariants.
201
+ * If B depends on A, and A changes, B must be re-verified.
202
+ */
203
+ function buildDependencyGraph(certified) {
204
+ return certified.map(inv => ({
205
+ id: inv.id,
206
+ dependsOn: inv.dependsOn,
207
+ dependedOnBy: inv.dependedOnBy,
208
+ }));
209
+ }
210
+ // ══════════════════════════════════════════════
211
+ // L3: CONSISTENCY CHECK (Contradiction Detection)
212
+ // ══════════════════════════════════════════════
213
+ /**
214
+ * Detect contradictions in the invariant set.
215
+ * A contradiction exists when we have both A⇒B and A⇒¬B
216
+ * (or equivalently, A⇒B and an invalid transition ¬(A→B)).
217
+ *
218
+ * Also detects: A⇒B and B⇒A simultaneously (cycle in strict partial order)
219
+ */
220
+ function checkConsistency(certified) {
221
+ const contradictions = [];
222
+ // Separate by logic type — different types don't conflict
223
+ const requires = new Map(); // REQUIRES: A ⇒ B
224
+ const forbids = new Map(); // FORBIDS: ¬(A → B)
225
+ const terminals = new Set(); // TERMINAL: A has no next state
226
+ for (const inv of certified) {
227
+ const pred = inv.predicate;
228
+ if (inv.logicType === "REQUIRES") {
229
+ const impliesMatch = pred.match(/(\w+)\s*⇒\s*(\w+)/);
230
+ if (impliesMatch) {
231
+ const a = impliesMatch[1].toLowerCase();
232
+ const b = impliesMatch[2].toLowerCase();
233
+ if (a !== b) {
234
+ if (!requires.has(a))
235
+ requires.set(a, []);
236
+ if (!requires.get(a).includes(b))
237
+ requires.get(a).push(b);
238
+ }
239
+ }
240
+ }
241
+ if (inv.logicType === "FORBIDS") {
242
+ const notImpliesMatch = pred.match(/¬\((\w+)\s*→\s*(\w+)\)/);
243
+ if (notImpliesMatch) {
244
+ const a = notImpliesMatch[1].toLowerCase();
245
+ const b = notImpliesMatch[2].toLowerCase();
246
+ if (!forbids.has(a))
247
+ forbids.set(a, []);
248
+ if (!forbids.get(a).includes(b))
249
+ forbids.get(a).push(b);
250
+ }
251
+ }
252
+ if (inv.logicType === "TERMINAL") {
253
+ const termMatch = pred.match(/(\w+)/);
254
+ if (termMatch)
255
+ terminals.add(termMatch[1].toLowerCase());
256
+ }
257
+ }
258
+ // ── Only check WITHIN each type ──
259
+ // REQUIRES internal: A⇒B and B⇒A (cycle in strict partial order)
260
+ for (const [a, deps] of requires) {
261
+ for (const b of deps) {
262
+ const bDeps = requires.get(b) || [];
263
+ if (bDeps.includes(a) && a < b) { // a < b to avoid double-counting
264
+ contradictions.push({
265
+ a: `${a}⇒${b}`,
266
+ b: `${b}⇒${a}`,
267
+ description: `REQUIRES 循环: ${a}⇒${b} 且 ${b}⇒${a} —— 违反严格偏序`,
268
+ });
269
+ }
270
+ }
271
+ }
272
+ // REQUIRES + TERMINAL conflict: A is terminal but also requires B (can't transition to B if terminal)
273
+ for (const a of terminals) {
274
+ const deps = requires.get(a) || [];
275
+ if (deps.length > 0) {
276
+ // Being terminal AND requiring something is suspicious
277
+ // (terminal means no outgoing transitions, but REQUIRES implies a dependency chain)
278
+ // This is NOT necessarily a contradiction — terminal just means no FURTHER states
279
+ // We'll skip this check for now
280
+ }
281
+ }
282
+ // FORBIDS internal: A forbids B and also forbids B twice (redundant, not contradiction)
283
+ // NOTE: REQUIRES vs FORBIDS are NOT contradictions.
284
+ // "shipped ⇒ production" (REQUIRES: must have passed through production)
285
+ // and "¬(shipped → production)" (FORBIDS: cannot transition back to production)
286
+ // are CONSISTENT. One is about history, the other about future transitions.
287
+ return {
288
+ isConsistent: contradictions.length === 0,
289
+ contradictions,
290
+ minimalBasis: { generators: [], consequences: [], removedRedundant: [] },
291
+ };
292
+ }
293
+ // ══════════════════════════════════════════════
294
+ // L4: MINIMAL BASIS (Redundancy Elimination)
295
+ // ══════════════════════════════════════════════
296
+ /**
297
+ * Compute the minimal generating basis.
298
+ *
299
+ * An invariant is REDUNDANT if it can be derived from other invariants
300
+ * via transitivity. Example:
301
+ * A⇒B, B⇒C, A⇒C → A⇒C is redundant (derivable from the first two)
302
+ *
303
+ * The minimal basis contains only the axioms that cannot be derived.
304
+ * All consequences are derivable from the basis.
305
+ */
306
+ function computeMinimalBasis(certified) {
307
+ const axioms = certified.filter(inv => inv.proof.isAxiom);
308
+ const derived = certified.filter(inv => !inv.proof.isAxiom);
309
+ // For now: all axioms are generators, all derived are consequences.
310
+ // A more sophisticated version would find transitive reducibility among axioms.
311
+ // e.g., if A⇒B and B⇒C are both axioms, we could remove A⇒C from generators
312
+ // (but we only generate A⇒C via closure, so it's already in derived).
313
+ const redundant = [];
314
+ // Check: are any axioms actually derivable from other axioms?
315
+ // If axiom A⇒C is also in the transitive closure of other axioms, it's redundant.
316
+ for (let i = 0; i < axioms.length; i++) {
317
+ for (let j = 0; j < axioms.length; j++) {
318
+ if (i === j)
319
+ continue;
320
+ // Check if axioms[i] is transitively implied by axioms[j] + some chain
321
+ // This is a simplified check: same predicate means redundant
322
+ if (axioms[i].predicate === axioms[j].predicate && i > j) {
323
+ redundant.push(axioms[i].id);
324
+ }
325
+ }
326
+ }
327
+ const generators = axioms.filter(a => !redundant.includes(a.id));
328
+ return {
329
+ generators,
330
+ consequences: derived,
331
+ removedRedundant: redundant,
332
+ };
333
+ }
334
+ // ══════════════════════════════════════════════
335
+ // L5: COUNTEREXAMPLE GENERATION
336
+ // ══════════════════════════════════════════════
337
+ /**
338
+ * Generate counterexamples for violated invariants.
339
+ *
340
+ * Given a state machine and an invariant A⇒B:
341
+ * - Find a path where A is true but B has not been satisfied yet.
342
+ * - The shortest such path is the counterexample.
343
+ */
344
+ function generateCounterexamples(certified, stateMachines) {
345
+ const counterexamples = [];
346
+ for (const machine of stateMachines) {
347
+ const states = machine.states || [];
348
+ const validTransitions = new Set(machine.validTransitions || []);
349
+ const invalidTransitions = machine.invalidTransitions || [];
350
+ // For each safety invariant (¬(A→B)), construct the violating path
351
+ for (const invId of invalidTransitions) {
352
+ const [from, to] = invId.split("→");
353
+ if (!from || !to)
354
+ continue;
355
+ // Find the corresponding certified invariant
356
+ const certInv = certified.find(c => c.predicate.includes(from) && c.predicate.includes(to) && c.predicate.includes("¬"));
357
+ if (certInv) {
358
+ // Construct the shortest violating path
359
+ const path = [from, to];
360
+ counterexamples.push({
361
+ invariantId: certInv.id,
362
+ invariantStatement: certInv.predicate,
363
+ path,
364
+ atStep: 1,
365
+ explanation: `状态机允许从 ${from} 直接跳转到 ${to}。违反了不变量: ${certInv.predicate}`,
366
+ });
367
+ }
368
+ }
369
+ // For prerequisite invariants (A⇒B), check if there's a path from initial to A that skips B
370
+ for (const certInv of certified) {
371
+ const impliesMatch = certInv.predicate.match(/(\w+)\s*⇒\s*(\w+)/);
372
+ if (!impliesMatch)
373
+ continue;
374
+ const a = impliesMatch[1].toLowerCase();
375
+ const b = impliesMatch[2].toLowerCase();
376
+ // Check: does any path from initial state reach 'a' without passing through 'b'?
377
+ const initialState = machine.initialState?.toLowerCase();
378
+ if (initialState && states.map((s) => s.toLowerCase()).includes(a)) {
379
+ // If there's a direct transition from initial to 'a' that skips 'b', that's a violation
380
+ const directPath = `${initialState}→${a}`;
381
+ if (!validTransitions.has(directPath) && initialState !== a) {
382
+ // This means the state machine already blocks this path — invariant is satisfied
383
+ // If the path IS valid, it's a violation
384
+ }
385
+ }
386
+ // Simpler check: if 'a' can be reached without 'b' in the state list before it
387
+ const aIdx = states.findIndex((s) => s.toLowerCase() === a);
388
+ const bIdx = states.findIndex((s) => s.toLowerCase() === b);
389
+ if (aIdx >= 0 && bIdx >= 0 && aIdx < bIdx) {
390
+ // 'a' appears before 'b' in state ordering — potential violation
391
+ // This means the state can be entered without satisfying the prerequisite
392
+ counterexamples.push({
393
+ invariantId: certInv.id,
394
+ invariantStatement: certInv.predicate,
395
+ path: [states[aIdx], states[bIdx]],
396
+ atStep: aIdx,
397
+ explanation: `在状态序列中,${states[aIdx]} 出现在 ${states[bIdx]} 之前。可能违反: ${certInv.predicate}`,
398
+ });
399
+ break; // One counterexample per invariant is sufficient
400
+ }
401
+ }
402
+ }
403
+ return counterexamples;
404
+ }
405
+ function runCalculus(input) {
406
+ console.log("🔬 Progmune Invariant Calculus — V5");
407
+ // Collect all invariants and closures
408
+ const allInvariants = [];
409
+ for (const proto of input.protocols || []) {
410
+ for (const inv of proto.invariants || []) {
411
+ allInvariants.push(inv);
412
+ }
413
+ }
414
+ const allClosures = [];
415
+ for (const proto of input.protocols || []) {
416
+ for (const inv of proto.closure || []) {
417
+ allClosures.push(inv);
418
+ }
419
+ }
420
+ console.log(` Input: ${allInvariants.length} invariants, ${allClosures.length} closure-derived`);
421
+ // ── L1: Proof Objects ──
422
+ console.log("\nL1 · Proof Object Construction...");
423
+ const certified = buildProofObjects(allInvariants, allClosures);
424
+ const axioms = certified.filter(c => c.proof.isAxiom);
425
+ const derived = certified.filter(c => !c.proof.isAxiom);
426
+ const typeCounts = {};
427
+ for (const c of certified) {
428
+ typeCounts[c.logicType] = (typeCounts[c.logicType] || 0) + 1;
429
+ }
430
+ console.log(` ${certified.length} certified: ${axioms.length} axioms, ${derived.length} derived`);
431
+ console.log(` By type: REQUIRES=${typeCounts["REQUIRES"] || 0} FORBIDS=${typeCounts["FORBIDS"] || 0} TERMINAL=${typeCounts["TERMINAL"] || 0} UNIQUE=${typeCounts["UNIQUE"] || 0} INITIAL=${typeCounts["INITIAL"] || 0}`);
432
+ // Show derivation chains
433
+ for (const d of derived.slice(0, 3)) {
434
+ const premises = d.proof.premises.join(", ");
435
+ console.log(` ⊢ ${d.predicate} [from: ${premises}]`);
436
+ }
437
+ // ── L2: Dependency Graph ──
438
+ console.log("\nL2 · Dependency Graph...");
439
+ const depGraph = buildDependencyGraph(certified);
440
+ const withDeps = depGraph.filter(d => d.dependedOnBy.length > 0);
441
+ console.log(` ${withDeps.length} invariants with dependents`);
442
+ for (const d of withDeps.slice(0, 3)) {
443
+ console.log(` ${d.id} is depended on by: ${d.dependedOnBy.join(", ")}`);
444
+ }
445
+ // ── L3: Consistency Check ──
446
+ console.log("\nL3 · Consistency Check...");
447
+ const consistency = checkConsistency(certified);
448
+ if (consistency.isConsistent) {
449
+ console.log(" ✅ No contradictions found");
450
+ }
451
+ else {
452
+ console.log(` ❌ ${consistency.contradictions.length} contradictions found`);
453
+ for (const c of consistency.contradictions.slice(0, 3)) {
454
+ console.log(` ${c.description}`);
455
+ }
456
+ }
457
+ // ── L4: Minimal Basis ──
458
+ console.log("\nL4 · Minimal Basis...");
459
+ const minimalBasis = computeMinimalBasis(certified);
460
+ // Update consistency with the computed basis
461
+ consistency.minimalBasis = minimalBasis;
462
+ console.log(` Generators: ${minimalBasis.generators.length}`);
463
+ console.log(` Consequences: ${minimalBasis.consequences.length}`);
464
+ console.log(` Redundant: ${minimalBasis.removedRedundant.length}`);
465
+ if (minimalBasis.removedRedundant.length > 0) {
466
+ console.log(` Removed: ${minimalBasis.removedRedundant.join(", ")}`);
467
+ }
468
+ // ── L5: Counterexample Generation ──
469
+ console.log(`\nL5 · Counterexample Generation (FORBIDS type only)...`);
470
+ // Only FORBIDS invariants can have counterexamples (invalid transitions)
471
+ const forbidsInvariants = certified.filter(c => c.logicType === "FORBIDS");
472
+ const counterexamples = generateCounterexamples(forbidsInvariants, input.stateMachines || []);
473
+ console.log(` ${counterexamples.length} counterexamples`);
474
+ for (const ce of counterexamples.slice(0, 3)) {
475
+ console.log(` ❌ ${ce.invariantStatement}`);
476
+ console.log(` Path: ${ce.path.join(" → ")}`);
477
+ console.log(` ${ce.explanation}`);
478
+ }
479
+ const report = {
480
+ timestamp: new Date().toISOString(),
481
+ certifiedInvariants: certified,
482
+ dependencyGraph: depGraph,
483
+ minimalBasis,
484
+ consistency,
485
+ counterexamples,
486
+ summary: {
487
+ totalInvariants: certified.length,
488
+ axioms: axioms.length,
489
+ derived: derived.length,
490
+ redundant: minimalBasis.removedRedundant.length,
491
+ contradictions: consistency.contradictions.length,
492
+ counterexamples: counterexamples.length,
493
+ },
494
+ };
495
+ return report;
496
+ }
497
+ // ══════════════════════════════════════════════
498
+ // CLI
499
+ // ══════════════════════════════════════════════
500
+ if (require.main === module) {
501
+ const targetProject = process.argv[2];
502
+ if (!targetProject) {
503
+ console.error("Usage: npx ts-node src/invariant-calculus.ts <project-path>");
504
+ process.exit(1);
505
+ }
506
+ const protoPath = path.join(targetProject, ".progmune_protocols.json");
507
+ const algebraPath = path.join(targetProject, ".progmune_algebra.json");
508
+ const statePath = path.join(targetProject, ".progmune_state_machines.json");
509
+ if (!fs.existsSync(protoPath)) {
510
+ console.error("Run V3.4 first: npx ts-node src/protocol-miner.ts");
511
+ process.exit(1);
512
+ }
513
+ const protocols = JSON.parse(fs.readFileSync(protoPath, "utf-8"));
514
+ const algebra = fs.existsSync(algebraPath) ? JSON.parse(fs.readFileSync(algebraPath, "utf-8")) : { protocols: [] };
515
+ const states = fs.existsSync(statePath) ? JSON.parse(fs.readFileSync(statePath, "utf-8")) : { machines: [] };
516
+ const input = {
517
+ protocols: protocols.protocols || [],
518
+ closures: algebra.protocols?.flatMap((p) => p.closure || []) || [],
519
+ stateMachines: states.machines || [],
520
+ };
521
+ const report = runCalculus(input);
522
+ const outputPath = path.join(targetProject, ".progmune_calculus.json");
523
+ fs.writeFileSync(outputPath, JSON.stringify(report, null, 2));
524
+ console.log(`\n✅ Calculus report saved to: ${outputPath}`);
525
+ console.log("\n═══ Invariant Calculus Summary ═══");
526
+ console.log(` Total: ${report.summary.totalInvariants}`);
527
+ console.log(` Axioms: ${report.summary.axioms}`);
528
+ console.log(` Derived: ${report.summary.derived}`);
529
+ console.log(` Redundant: ${report.summary.redundant}`);
530
+ console.log(` Contradictions:${report.summary.contradictions}`);
531
+ console.log(` Counterexamples:${report.summary.counterexamples}`);
532
+ console.log();
533
+ }
package/dist/ir-utils.js CHANGED
@@ -1,7 +1,57 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loadIR = loadIR;
3
37
  exports.countExported = countExported;
4
38
  exports.mergeResults = mergeResults;
39
+ exports.getExportedDeclarations = getExportedDeclarations;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ /**
43
+ * Load IR (Intermediate Representation) from disk.
44
+ * Centralised loader — used by validator, planner, and search modules.
45
+ * Returns the flat function array regardless of whether the on-disk format
46
+ * is a bare array or an object with a `functions` key.
47
+ */
48
+ function loadIR(filePath) {
49
+ const irPath = filePath || path.resolve(__dirname, "../ir.json");
50
+ if (!fs.existsSync(irPath))
51
+ return [];
52
+ const raw = JSON.parse(fs.readFileSync(irPath, "utf-8"));
53
+ return Array.isArray(raw) ? raw : (raw.functions || []);
54
+ }
5
55
  /** Count exported functions in an IR function list.
6
56
  * @requires IR_FUNCTIONS @produces EXPORT_COUNT
7
57
  * @tags ir, count, export
@@ -16,3 +66,23 @@ function countExported(ir) {
16
66
  function mergeResults(a, b) {
17
67
  return { first: a, second: b };
18
68
  }
69
+ /**
70
+ * Get all exported function declarations with capability metadata.
71
+ * @requires IR_FUNCTIONS @produces EXPORTED_DECLARATIONS
72
+ * @purpose Return exported functions with their purpose, requires, and produces
73
+ * @tags ir, export, catalog
74
+ * @useWhen building capability catalogs, listing available functions
75
+ */
76
+ function getExportedDeclarations() {
77
+ const allFuncs = loadIR();
78
+ return allFuncs
79
+ .filter((f) => f.exported)
80
+ .map((f) => ({
81
+ name: f.name,
82
+ purpose: f.purpose || "",
83
+ requires: f.requires || [],
84
+ produces: f.produces || [],
85
+ tags: f.tags || [],
86
+ file: f.file,
87
+ }));
88
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Unit tests for ir-utils.ts — IR helper functions.
5
+ */
6
+ const vitest_1 = require("vitest");
7
+ const ir_utils_1 = require("./ir-utils");
8
+ (0, vitest_1.describe)("countExported", () => {
9
+ (0, vitest_1.it)("returns 0 for empty array", () => {
10
+ (0, vitest_1.expect)((0, ir_utils_1.countExported)([])).toBe(0);
11
+ });
12
+ (0, vitest_1.it)("counts only exported functions", () => {
13
+ const ir = [
14
+ { name: "a", exported: true },
15
+ { name: "b", exported: false },
16
+ { name: "c", exported: true },
17
+ { name: "d" }, // no exported field → falsy
18
+ ];
19
+ (0, vitest_1.expect)((0, ir_utils_1.countExported)(ir)).toBe(2);
20
+ });
21
+ (0, vitest_1.it)("returns 0 if all are internal", () => {
22
+ (0, vitest_1.expect)((0, ir_utils_1.countExported)([
23
+ { name: "x", exported: false },
24
+ { name: "y", exported: false },
25
+ ])).toBe(0);
26
+ });
27
+ });
28
+ (0, vitest_1.describe)("mergeResults", () => {
29
+ (0, vitest_1.it)("returns object with first and second", () => {
30
+ const r = (0, ir_utils_1.mergeResults)({ a: 1 }, { b: 2 });
31
+ (0, vitest_1.expect)(r.first).toEqual({ a: 1 });
32
+ (0, vitest_1.expect)(r.second).toEqual({ b: 2 });
33
+ });
34
+ (0, vitest_1.it)("works with primitives", () => {
35
+ const r = (0, ir_utils_1.mergeResults)(42, "hello");
36
+ (0, vitest_1.expect)(r.first).toBe(42);
37
+ (0, vitest_1.expect)(r.second).toBe("hello");
38
+ });
39
+ });
40
+ (0, vitest_1.describe)("loadIR", () => {
41
+ (0, vitest_1.it)("returns empty array for non-existent file", () => {
42
+ const result = (0, ir_utils_1.loadIR)("/nonexistent/path/ir.json");
43
+ (0, vitest_1.expect)(result).toEqual([]);
44
+ });
45
+ (0, vitest_1.it)("returns empty array when no path matches", () => {
46
+ // loadIR without a valid ir.json returns [] (file doesn't exist in test)
47
+ const result = (0, ir_utils_1.loadIR)("/tmp/no-ir-here.json");
48
+ (0, vitest_1.expect)(Array.isArray(result)).toBe(true);
49
+ });
50
+ });