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,269 @@
1
+ "use strict";
2
+ /**
3
+ * SSG Bridge — Smoke Tests
4
+ *
5
+ * Validates that the SSG bridge correctly:
6
+ * 1. Maps semantic domains to SSG namespaces
7
+ * 2. Matches real API calls to protocol rules
8
+ * 3. Detects state machine violations
9
+ * 4. Passes valid sequences without false positives
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const vitest_1 = require("vitest");
13
+ const ssg_bridge_1 = require("./ssg-bridge");
14
+ // Load protocol rules once for all tests
15
+ const protoData = (0, ssg_bridge_1.loadProtocolRules)();
16
+ const rules = protoData?.rules;
17
+ const nsInit = protoData?.namespaceInitialStates || {};
18
+ const aliasIndex = protoData?.aliasIndex || new Map();
19
+ const noAliases = new Map(); // empty alias map for fallback tests
20
+ // Helper: run SSG validation with alias index
21
+ function validate(steps, file = "test.ts") {
22
+ return (0, ssg_bridge_1.validateSequenceWithSSG)(steps, rules, nsInit, file, aliasIndex);
23
+ }
24
+ // Helper: build a minimal SemanticStep
25
+ function step(api, domain, description = "") {
26
+ return {
27
+ api,
28
+ domain: domain,
29
+ description,
30
+ source: "lookup",
31
+ };
32
+ }
33
+ (0, vitest_1.describe)("SSG Bridge", () => {
34
+ (0, vitest_1.it)("loads protocol rules from protocols.json", () => {
35
+ (0, vitest_1.expect)(rules).toBeDefined();
36
+ (0, vitest_1.expect)(rules.size).toBeGreaterThan(100);
37
+ (0, vitest_1.expect)(nsInit).toBeDefined();
38
+ (0, vitest_1.expect)(nsInit["auth"]).toBeDefined();
39
+ });
40
+ (0, vitest_1.describe)("call → rule inference", () => {
41
+ (0, vitest_1.it)("matches bcrypt-like calls to auth rules", () => {
42
+ const steps = [
43
+ step("bcrypt.compare", "auth_hash", "Verify password against stored hash"),
44
+ ];
45
+ const result = validate(steps);
46
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBeGreaterThanOrEqual(1);
47
+ });
48
+ (0, vitest_1.it)("matches JWT-like calls to auth rules", () => {
49
+ const steps = [
50
+ step("jwt.sign", "auth_mech", "Generate JWT token"),
51
+ ];
52
+ const result = validate(steps);
53
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBeGreaterThanOrEqual(1);
54
+ });
55
+ (0, vitest_1.it)("matches TLS-related calls to tls rules", () => {
56
+ const steps = [
57
+ step("https.createServer", "http_ops", "Create HTTPS server"),
58
+ ];
59
+ const result = validate(steps);
60
+ // http_ops maps to "tls" namespace, and createServer → http_create_server rule
61
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBeGreaterThanOrEqual(1);
62
+ });
63
+ (0, vitest_1.it)("matches file I/O calls to resource rules", () => {
64
+ const steps = [
65
+ step("fs.openSync", "conn_mgmt", "Open file for reading"),
66
+ ];
67
+ const result = validate(steps);
68
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBeGreaterThanOrEqual(1);
69
+ });
70
+ (0, vitest_1.it)("does not match util/stateless calls", () => {
71
+ const steps = [
72
+ step("console.log", "util", "Log output"),
73
+ step("JSON.parse", "util", "Parse JSON"),
74
+ ];
75
+ const result = validate(steps);
76
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBe(0);
77
+ (0, vitest_1.expect)(result.stats.unmatchedCalls).toBe(steps.length);
78
+ });
79
+ });
80
+ (0, vitest_1.describe)("alias-based matching (exact)", () => {
81
+ (0, vitest_1.it)("matches bcrypt.compare to verify_hash via alias", () => {
82
+ (0, vitest_1.expect)(aliasIndex.get("bcrypt.compare")).toBe("verify_hash");
83
+ });
84
+ (0, vitest_1.it)("matches bcrypt.hash to hash_password via alias", () => {
85
+ (0, vitest_1.expect)(aliasIndex.get("bcrypt.hash")).toBe("hash_password");
86
+ });
87
+ (0, vitest_1.it)("matches jsonwebtoken.sign to generate_jwt via alias", () => {
88
+ (0, vitest_1.expect)(aliasIndex.get("jsonwebtoken.sign")).toBe("generate_jwt");
89
+ });
90
+ (0, vitest_1.it)("matches jsonwebtoken.verify to verify_token via alias", () => {
91
+ (0, vitest_1.expect)(aliasIndex.get("jsonwebtoken.verify")).toBe("verify_token");
92
+ });
93
+ (0, vitest_1.it)("matches fs.openSync to open_file via alias", () => {
94
+ (0, vitest_1.expect)(aliasIndex.get("fs.opensync")).toBe("open_file");
95
+ });
96
+ (0, vitest_1.it)("matches prisma.model.findMany to query_db via alias", () => {
97
+ (0, vitest_1.expect)(aliasIndex.get("prisma.model.findmany")).toBe("query_db");
98
+ });
99
+ (0, vitest_1.it)("matches prisma.$disconnect to disconnect_db via alias", () => {
100
+ (0, vitest_1.expect)(aliasIndex.get("prisma.$disconnect")).toBe("disconnect_db");
101
+ });
102
+ (0, vitest_1.it)("matches express.listen to http_create_server via alias", () => {
103
+ (0, vitest_1.expect)(aliasIndex.get("express.listen")).toBe("http_create_server");
104
+ });
105
+ (0, vitest_1.it)("matches app.listen to http_create_server via alias", () => {
106
+ (0, vitest_1.expect)(aliasIndex.get("app.listen")).toBe("http_create_server");
107
+ });
108
+ (0, vitest_1.it)("matches db.transaction to begin_tx via alias", () => {
109
+ (0, vitest_1.expect)(aliasIndex.get("db.transaction")).toBe("begin_tx");
110
+ });
111
+ (0, vitest_1.it)("alias index has expected number of entries", () => {
112
+ // 21 rules with aliases, each with 3-10+ aliases
113
+ (0, vitest_1.expect)(aliasIndex.size).toBeGreaterThanOrEqual(50);
114
+ });
115
+ (0, vitest_1.it)("no duplicate alias mappings", () => {
116
+ // Each alias should map to exactly one rule
117
+ const values = Array.from(aliasIndex.values());
118
+ const uniqueValues = new Set(values);
119
+ // All unique rules should be present
120
+ (0, vitest_1.expect)(uniqueValues.size).toBeGreaterThanOrEqual(15);
121
+ });
122
+ });
123
+ (0, vitest_1.describe)("state machine validation", () => {
124
+ (0, vitest_1.it)("accepts jwt.sign as entry point (OAuth / cold start)", () => {
125
+ // generate_jwt is now an entry point (empty pre_states) because
126
+ // JWT can be generated from OAuth flow or password flow.
127
+ // See: state machine split — auth vs registration namespaces.
128
+ const steps = [
129
+ step("jwt.sign", "auth_mech", "Generate JWT token (OAuth callback or login)"),
130
+ ];
131
+ const result = validate(steps);
132
+ // jwt.sign maps to generate_jwt which now has empty pre_states
133
+ // → should match and pass without violations
134
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBeGreaterThanOrEqual(1);
135
+ (0, vitest_1.expect)(result.violations.length).toBe(0);
136
+ });
137
+ (0, vitest_1.it)("passes valid auth sequence (all entry points after split)", () => {
138
+ // After state machine split:
139
+ // - bcrypt.hash → hash_password (registration, entry point)
140
+ // - bcrypt.compare → verify_hash (auth/login, entry point)
141
+ // - jwt.sign → generate_jwt (auth, entry point for OAuth/login)
142
+ // All three are now valid entry points — no pre_state requirements.
143
+ const steps = [
144
+ step("bcrypt.hash", "auth_hash", "Hash password (registration flow)"),
145
+ step("bcrypt.compare", "auth_hash", "Verify password (login flow)"),
146
+ step("jwt.sign", "auth_mech", "Generate JWT token"),
147
+ ];
148
+ const result = validate(steps);
149
+ (0, vitest_1.expect)(result.stats.matchedCalls).toBeGreaterThanOrEqual(3);
150
+ (0, vitest_1.expect)(result.violations.length).toBe(0);
151
+ });
152
+ (0, vitest_1.it)("passes valid TLS sequence", () => {
153
+ const steps = [
154
+ step("fs.readFileSync", "tls_config", "Load TLS certificate"),
155
+ step("https.createServer", "http_ops", "Create HTTPS server with TLS"),
156
+ ];
157
+ const result = validate(steps);
158
+ // load_tls_config → TLS_CONFIGURED
159
+ // http_create_server requires TLS_CONFIGURED
160
+ // No state violations expected for correct sequence
161
+ const tlsViolations = result.violations.filter(v => v.namespace === "tls");
162
+ if (tlsViolations.length > 0) {
163
+ // If there are violations, they should include fix paths
164
+ for (const v of tlsViolations) {
165
+ (0, vitest_1.expect)(v.explanation).toBeTruthy();
166
+ }
167
+ }
168
+ });
169
+ (0, vitest_1.it)("detects missing cleanup (file opened but not closed)", () => {
170
+ // open_file without close_file — state machine will show FILE_OPEN still active
171
+ const steps = [
172
+ step("fs.openSync", "conn_mgmt", "Open file"),
173
+ step("fs.readFileSync", "conn_mgmt", "Read file contents"),
174
+ // Missing: close_file
175
+ ];
176
+ const result = validate(steps);
177
+ // The SSG state machine tracks that file is still open.
178
+ // While it may not report this as a violation (since close_file
179
+ // isn't called), the state trace should show FILE_OPEN is active.
180
+ (0, vitest_1.expect)(result.trace.length).toBe(steps.length);
181
+ });
182
+ });
183
+ (0, vitest_1.describe)("violation → TrustViolation conversion", () => {
184
+ (0, vitest_1.it)("converts SSG violations to TrustViolation format", () => {
185
+ const mockResult = {
186
+ passed: false,
187
+ trace: [],
188
+ violations: [{
189
+ callName: "jwt.sign",
190
+ namespace: "auth",
191
+ currentState: ["UNAUTHENTICATED"],
192
+ requiredState: ["PASSWORD_VERIFIED"],
193
+ fixPath: ["hash_password", "verify_hash"],
194
+ matchedRule: "generate_jwt",
195
+ explanation: "State violation: requires PASSWORD_VERIFIED but current is UNAUTHENTICATED",
196
+ }],
197
+ stats: { totalCalls: 1, matchedCalls: 1, unmatchedCalls: 0, validatedCalls: 1, violatedCalls: 1 },
198
+ };
199
+ const tv = (0, ssg_bridge_1.ssgViolationsToTrustViolations)(mockResult, "auth.ts", "login");
200
+ (0, vitest_1.expect)(tv.length).toBe(1);
201
+ (0, vitest_1.expect)(tv[0].rule_id).toContain("SSG_AUTH");
202
+ (0, vitest_1.expect)(tv[0].severity).toBe("medium");
203
+ (0, vitest_1.expect)(tv[0].file).toBe("auth.ts");
204
+ (0, vitest_1.expect)(tv[0].function).toBe("login");
205
+ (0, vitest_1.expect)(tv[0].fix).toContain("hash_password");
206
+ });
207
+ });
208
+ (0, vitest_1.describe)("loadProjectAliases", () => {
209
+ (0, vitest_1.it)("returns null when no .progmune_aliases.json exists", () => {
210
+ const result = (0, ssg_bridge_1.loadProjectAliases)("/tmp/nonexistent", new Set(["rule_a"]));
211
+ (0, vitest_1.expect)(result).toBeNull();
212
+ });
213
+ (0, vitest_1.it)("validates that target rules exist", () => {
214
+ // We need a real temp dir with a .progmune_aliases.json
215
+ const fs = require("fs");
216
+ const path = require("path");
217
+ const tmpDir = fs.mkdtempSync("/tmp/progmune-test-");
218
+ const aliasPath = path.join(tmpDir, ".progmune_aliases.json");
219
+ fs.writeFileSync(aliasPath, JSON.stringify({
220
+ aliases: {
221
+ "createSessionToken": "create_user_session",
222
+ "unknownWrapper": "nonexistent_rule",
223
+ }
224
+ }));
225
+ const result = (0, ssg_bridge_1.loadProjectAliases)(tmpDir, new Set(["create_user_session"]));
226
+ (0, vitest_1.expect)(result).not.toBeNull();
227
+ (0, vitest_1.expect)(result.aliases["createsessiontoken"]).toBe("create_user_session");
228
+ // unknownWrapper should have been skipped with a warning
229
+ (0, vitest_1.expect)(result.aliases["unknownwrapper"]).toBeUndefined();
230
+ (0, vitest_1.expect)(result.warnings.length).toBeGreaterThanOrEqual(1);
231
+ (0, vitest_1.expect)(result.warnings[0]).toContain("nonexistent_rule");
232
+ // Cleanup
233
+ fs.unlinkSync(aliasPath);
234
+ fs.rmdirSync(tmpDir);
235
+ });
236
+ (0, vitest_1.it)("respects case-insensitive alias keys", () => {
237
+ const fs = require("fs");
238
+ const path = require("path");
239
+ const tmpDir = fs.mkdtempSync("/tmp/progmune-test-");
240
+ fs.writeFileSync(path.join(tmpDir, ".progmune_aliases.json"), JSON.stringify({
241
+ aliases: {
242
+ "CreateSessionToken": "create_user_session",
243
+ }
244
+ }));
245
+ const result = (0, ssg_bridge_1.loadProjectAliases)(tmpDir, new Set(["create_user_session"]));
246
+ (0, vitest_1.expect)(result.aliases["createsessiontoken"]).toBe("create_user_session");
247
+ fs.unlinkSync(path.join(tmpDir, ".progmune_aliases.json"));
248
+ fs.rmdirSync(tmpDir);
249
+ });
250
+ (0, vitest_1.it)("merges project aliases without overriding global ones", () => {
251
+ // Load rules with project aliases — global aliasIndex should still have
252
+ // the global entries, and project entries should be additive
253
+ const data = (0, ssg_bridge_1.loadProtocolRules)("/Users/shenlian/printlab_mvp");
254
+ (0, vitest_1.expect)(data).not.toBeNull();
255
+ // Global aliases should still be present
256
+ (0, vitest_1.expect)(data.aliasIndex.get("bcrypt.compare")).toBe("verify_hash");
257
+ (0, vitest_1.expect)(data.aliasIndex.get("jsonwebtoken.sign")).toBe("generate_jwt");
258
+ // Project aliases should be present (from .progmune_aliases.json)
259
+ (0, vitest_1.expect)(data.aliasIndex.get("createsessiontoken")).toBe("create_user_session");
260
+ (0, vitest_1.expect)(data.aliasIndex.get("sendemail")).toBe("send_notification");
261
+ // Project aliases should be recorded separately
262
+ (0, vitest_1.expect)(data.projectAliases).toBeDefined();
263
+ (0, vitest_1.expect)(Object.keys(data.projectAliases).length).toBeGreaterThan(10);
264
+ // Should not have warnings for valid rules
265
+ const warnCount = (data.aliasWarnings || []).filter(w => w.includes("not found")).length;
266
+ (0, vitest_1.expect)(warnCount).toBe(0);
267
+ });
268
+ });
269
+ });
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 1: AI Trust Decision Model — Type Definitions
4
+ *
5
+ * Self-contained type system for the Trust Decision Engine.
6
+ * Does NOT modify or depend on existing types in src/policy/types.ts
7
+ * or src/audit/types.ts. The Trust Engine maps from those types into
8
+ * these types during evaluation.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.DECISION_THRESHOLDS = exports.DEFAULT_GOVERNANCE_DEDUCTIONS = exports.DEFAULT_COVERAGE_MAX_SCORES = exports.DEFAULT_PROTOCOL_WEIGHTS = exports.DEFAULT_SEVERITY_DEDUCTIONS = exports.DEFAULT_DIMENSION_WEIGHTS = exports.TRUST_VIOLATION_REQUIRED_FIELDS = void 0;
12
+ /** The 7 required fields for explainability completeness */
13
+ exports.TRUST_VIOLATION_REQUIRED_FIELDS = [
14
+ "severity",
15
+ "rule_id",
16
+ "file",
17
+ "function",
18
+ "evidence",
19
+ "why",
20
+ "fix",
21
+ "policy_ref",
22
+ ];
23
+ // ── Default Dimension Weights (from design doc) ──
24
+ exports.DEFAULT_DIMENSION_WEIGHTS = {
25
+ policyCompliance: 0.35,
26
+ protocolSafety: 0.30,
27
+ verificationCoverage: 0.20,
28
+ governanceIntegrity: 0.15,
29
+ evolutionStability: 0.00, // N/A in v1
30
+ };
31
+ // ── Default Severity Deductions (from design doc) ──
32
+ exports.DEFAULT_SEVERITY_DEDUCTIONS = {
33
+ critical: 40,
34
+ high: 20,
35
+ medium: 8,
36
+ low: 2,
37
+ };
38
+ // ── Default Protocol Weights ──
39
+ exports.DEFAULT_PROTOCOL_WEIGHTS = {
40
+ authentication: 0.25,
41
+ authorization: 0.20,
42
+ payment: 0.20,
43
+ data_integrity: 0.20,
44
+ ledger: 0.15,
45
+ };
46
+ // ── Default Verification Coverage Max Scores ──
47
+ exports.DEFAULT_COVERAGE_MAX_SCORES = {
48
+ typescriptTypeCheck: 25,
49
+ ssgRules: 30,
50
+ ledgerInvariant: 20,
51
+ coverage: 15,
52
+ failureGenome: 10,
53
+ };
54
+ // ── Default Governance Integrity Deductions ──
55
+ exports.DEFAULT_GOVERNANCE_DEDUCTIONS = {
56
+ hashMismatch: 50,
57
+ ledgerMissing: 30,
58
+ chainBroken: 20,
59
+ auditIncomplete: 10,
60
+ };
61
+ // ── Decision Thresholds ──
62
+ exports.DECISION_THRESHOLDS = {
63
+ approved: 80,
64
+ needsReview: 60,
65
+ // below 60 = BLOCKED
66
+ criticalLock: 59, // max score when critical violation exists
67
+ };
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 3: ViolationTrace — Structured Reasoning Chain
4
+ *
5
+ * Replaces string-concatenated violation messages with first-class
6
+ * ViolationTrace objects. Each trace captures the step-by-step protocol
7
+ * state transition that led to the violation, making it possible for
8
+ * an engineer who hasn't read protocols.json to understand the causal
9
+ * chain in under 2 minutes.
10
+ *
11
+ * Design principle: trace length → understanding time should be LINEAR,
12
+ * not exponential. This solves the "reasoning step disaster" where hidden
13
+ * intermediate states cause comprehension difficulty to explode.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.buildViolationTrace = buildViolationTrace;
17
+ exports.renderTraceAsText = renderTraceAsText;
18
+ exports.renderTraceSummary = renderTraceSummary;
19
+ exports.buildViolationTraces = buildViolationTraces;
20
+ // ── Trace Builder ──
21
+ /**
22
+ * Build a violation trace from a trust violation and its protocol context.
23
+ *
24
+ * The trace is a chain of protocol state transitions showing:
25
+ * 1. The sequence of function calls leading up to the violation
26
+ * 2. The expected protocol state at each step
27
+ * 3. The actual state at each step
28
+ * 4. The exact point where expectation and reality diverged
29
+ * 5. The fix: what should have been called instead
30
+ *
31
+ * @param violation - The violation to trace
32
+ * @param protocolStates - Optional ordered list of protocol states observed
33
+ * @param functionCalls - Optional ordered list of function calls (from IR)
34
+ * @returns A structured ViolationTrace
35
+ */
36
+ function buildViolationTrace(violation, protocolStates, functionCalls) {
37
+ const steps = [];
38
+ const references = [];
39
+ // Extract RFC/protocol reference
40
+ if (violation.policy_ref) {
41
+ references.push(violation.policy_ref);
42
+ }
43
+ // ── Build the reasoning chain ──
44
+ if (protocolStates && protocolStates.length > 0 && functionCalls && functionCalls.length > 0) {
45
+ // Full trace: we have the actual state machine walk
46
+ buildFullTrace(steps, protocolStates, functionCalls, violation);
47
+ }
48
+ else {
49
+ // Minimal trace: reconstruct from violation fields alone
50
+ buildMinimalTrace(steps, violation);
51
+ }
52
+ // Calculate violation point
53
+ const violationIdx = steps.findIndex(s => s.isViolationPoint);
54
+ const actualIdx = violationIdx >= 0 ? violationIdx : steps.length - 1;
55
+ // Build expected behavior description
56
+ const expectedBehavior = buildExpectedBehavior(steps, violation);
57
+ // Build fix path
58
+ const fixPath = violation.fix
59
+ ? violation.fix.split(/[;,]\s*/).filter(Boolean)
60
+ : ["Add missing protocol safeguard call"];
61
+ // Estimate reading time: ~15 seconds per step (empirical)
62
+ const estimatedReadingTimeMinutes = Math.max(1, Math.ceil(steps.length * 0.25));
63
+ return {
64
+ violation: {
65
+ rule_id: violation.rule_id,
66
+ file: violation.file,
67
+ function: violation.function,
68
+ message: violation.message,
69
+ },
70
+ steps,
71
+ violationStepIndex: actualIdx,
72
+ expectedBehavior,
73
+ fixPath,
74
+ references,
75
+ estimatedReadingTimeMinutes,
76
+ };
77
+ }
78
+ // ── Full Trace (when we have state machine data) ──
79
+ function buildFullTrace(steps, states, calls, violation) {
80
+ for (let i = 0; i < Math.min(calls.length, states.length); i++) {
81
+ const call = calls[i];
82
+ const currentState = i > 0 ? states[i - 1] : "INITIAL";
83
+ const actualNextState = i < states.length ? states[i] : "UNKNOWN";
84
+ // Determine expected state transition
85
+ const expected = inferExpectedState(currentState, call);
86
+ // Violation: expected transition exists but actual state doesn't match
87
+ // OR: call requires specific pre-state but we're not in it
88
+ const isViolation = expected !== null && expected !== actualNextState &&
89
+ actualNextState !== "UNKNOWN" && actualNextState !== expected;
90
+ const stepExplanation = isViolation
91
+ ? `函数 ${call} 在状态 ${currentState} 下被调用。` +
92
+ `预期协议状态应转为 ${expected},但实际为 ${actualNextState}。` +
93
+ `这违反了 ${violation.rule_id}。${violation.evidence || violation.why || ""}`
94
+ : expected
95
+ ? `函数 ${call} 将协议状态从 ${currentState} 正常转移到 ${expected}。`
96
+ : `函数 ${call} 执行(无协议状态变更要求)。`;
97
+ steps.push({
98
+ step: i + 1,
99
+ label: inferStepLabel(call, currentState),
100
+ action: call,
101
+ preState: currentState,
102
+ expectedPostState: expected,
103
+ actualPostState: isViolation ? actualNextState : (expected || actualNextState),
104
+ isViolationPoint: isViolation,
105
+ ruleRef: violation.rule_id,
106
+ explanation: stepExplanation,
107
+ });
108
+ }
109
+ }
110
+ // ── Minimal Trace (reconstructed from violation fields) ──
111
+ function buildMinimalTrace(steps, violation) {
112
+ // Parse the violation to reconstruct the reasoning chain
113
+ const funcName = violation.function || "unknown_function";
114
+ const fileName = violation.file || "unknown_file";
115
+ // Step 1: The triggering action
116
+ steps.push({
117
+ step: 1,
118
+ label: "违规触发点",
119
+ action: funcName,
120
+ preState: "EXPECTED_PROTOCOL_STATE",
121
+ expectedPostState: "SAFE_STATE",
122
+ actualPostState: "VIOLATION_STATE",
123
+ isViolationPoint: true,
124
+ ruleRef: violation.rule_id,
125
+ explanation: `在 ${fileName} 中,函数 ${funcName} 的执行触发了违规检测。${violation.evidence || ""}`,
126
+ });
127
+ // Step 2: Why it's a violation
128
+ steps.push({
129
+ step: 2,
130
+ label: "违规原因",
131
+ action: "protocol_check",
132
+ preState: "VIOLATION_STATE",
133
+ expectedPostState: null,
134
+ actualPostState: null,
135
+ isViolationPoint: false,
136
+ ruleRef: violation.rule_id,
137
+ explanation: violation.why || violation.message || "协议规则匹配发现违规。",
138
+ });
139
+ // Step 3: The fix
140
+ if (violation.fix) {
141
+ steps.push({
142
+ step: 3,
143
+ label: "修复路径",
144
+ action: violation.fix,
145
+ preState: "VIOLATION_STATE",
146
+ expectedPostState: "SAFE_STATE",
147
+ actualPostState: null,
148
+ isViolationPoint: false,
149
+ ruleRef: violation.rule_id,
150
+ explanation: `建议修复: ${violation.fix}`,
151
+ });
152
+ }
153
+ }
154
+ // ── State Inference Helpers ──
155
+ /** Infer expected protocol state transition from function name + current state */
156
+ function inferExpectedState(currentState, functionCall) {
157
+ const call = functionCall.toLowerCase();
158
+ // Authentication chain
159
+ if (currentState === "UNAUTHENTICATED") {
160
+ if (/login|authenticate|signin|verify_password/.test(call))
161
+ return "AUTHENTICATED";
162
+ if (/register|signup/.test(call))
163
+ return "USER_REGISTERED";
164
+ }
165
+ if (currentState === "AUTHENTICATED") {
166
+ if (/authorize|check_owner|check_permission/.test(call))
167
+ return "AUTHORIZED";
168
+ if (/logout|revoke/.test(call))
169
+ return "UNAUTHENTICATED";
170
+ }
171
+ if (currentState === "PASSWORD_RECEIVED" && /hash|crypt|bcrypt|argon/.test(call))
172
+ return "PASSWORD_HASHED";
173
+ if (currentState === "PASSWORD_HASHED" && /verify|compare/.test(call))
174
+ return "PASSWORD_VERIFIED";
175
+ if (currentState === "TOKEN_ISSUED" && /revoke|invalidate/.test(call))
176
+ return "UNAUTHENTICATED";
177
+ // TLS chain
178
+ if (currentState === "TLS_CONFIGURED") {
179
+ if (/listen|bind|accept|start_server|create_server/.test(call))
180
+ return "SERVER_STARTED";
181
+ if (/set_cipher|use_cert|load_cert/.test(call))
182
+ return "TLS_CONFIGURED"; // still configuring
183
+ }
184
+ // File upload chain
185
+ if (currentState === "AUTHENTICATED" && /receive_upload|handle_upload/.test(call))
186
+ return "FILE_RECEIVED";
187
+ if (currentState === "FILE_RECEIVED" && /validate_file|check_file|stat\b/.test(call))
188
+ return "FILE_VALIDATED";
189
+ if (currentState === "FILE_VALIDATED" && /store_file|save_file|write_file/.test(call))
190
+ return "FILE_STORED";
191
+ // Payment chain
192
+ if (currentState === "ORDER_CREATED" && /initiate_payment/.test(call))
193
+ return "PAYMENT_INITIATED";
194
+ if (currentState === "PAYMENT_INITIATED" && /receive_callback/.test(call))
195
+ return "PAYMENT_CALLBACK_RECEIVED";
196
+ if (currentState === "PAYMENT_CALLBACK_RECEIVED") {
197
+ if (/confirm/.test(call))
198
+ return "PAYMENT_CONFIRMED";
199
+ if (/fail/.test(call))
200
+ return "PAYMENT_FAILED";
201
+ }
202
+ // Generic patterns (fallback)
203
+ if (/init|create|new|start|setup|open/.test(call))
204
+ return "INITIALIZED";
205
+ if (/connect|handshake/.test(call))
206
+ return "CONNECTED";
207
+ if (/send|write|transfer|xfer/.test(call))
208
+ return "DATA_TRANSFERRED";
209
+ if (/close|free|cleanup|shutdown|destroy|done/.test(call))
210
+ return "CLOSED";
211
+ if (/validate|verify|check/.test(call))
212
+ return "VALIDATED";
213
+ return null;
214
+ }
215
+ /** Generate a human-readable label for a trace step */
216
+ function inferStepLabel(functionCall, currentState) {
217
+ const call = functionCall.toLowerCase();
218
+ // Auth
219
+ if (/login|authenticate|signin|verify_password/.test(call))
220
+ return "用户认证";
221
+ if (/register|signup/.test(call))
222
+ return "用户注册";
223
+ if (/logout|revoke|invalidate/.test(call))
224
+ return "会话终止";
225
+ if (/authorize|check_owner|check_permission/.test(call))
226
+ return "权限检查";
227
+ if (/hash|crypt|bcrypt|argon/.test(call))
228
+ return "密码哈希";
229
+ if (/verify_hash|compare_password/.test(call))
230
+ return "密码验证";
231
+ // TLS
232
+ if (/load_tls|ssl_init|tls_setup|configure_ssl|configure_tls/.test(call))
233
+ return "TLS 配置";
234
+ if (/listen|bind|accept|start_server|create_server/.test(call))
235
+ return "服务器启动";
236
+ if (/set_cipher|use_cert|load_cert/.test(call))
237
+ return "证书配置";
238
+ // Network
239
+ if (/connect|handshake/.test(call))
240
+ return "协议握手";
241
+ if (/send|write|transfer|xfer/.test(call))
242
+ return "数据传输";
243
+ if (/close|free|cleanup|shutdown|destroy|done/.test(call))
244
+ return "连接关闭";
245
+ // File
246
+ if (/receive_upload|handle_upload/.test(call))
247
+ return "文件接收";
248
+ if (/validate_file|check_file/.test(call))
249
+ return "文件校验";
250
+ if (/store_file|save_file|write_file/.test(call))
251
+ return "文件存储";
252
+ // General
253
+ if (/init|create|new|start|setup|open/.test(call))
254
+ return "资源初始化";
255
+ if (/validate|verify|check/.test(call))
256
+ return "安全校验";
257
+ if (/encrypt|cipher/.test(call))
258
+ return "数据加密";
259
+ if (/decrypt/.test(call))
260
+ return "数据解密";
261
+ if (/hash/.test(call))
262
+ return "哈希计算";
263
+ return `状态转换: ${currentState}`;
264
+ }
265
+ /** Build a human-readable expected behavior description */
266
+ function buildExpectedBehavior(steps, violation) {
267
+ const violStep = steps.find(s => s.isViolationPoint);
268
+ if (!violStep) {
269
+ return `应遵循协议规则 ${violation.rule_id}。修复建议: ${violation.fix || "添加缺失的协议安全调用"}`;
270
+ }
271
+ return `函数 ${violStep.action} 在状态 ${violStep.preState} 下被调用时,` +
272
+ `应首先确保协议状态转换到 ${violStep.expectedPostState || "安全状态"},` +
273
+ `而非停留在 ${violStep.actualPostState || "违规状态"}。` +
274
+ `这违反了 ${violation.rule_id}。`;
275
+ }
276
+ // ── Serialization ──
277
+ /**
278
+ * Render a ViolationTrace as a human-readable text block.
279
+ *
280
+ * Format:
281
+ * 代码第 X 行调用了 send()
282
+ * → 此时 TLS 状态是 HANDSHAKE_INCOMPLETE
283
+ * → 根据 RFC 8446 §4.2.2,此状态下不允许发送应用数据
284
+ * → 违规
285
+ */
286
+ function renderTraceAsText(trace) {
287
+ const lines = [];
288
+ lines.push(`═══════ 违规推理链 ═══════`);
289
+ lines.push(`文件: ${trace.violation.file}`);
290
+ lines.push(`函数: ${trace.violation.function}`);
291
+ lines.push(`规则: ${trace.violation.rule_id}`);
292
+ lines.push("");
293
+ for (const step of trace.steps) {
294
+ const marker = step.isViolationPoint ? "❌" : " ";
295
+ lines.push(`${marker} [步骤 ${step.step}] ${step.label}`);
296
+ lines.push(` 操作: ${step.action}`);
297
+ lines.push(` 状态: ${step.preState}`);
298
+ if (step.expectedPostState) {
299
+ lines.push(` 预期: → ${step.expectedPostState}`);
300
+ }
301
+ if (step.actualPostState && step.isViolationPoint) {
302
+ lines.push(` 实际: → ${step.actualPostState} ← 违规发生`);
303
+ }
304
+ if (step.ruleRef) {
305
+ lines.push(` 依据: ${step.ruleRef}`);
306
+ }
307
+ lines.push(` 说明: ${step.explanation}`);
308
+ lines.push("");
309
+ }
310
+ lines.push(`预期行为: ${trace.expectedBehavior}`);
311
+ lines.push(`修复路径: ${trace.fixPath.join(" → ")}`);
312
+ if (trace.references.length > 0) {
313
+ lines.push(`参考: ${trace.references.join(", ")}`);
314
+ }
315
+ lines.push("");
316
+ lines.push(`估算阅读时间: ~${trace.estimatedReadingTimeMinutes} 分钟`);
317
+ return lines.join("\n");
318
+ }
319
+ /**
320
+ * Render a ViolationTrace as a compact single-line summary.
321
+ */
322
+ function renderTraceSummary(trace) {
323
+ const violStep = trace.steps[trace.violationStepIndex];
324
+ if (!violStep)
325
+ return trace.violation.message;
326
+ return `${violStep.action} 在 ${violStep.preState} 状态下违反 ${trace.violation.rule_id}` +
327
+ (trace.fixPath.length > 0 ? ` → 修复: ${trace.fixPath.join(" → ")}` : "");
328
+ }
329
+ // ── Batch Tracing ──
330
+ /**
331
+ * Build traces for multiple violations.
332
+ */
333
+ function buildViolationTraces(violations) {
334
+ return violations.map(v => buildViolationTrace(v));
335
+ }