progmune-runtime 2.1.5 → 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 +326 -59
  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,386 @@
1
+ "use strict";
2
+ /**
3
+ * Progmune V3.3 — State Mining Engine
4
+ * ====================================
5
+ * 从代码中恢复业务状态机,而非函数调用序列。
6
+ *
7
+ * 核心理念:
8
+ * Policy 真正约束的是 State Transition(状态变化),不是 Function Order(函数顺序)。
9
+ * "Created → Paid → Shipped" 合法,"Created → Shipped" 非法。
10
+ * 这不是函数顺序问题,是状态机问题。
11
+ *
12
+ * 三层挖掘:
13
+ * L1: State Discovery — 从枚举、常量、类型定义中提取状态值
14
+ * L2: State Transition Recovery — 从行为图中恢复状态转换
15
+ * L3: State Machine Assembly — 将状态和转换组装成完整状态机
16
+ *
17
+ * 输入: Behavior Graph (V3.2) + 项目路径
18
+ * 输出: State Machines — 每个业务实体的完整生命周期
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.mineStates = mineStates;
55
+ const ts_morph_1 = require("ts-morph");
56
+ const path = __importStar(require("path"));
57
+ const fs = __importStar(require("fs"));
58
+ // ══════════════════════════════════════════════
59
+ // L1: STATE DISCOVERY
60
+ // ══════════════════════════════════════════════
61
+ /**
62
+ * Extract all state-like definitions from the codebase.
63
+ * States come from:
64
+ * 1. TypeScript enums with Status/State/Stage/Type names
65
+ * 2. Drizzle mysqlEnum column definitions
66
+ * 3. String literal union types (type Status = "active" | "inactive")
67
+ */
68
+ function discoverStates(projectPath) {
69
+ const states = [];
70
+ // ── Direct regex extraction from Drizzle/Prisma schema files ──
71
+ // ts-morph can fail parsing runtime imports. Regex is more robust.
72
+ for (const schemaDir of ["drizzle", "prisma", "db", "database"]) {
73
+ const schemaPath = path.join(projectPath, schemaDir);
74
+ if (!fs.existsSync(schemaPath))
75
+ continue;
76
+ for (const entry of fs.readdirSync(schemaPath, { recursive: true })) {
77
+ const fullPath = path.join(schemaPath, entry);
78
+ if (!fullPath.endsWith(".ts"))
79
+ continue;
80
+ const content = fs.readFileSync(fullPath, "utf-8");
81
+ const fileName = path.relative(projectPath, fullPath);
82
+ // Extract: mysqlTable("tableName", { ... status: mysqlEnum("status", ["a","b"]) ... })
83
+ // Pattern: mysqlTable("name", { ... colName: mysqlEnum("col", [...values]) ... })
84
+ const tableRegex = /mysqlTable\s*\(\s*["']([^"']+)["']\s*,\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}\s*\)/gs;
85
+ let tableMatch;
86
+ while ((tableMatch = tableRegex.exec(content)) !== null) {
87
+ const tableName = tableMatch[1];
88
+ const columnsBlock = tableMatch[2];
89
+ // Extract: colName: mysqlEnum("col", ["val1", "val2", ...])
90
+ const enumRegex = /(\w+)\s*:\s*mysqlEnum\s*\(\s*["'][^"']*["']\s*,\s*\[([^\]]+)\]/g;
91
+ let enumMatch;
92
+ while ((enumMatch = enumRegex.exec(columnsBlock)) !== null) {
93
+ const colName = enumMatch[1];
94
+ const valuesStr = enumMatch[2];
95
+ const values = valuesStr.match(/["']([^"']+)["']/g)?.map(v => v.replace(/["']/g, "")) || [];
96
+ const isStateColumn = ["status", "state", "type", "stage", "phase", "role", "paymentMethod"].includes(colName);
97
+ if (isStateColumn && values.length >= 2) {
98
+ for (const val of values) {
99
+ states.push({
100
+ name: val,
101
+ entity: tableName,
102
+ source: "enum",
103
+ file: fileName,
104
+ lineNumber: 0,
105
+ });
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ // ── TypeScript enums from server source files ──
113
+ if (fs.existsSync(path.join(projectPath, "server"))) {
114
+ for (const entry of fs.readdirSync(path.join(projectPath, "server"), { recursive: true })) {
115
+ const fullPath = path.join(projectPath, "server", entry);
116
+ if (!fullPath.endsWith(".ts"))
117
+ continue;
118
+ const content = fs.readFileSync(fullPath, "utf-8");
119
+ const fileName = path.relative(projectPath, fullPath);
120
+ // Extract: enum OrderStatus { CREATED = "created", ... }
121
+ const enumRegex = /enum\s+(\w+)\s*\{([^}]+)\}/g;
122
+ let enumMatch;
123
+ while ((enumMatch = enumRegex.exec(content)) !== null) {
124
+ const enumName = enumMatch[1];
125
+ const body = enumMatch[2];
126
+ const isStateEnum = /status|state|stage|type|step|phase/i.test(enumName);
127
+ if (isStateEnum) {
128
+ const entityName = enumName.replace(/status|state|stage|type|step|phase/gi, "").trim() || enumName;
129
+ const members = body.match(/(\w+)\s*(?:=\s*["']?(\w+)["']?)?/g) || [];
130
+ for (const m of members) {
131
+ const name = m.split("=")[0].trim();
132
+ if (name && !name.startsWith("//")) {
133
+ states.push({ name, entity: entityName, source: "enum", file: fileName, lineNumber: 0 });
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ return states;
141
+ }
142
+ // ══════════════════════════════════════════════
143
+ // L2: STATE TRANSITION RECOVERY
144
+ // ══════════════════════════════════════════════
145
+ /**
146
+ * Map function names to state transitions using heuristics.
147
+ * e.g. "updateOrderStatus" + args containing "SHIPPED" → transition to SHIPPED
148
+ * e.g. "createOrder" → transition to CREATED
149
+ * e.g. "payOrder" → transition to PAID
150
+ */
151
+ function recoverTransitions(projectPath, states, behaviorEdges) {
152
+ const project = new ts_morph_1.Project({
153
+ tsConfigFilePath: path.join(projectPath, "tsconfig.json"),
154
+ skipAddingFilesFromTsConfig: false,
155
+ });
156
+ // Also add drizzle/prisma schema files (often excluded from tsconfig includes)
157
+ for (const schemaDir of ["drizzle", "prisma", "db", "database"]) {
158
+ const schemaPath = path.join(projectPath, schemaDir);
159
+ if (fs.existsSync(schemaPath)) {
160
+ project.addSourceFilesAtPaths(path.join(schemaPath, "**/*.ts"));
161
+ }
162
+ }
163
+ const transitions = [];
164
+ const stateNamesByEntity = new Map();
165
+ for (const s of states) {
166
+ if (!stateNamesByEntity.has(s.entity)) {
167
+ stateNamesByEntity.set(s.entity, new Set());
168
+ }
169
+ stateNamesByEntity.get(s.entity).add(s.name);
170
+ }
171
+ for (const sourceFile of project.getSourceFiles()) {
172
+ const filePath = sourceFile.getFilePath().replace(projectPath + "/", "");
173
+ if (filePath.includes("node_modules") || filePath.includes(".test."))
174
+ continue;
175
+ // Walk all function calls
176
+ sourceFile.forEachDescendant((node) => {
177
+ if (!ts_morph_1.Node.isCallExpression(node))
178
+ return;
179
+ const callText = node.getExpression().getText().toLowerCase();
180
+ // Heuristic: if a function call contains a state name + verb,
181
+ // it's likely a state transition
182
+ for (const [entity, stateNames] of stateNamesByEntity) {
183
+ const entityLower = entity.toLowerCase();
184
+ // Check if this call is related to the entity
185
+ if (!callText.includes(entityLower) && !callText.includes("status") && !callText.includes("state")) {
186
+ continue;
187
+ }
188
+ // Look for state values in the function call or its arguments
189
+ for (const stateName of stateNames) {
190
+ const stateLower = stateName.toLowerCase();
191
+ const args = node.getArguments().map(a => a.getText().toLowerCase()).join(" ");
192
+ // Does this call set or transition to this state?
193
+ const isTransition = callText.includes(stateLower) ||
194
+ args.includes(stateLower) ||
195
+ args.includes(`"${stateLower}"`) ||
196
+ args.includes(`'${stateLower}'`);
197
+ if (isTransition) {
198
+ // Determine the transition direction:
199
+ // - "create" or "insert" → entering this state
200
+ // - "update" or "set" → transitioning TO this state (from unknown previous state)
201
+ // - "delete" or "remove" → leaving this state
202
+ const isCreation = callText.includes("create") || callText.includes("insert") || callText.includes("init");
203
+ const isMutation = callText.includes("update") || callText.includes("set") || callText.includes("change");
204
+ // Try to find the previous state from the call context
205
+ // Look at enclosing function for "if (status === X)" patterns
206
+ let fromState = "UNKNOWN";
207
+ const parent = node.getParent();
208
+ if (parent) {
209
+ const parentText = parent.getText().toLowerCase();
210
+ for (const prevState of stateNames) {
211
+ if (parentText.includes(`"${prevState.toLowerCase()}"`) ||
212
+ parentText.includes(`'${prevState.toLowerCase()}'`) ||
213
+ parentText.includes(`=== "${prevState.toLowerCase()}"`)) {
214
+ fromState = prevState;
215
+ break;
216
+ }
217
+ }
218
+ }
219
+ if (isCreation) {
220
+ fromState = "INITIAL";
221
+ }
222
+ const existingTransition = transitions.find(t => t.from === fromState && t.to === stateName && t.entity === entity);
223
+ if (existingTransition) {
224
+ existingTransition.frequency++;
225
+ existingTransition.confidence = Math.min(100, existingTransition.confidence + 5);
226
+ }
227
+ else {
228
+ transitions.push({
229
+ from: fromState,
230
+ to: stateName,
231
+ entity,
232
+ viaFunction: callText,
233
+ frequency: 1,
234
+ topologyConfirmed: isMutation || isCreation,
235
+ confidence: isCreation ? 70 : 40,
236
+ });
237
+ }
238
+ }
239
+ }
240
+ }
241
+ });
242
+ }
243
+ return transitions;
244
+ }
245
+ // ══════════════════════════════════════════════
246
+ // L3: STATE MACHINE ASSEMBLY
247
+ // ══════════════════════════════════════════════
248
+ /**
249
+ * From states and transitions, assemble complete business state machines.
250
+ */
251
+ function assembleMachines(states, transitions) {
252
+ const machines = [];
253
+ const entities = [...new Set(states.map(s => s.entity))];
254
+ for (const entity of entities) {
255
+ const entityStates = states.filter(s => s.entity === entity);
256
+ const entityTransitions = transitions.filter(t => t.entity === entity);
257
+ if (entityStates.length < 2)
258
+ continue;
259
+ // Sort states: INITIAL first, then by transition frequency, then terminal
260
+ const stateNames = [...new Set(entityStates.map(s => s.name))];
261
+ const initialState = entityTransitions.find(t => t.from === "INITIAL")?.to || stateNames[0];
262
+ // Terminal states: states that appear as "to" but not as "from"
263
+ const fromSet = new Set(entityTransitions.map(t => t.from));
264
+ const toSet = new Set(entityTransitions.map(t => t.to));
265
+ const terminalStates = stateNames.filter(s => toSet.has(s) && !fromSet.has(s));
266
+ // Valid transitions: the ones we've observed
267
+ const validTransitions = entityTransitions.map(t => `${t.from}→${t.to}`);
268
+ // Invalid transitions: all other possible pairs (for validation)
269
+ const invalidTransitions = [];
270
+ for (const from of stateNames) {
271
+ for (const to of stateNames) {
272
+ if (from === to)
273
+ continue;
274
+ const key = `${from}→${to}`;
275
+ if (!validTransitions.includes(key)) {
276
+ invalidTransitions.push(key);
277
+ }
278
+ }
279
+ }
280
+ // Coverage: what % of possible transitions have we observed?
281
+ const totalPossible = stateNames.length * (stateNames.length - 1);
282
+ const coverage = totalPossible > 0 ? Math.round((validTransitions.length / totalPossible) * 100) : 0;
283
+ // Overall confidence: average of transition confidences
284
+ const avgConf = entityTransitions.length > 0
285
+ ? Math.round(entityTransitions.reduce((s, t) => s + t.confidence, 0) / entityTransitions.length)
286
+ : 0;
287
+ machines.push({
288
+ entity,
289
+ states: stateNames,
290
+ initialState,
291
+ terminalStates,
292
+ transitions: entityTransitions,
293
+ validTransitions,
294
+ invalidTransitions: invalidTransitions.slice(0, 20), // Don't blow up
295
+ coverage,
296
+ confidence: avgConf,
297
+ });
298
+ }
299
+ // Sort by confidence descending
300
+ machines.sort((a, b) => b.confidence - a.confidence);
301
+ return machines;
302
+ }
303
+ // ══════════════════════════════════════════════
304
+ // MAIN PIPELINE
305
+ // ══════════════════════════════════════════════
306
+ function mineStates(projectPath) {
307
+ console.log("🔬 Progmune State Mining Engine — V3.3");
308
+ console.log(" Project:", projectPath);
309
+ // L1: State Discovery
310
+ console.log("\nL1 · State Discovery...");
311
+ const states = discoverStates(projectPath);
312
+ const entityCount = new Set(states.map(s => s.entity)).size;
313
+ console.log(` ${states.length} states found across ${entityCount} entities`);
314
+ // Group by entity and show
315
+ const byEntity = new Map();
316
+ for (const s of states) {
317
+ if (!byEntity.has(s.entity))
318
+ byEntity.set(s.entity, []);
319
+ byEntity.get(s.entity).push(s);
320
+ }
321
+ for (const [entity, entityStates] of byEntity) {
322
+ const stateNames = entityStates.map(s => s.name);
323
+ console.log(` ${entity}: [${stateNames.join(", ")}]`);
324
+ }
325
+ // L2: State Transition Recovery
326
+ console.log("\nL2 · Transition Recovery...");
327
+ const transitions = recoverTransitions(projectPath, states);
328
+ const confTransitions = transitions.filter(t => t.topologyConfirmed);
329
+ console.log(` ${transitions.length} transitions (${confTransitions.length} topology-confirmed)`);
330
+ // L3: State Machine Assembly
331
+ console.log("\nL3 · State Machine Assembly...");
332
+ const machines = assembleMachines(states, transitions);
333
+ console.log(` ${machines.length} state machines assembled`);
334
+ for (const m of machines) {
335
+ console.log(`\n 🏗️ ${m.entity} State Machine [confidence: ${m.confidence}%]`);
336
+ console.log(` States: ${m.states.join(" → ")}`);
337
+ console.log(` Initial: ${m.initialState} | Terminal: ${m.terminalStates.join(", ") || "(none)"}`);
338
+ console.log(` Coverage: ${m.coverage}% (${m.validTransitions.length} observed / ${m.validTransitions.length + m.invalidTransitions.length} possible)`);
339
+ if (m.transitions.length > 0) {
340
+ console.log(` Transitions:`);
341
+ for (const t of m.transitions.slice(0, 5)) {
342
+ console.log(` ${t.from.padEnd(15)} → ${t.to.padEnd(15)} via ${t.viaFunction} [${t.confidence}%]`);
343
+ }
344
+ }
345
+ // Show violations this machine would catch
346
+ if (m.invalidTransitions.length > 0) {
347
+ console.log(` Would catch these violations:`);
348
+ for (const inv of m.invalidTransitions.slice(0, 3)) {
349
+ console.log(` ❌ ${inv} — would be blocked`);
350
+ }
351
+ }
352
+ }
353
+ const report = {
354
+ projectPath,
355
+ timestamp: new Date().toISOString(),
356
+ states,
357
+ transitions,
358
+ machines,
359
+ summary: {
360
+ statesFound: states.length,
361
+ transitionsFound: transitions.length,
362
+ machinesFound: machines.length,
363
+ completeMachines: machines.filter(m => m.coverage >= 50).length,
364
+ },
365
+ };
366
+ return report;
367
+ }
368
+ // ══════════════════════════════════════════════
369
+ // CLI
370
+ // ══════════════════════════════════════════════
371
+ if (require.main === module) {
372
+ const targetProject = process.argv[2];
373
+ if (!targetProject) {
374
+ console.error("Usage: npx ts-node src/state-miner.ts <project-path>");
375
+ process.exit(1);
376
+ }
377
+ const report = mineStates(targetProject);
378
+ const outputPath = path.join(targetProject, ".progmune_state_machines.json");
379
+ fs.writeFileSync(outputPath, JSON.stringify(report, null, 2));
380
+ console.log(`\n✅ State machines saved to: ${outputPath}`);
381
+ console.log("\n═══ State Mining Summary ═══");
382
+ console.log(` States: ${report.summary.statesFound}`);
383
+ console.log(` Transitions: ${report.summary.transitionsFound}`);
384
+ console.log(` Machines: ${report.summary.machinesFound} (${report.summary.completeMachines} complete)`);
385
+ console.log();
386
+ }
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ /**
3
+ * P6.8: State Name Semantic Inference
4
+ *
5
+ * Maps synthesized generic state names (C0_S1, C1_S2) to
6
+ * hand-written semantic names (FILE_OPEN, DB_CONNECTED, etc.)
7
+ * using action signature matching.
8
+ *
9
+ * Approach:
10
+ * 1. Build a "dictionary" of hand-written states with their
11
+ * action signatures (inbound + outbound function sets).
12
+ * 2. For each synthesized state, compute Jaccard similarity
13
+ * against all hand-written state signatures.
14
+ * 3. Map to the best-matching semantic name.
15
+ * 4. Replace generic names in synthesized rules.
16
+ *
17
+ * Target: bootstrap function overlap 12% → 60%+
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.alignSynthesizedProtocols = alignSynthesizedProtocols;
21
+ exports.runStateAlignment = runStateAlignment;
22
+ exports.printAlignmentReport = printAlignmentReport;
23
+ const protocol_coverage_1 = require("./protocol-coverage");
24
+ const auto_protocol_synthesizer_1 = require("./auto-protocol-synthesizer");
25
+ const bootstrap_validation_1 = require("./bootstrap-validation");
26
+ /** Build state signatures from protocol rules. */
27
+ function buildStateSignatures(rules) {
28
+ const sigs = [];
29
+ const seen = new Set();
30
+ for (const [fn, rule] of rules) {
31
+ // For each post_state, record fn as inbound
32
+ for (const ps of rule.post_states) {
33
+ if (ps.length === 0 || seen.has(ps))
34
+ continue;
35
+ seen.add(ps);
36
+ const inbound = new Set();
37
+ const outbound = new Set();
38
+ // Find all functions that produce this state (inbound)
39
+ for (const [otherFn, otherRule] of rules) {
40
+ if (otherRule.post_states.includes(ps))
41
+ inbound.add(otherFn);
42
+ if (otherRule.pre_states.includes(ps))
43
+ outbound.add(otherFn);
44
+ }
45
+ if (inbound.size > 0 || outbound.size > 0) {
46
+ sigs.push({ name: ps, inbound, outbound });
47
+ }
48
+ }
49
+ // Also add pre_states as signatures
50
+ for (const ps of rule.pre_states) {
51
+ if (ps.length === 0 || seen.has(ps))
52
+ continue;
53
+ seen.add(ps);
54
+ const inbound = new Set();
55
+ const outbound = new Set();
56
+ for (const [otherFn, otherRule] of rules) {
57
+ if (otherRule.post_states.includes(ps))
58
+ inbound.add(otherFn);
59
+ if (otherRule.pre_states.includes(ps))
60
+ outbound.add(otherFn);
61
+ }
62
+ if (inbound.size > 0 || outbound.size > 0) {
63
+ sigs.push({ name: ps, inbound, outbound });
64
+ }
65
+ }
66
+ }
67
+ return sigs;
68
+ }
69
+ // ═══════════════════════════════════════════════════════════════
70
+ // Jaccard Similarity
71
+ // ═══════════════════════════════════════════════════════════════
72
+ function jaccard(a, b) {
73
+ const intersection = [...a].filter(x => b.has(x)).length;
74
+ const union = new Set([...a, ...b]).size;
75
+ return union > 0 ? intersection / union : 0;
76
+ }
77
+ /**
78
+ * Find the best semantic name for a synthetic state.
79
+ *
80
+ * Computes Jaccard similarity between the synthetic state's
81
+ * action signature and each hand-written state's signature.
82
+ * Returns the name with the highest combined similarity.
83
+ */
84
+ function inferStateName(syntheticState, synthRules, handSignatures) {
85
+ // Build action signature for this synthetic state
86
+ const inbound = new Set();
87
+ const outbound = new Set();
88
+ for (const sr of synthRules) {
89
+ if (sr.post_states.includes(syntheticState))
90
+ inbound.add(sr.function);
91
+ if (sr.pre_states.includes(syntheticState))
92
+ outbound.add(sr.function);
93
+ }
94
+ // Fallback: try to derive name from function names
95
+ if (inbound.size === 0 && outbound.size === 0) {
96
+ return syntheticState; // keep original
97
+ }
98
+ let bestName = syntheticState;
99
+ let bestScore = 0;
100
+ for (const hs of handSignatures) {
101
+ const inSim = jaccard(inbound, hs.inbound);
102
+ const outSim = jaccard(outbound, hs.outbound);
103
+ const score = inSim * 0.5 + outSim * 0.5;
104
+ if (score > bestScore && score > 0.1) {
105
+ bestScore = score;
106
+ bestName = hs.name;
107
+ }
108
+ }
109
+ // If no good match found, try name-based inference
110
+ if (bestName === syntheticState) {
111
+ const allActions = [...inbound, ...outbound];
112
+ const prefixes = allActions.map(fn => {
113
+ const parts = fn.split("_");
114
+ // Extract domain prefix: "DB_Open" → "DB", "open_file" → "FILE"
115
+ if (parts.length > 1)
116
+ return parts[0].toUpperCase();
117
+ return "";
118
+ }).filter(p => p.length > 0);
119
+ if (prefixes.length > 0) {
120
+ // Most common prefix becomes the state name prefix
121
+ const prefixCounts = new Map();
122
+ for (const p of prefixes) {
123
+ prefixCounts.set(p, (prefixCounts.get(p) || 0) + 1);
124
+ }
125
+ const topPrefix = [...prefixCounts.entries()].sort((a, b) => b[1] - a[1])[0][0];
126
+ bestName = `${topPrefix}_${syntheticState.replace(/C\d+_/, "")}`;
127
+ }
128
+ }
129
+ return bestName;
130
+ }
131
+ // ═══════════════════════════════════════════════════════════════
132
+ // Protocol Alignment
133
+ // ═══════════════════════════════════════════════════════════════
134
+ /**
135
+ * Align synthesized protocol rules with hand-written state names.
136
+ *
137
+ * Replaces generic state names (C0_S1) with semantically meaningful
138
+ * names inferred from action context.
139
+ */
140
+ function alignSynthesizedProtocols(synthesized, handRules) {
141
+ const handSigs = buildStateSignatures(handRules);
142
+ return synthesized.map(sp => {
143
+ const allSynthRules = sp.rules;
144
+ const stateMap = new Map();
145
+ // Map each synthetic state to its best semantic name
146
+ const allStates = new Set();
147
+ for (const sr of allSynthRules) {
148
+ for (const s of sr.pre_states)
149
+ if (s !== "INIT")
150
+ allStates.add(s);
151
+ for (const s of sr.post_states)
152
+ if (s !== "INIT")
153
+ allStates.add(s);
154
+ }
155
+ for (const s of allStates) {
156
+ stateMap.set(s, inferStateName(s, allSynthRules, handSigs));
157
+ }
158
+ // Replace state names in rules
159
+ const alignedRules = allSynthRules.map(sr => ({
160
+ ...sr,
161
+ pre_states: sr.pre_states.map(s => s === "INIT" ? "INIT" : (stateMap.get(s) || s)),
162
+ post_states: sr.post_states.map(s => (stateMap.get(s) || s)),
163
+ invalidate: sr.invalidate?.map(s => (stateMap.get(s) || s)),
164
+ }));
165
+ return { ...sp, rules: alignedRules };
166
+ });
167
+ }
168
+ /**
169
+ * Run the full state name alignment pipeline and measure bootstrap improvement.
170
+ */
171
+ async function runStateAlignment() {
172
+ // Baseline
173
+ const baseline = await (0, bootstrap_validation_1.runBootstrapValidation)();
174
+ const beforeOverlap = baseline.functionOverlap;
175
+ // Get synthesized protocols
176
+ const synthesized = (0, auto_protocol_synthesizer_1.synthesizeAllKnownProtocols)();
177
+ // Get hand-written rules
178
+ const defs = (0, protocol_coverage_1.loadDefaultProtocolDefinitions)();
179
+ const handRules = new Map();
180
+ for (const p of defs)
181
+ for (const [fn, rule] of p.rules)
182
+ handRules.set(fn, rule);
183
+ // Align
184
+ const aligned = alignSynthesizedProtocols(synthesized, handRules);
185
+ // Count state alignments
186
+ let statesAligned = 0;
187
+ for (let i = 0; i < synthesized.length; i++) {
188
+ const orig = synthesized[i];
189
+ const algn = aligned[i];
190
+ for (let j = 0; j < orig.rules.length; j++) {
191
+ if (orig.rules[j].post_states[0] !== algn.rules[j].post_states[0]) {
192
+ statesAligned++;
193
+ }
194
+ }
195
+ }
196
+ // Re-run bootstrap (uses the aligned rules via synthesizeAllKnownProtocols)
197
+ const after = await (0, bootstrap_validation_1.runBootstrapValidation)();
198
+ const afterOverlap = after.functionOverlap;
199
+ return {
200
+ beforeOverlap,
201
+ afterOverlap,
202
+ improvement: afterOverlap - beforeOverlap,
203
+ statesAligned,
204
+ };
205
+ }
206
+ function printAlignmentReport(report) {
207
+ console.log("\n─── P6.8 State Name Alignment ───");
208
+ console.log(` States Aligned: ${report.statesAligned}`);
209
+ console.log(` Before Overlap: ${(report.beforeOverlap * 100).toFixed(0)}%`);
210
+ console.log(` After Overlap: ${(report.afterOverlap * 100).toFixed(0)}%`);
211
+ console.log(` Improvement: ${(report.improvement > 0 ? "+" : "")}${(report.improvement * 100).toFixed(0)}%`);
212
+ console.log();
213
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ /**
3
+ * P6.8: State Name Inference Tests
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vitest_1 = require("vitest");
7
+ const state_name_inference_1 = require("./state-name-inference");
8
+ const auto_protocol_synthesizer_1 = require("./auto-protocol-synthesizer");
9
+ const protocol_coverage_1 = require("./protocol-coverage");
10
+ (0, vitest_1.describe)("P6.8 State Name Inference", () => {
11
+ (0, vitest_1.it)("synthesizer generates semantic state names (integrated pipeline)", () => {
12
+ // Use the integrated synthesizer which now calls inferStateName internally
13
+ const protocols = (0, auto_protocol_synthesizer_1.synthesizeAllKnownProtocols)();
14
+ (0, vitest_1.expect)(protocols.length).toBeGreaterThan(0);
15
+ for (const sp of protocols) {
16
+ for (const sr of sp.rules) {
17
+ // Post states should NOT be generic C0_S1 format
18
+ for (const ps of sr.post_states) {
19
+ if (ps !== "INIT" && !ps.includes("_DONE")) {
20
+ // Semantic names come from inferStateName: FILE_OPEN, DB_CONNECTED, etc.
21
+ // or name-derived: DB_S1 (when no hand-written match found)
22
+ (0, vitest_1.expect)(ps).not.toMatch(/^C\d+_S\d+$/);
23
+ }
24
+ }
25
+ // Last rule's invalidate should contain semantic state names
26
+ if (sr.invalidate && sr.invalidate.length > 1) {
27
+ const hasSemantic = sr.invalidate.some(s => s.includes("_OPEN") || s.includes("_CLOSED") || s.includes("_CONNECTED") ||
28
+ s.includes("_VERIFIED") || s.includes("_ISSUED") || s.includes("_CREATED") ||
29
+ s.includes("_PRODUCED") || s.includes("_COMPLETED") || s.includes("_READY"));
30
+ (0, vitest_1.expect)(hasSemantic).toBe(true);
31
+ }
32
+ }
33
+ }
34
+ });
35
+ (0, vitest_1.it)("aligned states use semantically meaningful names", () => {
36
+ const dbSynth = {
37
+ clusterId: "DB",
38
+ prototype: ["open_file", "write_file", "close_file"],
39
+ rules: [
40
+ { function: "open_file", pre_states: ["INIT"], post_states: ["DB_S1"] },
41
+ { function: "write_file", pre_states: ["DB_S1"], post_states: ["DB_S2"] },
42
+ { function: "close_file", pre_states: ["DB_S2"], post_states: ["DB_DONE"], invalidate: ["DB_S1", "DB_S2"] },
43
+ ],
44
+ stateCount: 4,
45
+ inferredPattern: "RESOURCE_ACQUIRE",
46
+ confidence: 1.0,
47
+ };
48
+ const defs = (0, protocol_coverage_1.loadDefaultProtocolDefinitions)();
49
+ const handRules = new Map();
50
+ for (const p of defs)
51
+ for (const [fn, rule] of p.rules)
52
+ handRules.set(fn, rule);
53
+ const aligned = (0, state_name_inference_1.alignSynthesizedProtocols)([dbSynth], handRules);
54
+ const rules = aligned[0].rules;
55
+ // open_file's post_state → FILE_OPEN (matches hand-written open_file rule)
56
+ (0, vitest_1.expect)(rules[0].post_states[0]).toBe("FILE_OPEN");
57
+ // close_file: should invalidate FILE_OPEN (matches hand-written close_file invalidation)
58
+ const closeRule = rules[2];
59
+ (0, vitest_1.expect)(closeRule.invalidate).toBeDefined();
60
+ (0, vitest_1.expect)(closeRule.invalidate.some(s => s.includes("FILE_OPEN") || s.includes("FILE_CLOSED"))).toBe(true);
61
+ });
62
+ (0, vitest_1.it)("full alignment pipeline improves bootstrap overlap", async () => {
63
+ const report = await (0, state_name_inference_1.runStateAlignment)();
64
+ (0, vitest_1.expect)(report.statesAligned).toBeGreaterThan(0);
65
+ // Alignment should maintain or improve function overlap
66
+ (0, vitest_1.expect)(report.afterOverlap).toBeGreaterThanOrEqual(report.beforeOverlap);
67
+ (0, state_name_inference_1.printAlignmentReport)(report);
68
+ }, 30000);
69
+ });