progmune-runtime 2.1.6 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/README.md +108 -468
  2. package/dist/ablation-study.js +144 -0
  3. package/dist/ablation-study.test.js +18 -0
  4. package/dist/action-runtime.js +3 -1
  5. package/dist/active-learning.js +211 -0
  6. package/dist/analytics.js +139 -0
  7. package/dist/asset-factory.js +309 -0
  8. package/dist/asset-growth.js +244 -0
  9. package/dist/asset-promotion.js +382 -0
  10. package/dist/asset-quality.js +550 -0
  11. package/dist/audit/business-translator.js +285 -0
  12. package/dist/audit/cli.js +66 -0
  13. package/dist/audit/formatters/html.js +379 -0
  14. package/dist/audit/formatters/json.js +11 -0
  15. package/dist/audit/formatters/markdown.js +192 -0
  16. package/dist/audit/formatters/terminal.js +189 -0
  17. package/dist/audit/index.js +25 -0
  18. package/dist/audit/report-builder.js +318 -0
  19. package/dist/audit/types.js +8 -0
  20. package/dist/audit.js +3 -3
  21. package/dist/auto-benchmark-generator.js +137 -0
  22. package/dist/auto-benchmark-generator.test.js +45 -0
  23. package/dist/auto-protocol-synthesizer.js +362 -0
  24. package/dist/auto-protocol-synthesizer.test.js +82 -0
  25. package/dist/autonomous-patch.js +175 -0
  26. package/dist/autonomous-patch.test.js +128 -0
  27. package/dist/badge/badge-server.js +98 -0
  28. package/dist/behavior-miner.js +442 -0
  29. package/dist/belief-layer.js +475 -0
  30. package/dist/benchmark-count.js +5 -0
  31. package/dist/benchmark-generator.js +211 -0
  32. package/dist/benchmark-harness.js +201 -0
  33. package/dist/benchmark-pass-rate.js +7 -0
  34. package/dist/benchmark-report.js +8 -3
  35. package/dist/benchmark-save.js +14 -1
  36. package/dist/bootstrap-validation.js +197 -0
  37. package/dist/bootstrap-validation.test.js +51 -0
  38. package/dist/branch-ledger.js +1 -1
  39. package/dist/capability-gap.js +130 -0
  40. package/dist/certify-html.js +351 -0
  41. package/dist/certify.js +326 -0
  42. package/dist/check.js +4 -4
  43. package/dist/compliance-miner.js +447 -0
  44. package/dist/continuous-benchmark.js +194 -0
  45. package/dist/continuous-benchmark.test.js +116 -0
  46. package/dist/corpus-stats.js +173 -0
  47. package/dist/counterfactual-engine.js +288 -0
  48. package/dist/coverage-dashboard.js +109 -0
  49. package/dist/coverage-system.test.js +205 -0
  50. package/dist/cross-repo-precision.js +352 -0
  51. package/dist/cve-benchmark.js +180 -0
  52. package/dist/cve-benchmark.test.js +28 -0
  53. package/dist/cve-collector.js +73 -0
  54. package/dist/data-quality.js +141 -0
  55. package/dist/decision-engine.js +388 -0
  56. package/dist/derive-metadata.js +250 -0
  57. package/dist/difficulty-active.test.js +198 -0
  58. package/dist/difficulty-map.js +244 -0
  59. package/dist/discovery-analytics.js +125 -0
  60. package/dist/discovery-model.js +149 -0
  61. package/dist/discovery-optimize.test.js +199 -0
  62. package/dist/discovery-trace.js +276 -0
  63. package/dist/discovery-trace.test.js +97 -0
  64. package/dist/emitter.js +83 -1
  65. package/dist/enterprise-dashboard.js +405 -0
  66. package/dist/eval-hardening.js +297 -0
  67. package/dist/eval-hardening.test.js +85 -0
  68. package/dist/evaluation-campaign.js +359 -0
  69. package/dist/evaluation-campaign.test.js +181 -0
  70. package/dist/evidence-growth.js +143 -0
  71. package/dist/evidence-repository.js +209 -0
  72. package/dist/evidence-system.js +441 -0
  73. package/dist/execute.js +15 -7
  74. package/dist/experimental/software-physics.js +291 -0
  75. package/dist/experimental/state-inference.js +516 -0
  76. package/dist/experimental/unsupervised-physics.js +230 -0
  77. package/dist/extract-ir-python.js +54 -7
  78. package/dist/extract-ir.js +376 -12
  79. package/dist/failure-collector.js +2 -2
  80. package/dist/failure-corpus.js +322 -9
  81. package/dist/feedback.js +16 -5
  82. package/dist/feedback.test.js +49 -0
  83. package/dist/file-lock.js +1 -1
  84. package/dist/flywheel-batch.js +292 -0
  85. package/dist/frameworks/express-cli.js +237 -0
  86. package/dist/frameworks/express-detector.js +445 -0
  87. package/dist/frameworks/express-detector.test.js +206 -0
  88. package/dist/frameworks/index.js +30 -0
  89. package/dist/frameworks/nestjs-detector.js +302 -0
  90. package/dist/frameworks/trpc-detector.js +161 -0
  91. package/dist/frameworks/version-awareness.js +179 -0
  92. package/dist/function-synonyms.js +164 -0
  93. package/dist/function-synonyms.test.js +68 -0
  94. package/dist/generalization.test.js +352 -0
  95. package/dist/goal-annotator.js +113 -0
  96. package/dist/goal-planner.js +563 -0
  97. package/dist/gold-cve.js +164 -0
  98. package/dist/gold-cve.test.js +104 -0
  99. package/dist/gold-quality.js +206 -0
  100. package/dist/gold-tiers.js +241 -0
  101. package/dist/governance-dashboard.js +327 -0
  102. package/dist/graph-viz.js +240 -0
  103. package/dist/guided-frontier.js +195 -0
  104. package/dist/hierarchical-planner.js +148 -0
  105. package/dist/identifier-parser.js +260 -0
  106. package/dist/immune-metrics.js +93 -0
  107. package/dist/immune-receiver.js +158 -0
  108. package/dist/immune-reporter.js +1 -1
  109. package/dist/improvement-orchestrator.js +206 -0
  110. package/dist/inject-p0-vocabulary.js +300 -0
  111. package/dist/intent-parser.js +218 -0
  112. package/dist/invariant-algebra.js +476 -0
  113. package/dist/invariant-calculus.js +533 -0
  114. package/dist/ir-utils.js +70 -0
  115. package/dist/ir-utils.test.js +50 -0
  116. package/dist/knowledge-api.js +312 -0
  117. package/dist/knowledge-evolution.js +452 -0
  118. package/dist/knowledge-explorer.js +506 -0
  119. package/dist/knowledge-flywheel.js +274 -0
  120. package/dist/knowledge-governance.js +338 -0
  121. package/dist/knowledge-governance.test.js +150 -0
  122. package/dist/knowledge-graph.js +181 -0
  123. package/dist/knowledge-guided-synth.js +246 -0
  124. package/dist/knowledge-loop.test.js +77 -0
  125. package/dist/knowledge-object.js +316 -0
  126. package/dist/knowledge-package.js +98 -0
  127. package/dist/kpi-dashboard.js +561 -0
  128. package/dist/l3-cross-function.js +280 -0
  129. package/dist/learning-ranker.js +148 -0
  130. package/dist/learning-ranker.test.js +291 -0
  131. package/dist/ledger/accountability.js +322 -0
  132. package/dist/ledger/chain-builder.js +185 -0
  133. package/dist/ledger/cli.js +222 -0
  134. package/dist/ledger/index.js +13 -0
  135. package/dist/ledger/signatures.js +193 -0
  136. package/dist/ledger/types.js +9 -0
  137. package/dist/llm.js +74 -3
  138. package/dist/load-benchmarks.js +8 -3
  139. package/dist/logger.js +66 -0
  140. package/dist/logger.test.js +37 -0
  141. package/dist/logistic-reward.js +339 -0
  142. package/dist/logistic-reward.test.js +180 -0
  143. package/dist/macro-graph.js +193 -0
  144. package/dist/macro-repair.js +183 -0
  145. package/dist/mcp-server.mjs +1202 -483
  146. package/dist/memory-layer.js +42 -5
  147. package/dist/multi-repo-precision.js +422 -0
  148. package/dist/name-free-protocol.js +425 -0
  149. package/dist/name-free-protocol.test.js +170 -0
  150. package/dist/name-scrambling.js +138 -0
  151. package/dist/name-scrambling.test.js +16 -0
  152. package/dist/p3-observability.test.js +281 -0
  153. package/dist/p5-orchestrator.test.js +225 -0
  154. package/dist/pairwise-preference.js +294 -0
  155. package/dist/pairwise-preference.test.js +140 -0
  156. package/dist/planner-constraints.js +104 -0
  157. package/dist/planner-prompts.js +155 -0
  158. package/dist/planner-telemetry.js +415 -0
  159. package/dist/planner-trace.js +214 -0
  160. package/dist/planner.js +162 -167
  161. package/dist/plsb/artifact.js +116 -0
  162. package/dist/plsb/cli.js +71 -0
  163. package/dist/plsb/index.js +19 -0
  164. package/dist/plsb/leaderboard.js +249 -0
  165. package/dist/plsb/report-md.js +156 -0
  166. package/dist/plsb/schema.js +179 -0
  167. package/dist/plsb-benchmark.js +284 -0
  168. package/dist/plsb-benchmark.test.js +119 -0
  169. package/dist/policy/cli.js +134 -0
  170. package/dist/policy/engine.js +333 -0
  171. package/dist/policy/index.js +12 -0
  172. package/dist/policy/types.js +59 -0
  173. package/dist/policy-miner.js +505 -0
  174. package/dist/precision-analyze.js +229 -0
  175. package/dist/precision-benchmark.js +147 -0
  176. package/dist/precision-label-c.js +134 -0
  177. package/dist/precision-label.js +193 -0
  178. package/dist/precision-report-c.js +149 -0
  179. package/dist/precision-report.js +246 -0
  180. package/dist/progmune-status.js +108 -0
  181. package/dist/proof-engine.js +479 -0
  182. package/dist/proof-provenance.js +315 -0
  183. package/dist/protocol-coverage.js +294 -0
  184. package/dist/protocol-detector.js +1189 -0
  185. package/dist/protocol-embedding-expanded.js +297 -0
  186. package/dist/protocol-embedding-expanded.test.js +97 -0
  187. package/dist/protocol-embedding.js +195 -0
  188. package/dist/protocol-embedding.test.js +82 -0
  189. package/dist/protocol-extractor-v2.js +354 -0
  190. package/dist/protocol-extractor-v2.test.js +140 -0
  191. package/dist/protocol-extractor.js +310 -0
  192. package/dist/protocol-extractor.test.js +113 -0
  193. package/dist/protocol-foundation.js +322 -0
  194. package/dist/protocol-foundation.test.js +163 -0
  195. package/dist/protocol-frontier.js +243 -0
  196. package/dist/protocol-frontier.test.js +92 -0
  197. package/dist/protocol-gap-analyzer.js +228 -0
  198. package/dist/protocol-gap-analyzer.test.js +49 -0
  199. package/dist/protocol-invariants.js +276 -0
  200. package/dist/protocol-invariants.test.js +111 -0
  201. package/dist/protocol-knowledge.js +464 -0
  202. package/dist/protocol-miner.js +343 -0
  203. package/dist/protocol-mining.js +207 -0
  204. package/dist/protocol-mining.test.js +37 -0
  205. package/dist/protocol-registry.js +1 -1
  206. package/dist/protocol-security-benchmark.js +222 -0
  207. package/dist/protocol-vulnerability.js +257 -0
  208. package/dist/protocol-vulnerability.test.js +60 -0
  209. package/dist/python-benchmark.js +120 -0
  210. package/dist/python-emitter.js +163 -45
  211. package/dist/python-protocol-extractor.js +187 -0
  212. package/dist/python-protocol-extractor.test.js +116 -0
  213. package/dist/realworld-benchmark.js +646 -0
  214. package/dist/realworld-benchmark.test.js +36 -0
  215. package/dist/repair-arch.test.js +411 -0
  216. package/dist/repair-evolution.test.js +454 -0
  217. package/dist/repair-executor.js +719 -0
  218. package/dist/repair-proposal.js +4 -4
  219. package/dist/repair-ranker.js +141 -0
  220. package/dist/repair-strategies.js +419 -0
  221. package/dist/repair-taxonomy.js +234 -0
  222. package/dist/repair-types.js +12 -0
  223. package/dist/repo-evaluator.js +250 -0
  224. package/dist/repo-evaluator.test.js +128 -0
  225. package/dist/resource-abstraction.js +242 -0
  226. package/dist/resource-detector.js +211 -0
  227. package/dist/result.test.js +43 -0
  228. package/dist/reward-system.js +411 -0
  229. package/dist/reward-system.test.js +175 -0
  230. package/dist/risk-model.js +215 -0
  231. package/dist/rule-miner.js +234 -7
  232. package/dist/rule-specificity.js +254 -0
  233. package/dist/runtime-types.js +27 -0
  234. package/dist/scaffold.js +208 -0
  235. package/dist/scale-collector.test.js +101 -0
  236. package/dist/scale-trajectory-collector.js +128 -0
  237. package/dist/sdk.js +250 -0
  238. package/dist/search-planner.js +4 -41
  239. package/dist/semantic-snapshot.js +1 -1
  240. package/dist/semantic-topology.js +121 -0
  241. package/dist/semantic-trace.js +310 -317
  242. package/dist/sequence-extractor.js +343 -0
  243. package/dist/skill-library.js +245 -0
  244. package/dist/skill-planner.test.js +189 -0
  245. package/dist/software-physics.js +291 -0
  246. package/dist/software-physics.test.js +81 -0
  247. package/dist/ssg-precision.js +478 -0
  248. package/dist/ssg-validator.js +71 -21
  249. package/dist/state-inference-doubleblind.test.js +160 -0
  250. package/dist/state-inference.js +516 -0
  251. package/dist/state-inference.test.js +115 -0
  252. package/dist/state-machine-fingerprint.js +345 -0
  253. package/dist/state-machine-fingerprint.test.js +120 -0
  254. package/dist/state-miner.js +386 -0
  255. package/dist/state-name-inference.js +213 -0
  256. package/dist/state-name-inference.test.js +69 -0
  257. package/dist/strategy-planner.js +262 -96
  258. package/dist/strategy-planner.test.js +135 -0
  259. package/dist/telemetry-analytics.test.js +402 -0
  260. package/dist/terminal-format.js +68 -0
  261. package/dist/terminal-format.test.js +83 -0
  262. package/dist/topology-factory.js +196 -0
  263. package/dist/topology-representation.js +242 -0
  264. package/dist/topology-representation.test.js +27 -0
  265. package/dist/trajectory-augmentation.js +254 -0
  266. package/dist/trajectory-augmentation.test.js +63 -0
  267. package/dist/trajectory-corpus.js +440 -0
  268. package/dist/trajectory-corpus.test.js +32 -0
  269. package/dist/trajectory-feedback.test.js +116 -0
  270. package/dist/transition-synthesizer.js +286 -0
  271. package/dist/transition-synthesizer.test.js +123 -0
  272. package/dist/trust/api-semantic-mapper.js +809 -0
  273. package/dist/trust/call-graph-propagator.js +225 -0
  274. package/dist/trust/cli.js +122 -0
  275. package/dist/trust/compliance-scorer.js +283 -0
  276. package/dist/trust/confidence-calculator.js +261 -0
  277. package/dist/trust/engine.js +1145 -0
  278. package/dist/trust/explainability.js +85 -0
  279. package/dist/trust/formatters/ci.js +42 -0
  280. package/dist/trust/formatters/json.js +11 -0
  281. package/dist/trust/formatters/terminal.js +152 -0
  282. package/dist/trust/index.js +39 -0
  283. package/dist/trust/phase1-verify.js +171 -0
  284. package/dist/trust/protocol-domain-validator.js +697 -0
  285. package/dist/trust/score-calculator.js +282 -0
  286. package/dist/trust/ssg-bridge.js +641 -0
  287. package/dist/trust/ssg-bridge.test.js +269 -0
  288. package/dist/trust/types.js +67 -0
  289. package/dist/trust/violation-trace.js +335 -0
  290. package/dist/trust-api.js +179 -0
  291. package/dist/trust-calibration.js +279 -0
  292. package/dist/unknown-protocol-discovery.js +339 -0
  293. package/dist/unknown-protocol-discovery.test.js +102 -0
  294. package/dist/unsupervised-physics.js +230 -0
  295. package/dist/unsupervised-physics.test.js +95 -0
  296. package/dist/utils.test.js +37 -0
  297. package/dist/validator.js +187 -10
  298. package/dist/verification-intelligence.js +475 -0
  299. package/dist/verify-api.js +432 -0
  300. package/dist/vi-impact-report.js +293 -0
  301. package/dist/wl-fingerprint.js +162 -0
  302. package/dist/wl-fingerprint.test.js +130 -0
  303. package/dist/zeroshot-strategy.js +139 -0
  304. package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
  305. package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
  306. package/package.json +74 -7
  307. package/protocols.json +1956 -50
  308. package/.dockerignore +0 -14
  309. package/.mcp.json +0 -11
  310. package/.progmune_allowlist +0 -50
  311. package/.test_report/test_report.md +0 -87
  312. package/Dockerfile +0 -9
  313. package/FAQ.md +0 -167
  314. package/WHITEPAPER.md +0 -540
  315. package/demo-project/auth.ts +0 -55
  316. package/demo-project/tsconfig.json +0 -8
  317. package/dist/acl-breakdown.js +0 -13
  318. package/dist/all-sessions.js +0 -11
  319. package/dist/antibody-stats.js +0 -11
  320. package/dist/branch-tree-count.js +0 -14
  321. package/dist/common-fixpath.js +0 -12
  322. package/dist/constraint-types.js +0 -12
  323. package/dist/exec-metrics.js +0 -11
  324. package/dist/failure-report.js +0 -11
  325. package/dist/fast-path-hits.js +0 -13
  326. package/dist/fingerprint-list.js +0 -15
  327. package/dist/gen-history-log.js +0 -13
  328. package/dist/heatmap-data.js +0 -11
  329. package/dist/recent-session.js +0 -12
  330. package/dist/svl-distribution.js +0 -11
  331. package/dist/terminal-status.js +0 -11
  332. package/dist/token-savings.js +0 -11
  333. package/dist/total-repairs.js +0 -12
  334. package/dist/unresolved-count.js +0 -12
  335. package/dist/valid-fingerprints.js +0 -13
  336. package/dist/verify-ledgers.js +0 -11
  337. package/docs/whitepaper-style.css +0 -77
  338. package/docs/whitepaper-v2.1.md +0 -609
  339. package/docs/whitepaper-v2.2.md +0 -1064
  340. package/docs/whitepaper-v2.2.pdf +0 -0
  341. package/fly.toml +0 -31
  342. package/public/dashboard.html +0 -119
  343. package/server/hub.js +0 -116
  344. package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
  345. package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
  346. package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
  347. package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
  348. package/test/replay-golden.ts +0 -84
  349. package/test_benchmark.js +0 -165
  350. package/test_comprehensive.mjs +0 -638
  351. package/test_concurrency.js +0 -129
  352. package/test_ir_robustness.js +0 -85
  353. package/test_semantic_contracts.js +0 -269
  354. package/test_ssg_stress.js +0 -156
  355. package/test_svl3.js +0 -58
  356. package/tsconfig.json +0 -17
@@ -0,0 +1,402 @@
1
+ "use strict";
2
+ /**
3
+ * P2.5 Telemetry + Analytics + Benchmark Integration Tests
4
+ *
5
+ * Verifies:
6
+ * 1. PlannerTelemetry records decisions and feedback
7
+ * 2. Acceptance dashboard produces correct aggregates
8
+ * 3. Benchmark harness runs against known fixtures
9
+ * 4. 1000 simulated decisions produce a coherent dashboard
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const vitest_1 = require("vitest");
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const planner_telemetry_1 = require("./planner-telemetry");
49
+ const analytics_1 = require("./analytics");
50
+ const benchmark_harness_1 = require("./benchmark-harness");
51
+ // ═══════════════════════════════════════════════════════════════
52
+ // Candidate ID
53
+ // ═══════════════════════════════════════════════════════════════
54
+ (0, vitest_1.describe)("Candidate Fingerprint v2", () => {
55
+ (0, vitest_1.it)("produces stable hash for same action sequence", () => {
56
+ (0, vitest_1.expect)((0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "close_file"]))
57
+ .toBe((0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "close_file"]));
58
+ });
59
+ (0, vitest_1.it)("different protocol = different hash (no collision)", () => {
60
+ const a = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]);
61
+ const b = (0, planner_telemetry_1.candidateFingerprint)("AuthProtocol", ["close_file"]);
62
+ (0, vitest_1.expect)(a).not.toBe(b);
63
+ });
64
+ (0, vitest_1.it)("different violationType = different hash", () => {
65
+ const a = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"], "resource_leak");
66
+ const b = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"], "missing_prerequisite");
67
+ (0, vitest_1.expect)(a).not.toBe(b);
68
+ });
69
+ (0, vitest_1.it)("different functions = different hash", () => {
70
+ (0, vitest_1.expect)((0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]))
71
+ .not.toBe((0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["flush"]));
72
+ });
73
+ });
74
+ // ═══════════════════════════════════════════════════════════════
75
+ // Telemetry: record → query roundtrip
76
+ // ═══════════════════════════════════════════════════════════════
77
+ const TELEMETRY_DIR = path.resolve(__dirname, "..", "test-telemetry");
78
+ process.env.PROGMUNE_PROJECT_DIR = TELEMETRY_DIR;
79
+ fs.mkdirSync(TELEMETRY_DIR, { recursive: true });
80
+ fs.mkdirSync(path.join(TELEMETRY_DIR, ".progmune_corpus", "telemetry"), { recursive: true });
81
+ function createTelemetry() {
82
+ return new planner_telemetry_1.PlannerTelemetry(path.join(TELEMETRY_DIR, ".progmune_corpus", "telemetry", `test-${Date.now()}.jsonl`));
83
+ }
84
+ (0, vitest_1.describe)("PlannerTelemetry", () => {
85
+ (0, vitest_1.it)("records a decision and returns an ID", () => {
86
+ const t = createTelemetry();
87
+ const id = t.recordDecision({
88
+ goal: "safely write config file",
89
+ protocol: "FileProtocol",
90
+ candidates: [{
91
+ candidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]),
92
+ source: "protocol",
93
+ evidenceSources: ["protocol"],
94
+ actions: ["close_file"],
95
+ explanation: "Close the file",
96
+ }],
97
+ selectedCandidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]),
98
+ });
99
+ (0, vitest_1.expect)(id).toMatch(/^PD-/);
100
+ (0, vitest_1.expect)(t.size).toBe(1);
101
+ (0, vitest_1.expect)(t.withFeedback).toBe(0);
102
+ });
103
+ (0, vitest_1.it)("records accepted feedback and updates acceptance rate", () => {
104
+ const t = createTelemetry();
105
+ const id = t.recordDecision({
106
+ goal: "authenticate user",
107
+ protocol: "AuthProtocol",
108
+ candidates: [{
109
+ candidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["verify_password"]),
110
+ source: "protocol",
111
+ evidenceSources: ["protocol"],
112
+ actions: ["verify_password", "generate_jwt"],
113
+ explanation: "Full auth flow",
114
+ }],
115
+ selectedCandidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["verify_password"]),
116
+ });
117
+ t.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, userReason: "safer", timestamp: Date.now() });
118
+ (0, vitest_1.expect)(t.withFeedback).toBe(1);
119
+ (0, vitest_1.expect)(t.getAcceptanceRate()).toBe(1.0);
120
+ });
121
+ (0, vitest_1.it)("records rejected feedback", () => {
122
+ const t = createTelemetry();
123
+ const id = t.recordDecision({
124
+ goal: "write file unsafely",
125
+ protocol: "FileProtocol",
126
+ candidates: [{
127
+ candidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["write_file"]),
128
+ source: "antibody",
129
+ evidenceSources: ["antibody"],
130
+ actions: ["write_file"],
131
+ explanation: "Just write",
132
+ }],
133
+ selectedCandidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["write_file"]),
134
+ });
135
+ t.recordFeedback(id, { decision: "rejected", userReason: "irrelevant", timestamp: Date.now() });
136
+ (0, vitest_1.expect)(t.withFeedback).toBe(1);
137
+ (0, vitest_1.expect)(t.getAcceptanceRate()).toBe(0.0);
138
+ });
139
+ (0, vitest_1.it)("records execution result with latency", () => {
140
+ const t = createTelemetry();
141
+ const id = t.recordDecision({
142
+ goal: "quick operation",
143
+ protocol: "FileProtocol",
144
+ candidates: [{
145
+ candidateId: "q",
146
+ source: "corpus",
147
+ evidenceSources: ["corpus"],
148
+ actions: ["flush"],
149
+ explanation: "Quick flush",
150
+ }],
151
+ });
152
+ t.recordExecutionResult(id, true, [], 42);
153
+ const events = t.all();
154
+ const ev = events.find(e => e.id === id);
155
+ (0, vitest_1.expect)(ev?.feedback?.executionResult?.success).toBe(true);
156
+ (0, vitest_1.expect)(ev?.cost?.latencyMs).toBe(42);
157
+ });
158
+ });
159
+ // ═══════════════════════════════════════════════════════════════
160
+ // Telemetry: aggregation queries
161
+ // ═══════════════════════════════════════════════════════════════
162
+ (0, vitest_1.describe)("Telemetry aggregation", () => {
163
+ (0, vitest_1.it)("getAcceptanceBySource breaks down by strategy", () => {
164
+ const t = createTelemetry();
165
+ // Corpus: 2 accepted out of 2
166
+ for (let i = 0; i < 2; i++) {
167
+ const id = t.recordDecision({
168
+ goal: "test",
169
+ protocol: "FileProtocol",
170
+ candidates: [{
171
+ candidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]),
172
+ source: "corpus",
173
+ evidenceSources: ["corpus"],
174
+ actions: ["close_file"],
175
+ explanation: "close",
176
+ }],
177
+ selectedCandidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]),
178
+ });
179
+ t.recordFeedback(id, { decision: "accepted", userReason: "safer", timestamp: Date.now() });
180
+ }
181
+ // Protocol: 1 accepted out of 1
182
+ const pid = t.recordDecision({
183
+ goal: "test",
184
+ protocol: "FileProtocol",
185
+ candidates: [{
186
+ candidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]),
187
+ source: "protocol",
188
+ evidenceSources: ["protocol"],
189
+ actions: ["close_file"],
190
+ explanation: "close",
191
+ }],
192
+ selectedCandidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]),
193
+ });
194
+ t.recordFeedback(pid, { decision: "accepted", userReason: "faster", timestamp: Date.now() });
195
+ // Antibody: 0 accepted out of 1
196
+ const aid = t.recordDecision({
197
+ goal: "test",
198
+ protocol: "FileProtocol",
199
+ candidates: [{
200
+ candidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["flush"]),
201
+ source: "antibody",
202
+ evidenceSources: ["antibody"],
203
+ actions: ["flush"],
204
+ explanation: "flush instead",
205
+ }],
206
+ selectedCandidateId: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["flush"]),
207
+ });
208
+ t.recordFeedback(aid, { decision: "rejected", userReason: "incorrect", timestamp: Date.now() });
209
+ const stats = (0, analytics_1.getStrategyStats)(t);
210
+ (0, vitest_1.expect)(stats.length).toBe(3);
211
+ const corpus = stats.find(s => s.strategy === "corpus");
212
+ (0, vitest_1.expect)(corpus.rate).toBe(1.0); // 100%
213
+ (0, vitest_1.expect)(corpus.accepted).toBe(2);
214
+ const protocol = stats.find(s => s.strategy === "protocol");
215
+ (0, vitest_1.expect)(protocol.rate).toBe(1.0);
216
+ const antibody = stats.find(s => s.strategy === "antibody");
217
+ (0, vitest_1.expect)(antibody.rate).toBe(0.0);
218
+ });
219
+ (0, vitest_1.it)("getTopAcceptedRepairs returns ranked list", () => {
220
+ const t = createTelemetry();
221
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]);
222
+ for (let i = 0; i < 3; i++) {
223
+ const id = t.recordDecision({
224
+ goal: "safely write config file",
225
+ protocol: "FileProtocol",
226
+ candidates: [{
227
+ candidateId: fp,
228
+ source: "corpus",
229
+ evidenceSources: ["corpus", "protocol"],
230
+ actions: ["close_file"],
231
+ explanation: "close",
232
+ }],
233
+ selectedCandidateId: fp,
234
+ });
235
+ t.recordFeedback(id, { decision: "accepted", userReason: "safer", timestamp: Date.now() });
236
+ }
237
+ const tops = (0, analytics_1.getTopAcceptedRepairs)(t);
238
+ (0, vitest_1.expect)(tops.length).toBeGreaterThanOrEqual(1);
239
+ (0, vitest_1.expect)(tops[0].actions).toBe("close_file");
240
+ (0, vitest_1.expect)(tops[0].count).toBe(3);
241
+ (0, vitest_1.expect)(tops[0].goal).toBe("safely write config file");
242
+ });
243
+ });
244
+ // ═══════════════════════════════════════════════════════════════
245
+ // Dashboard
246
+ // ═══════════════════════════════════════════════════════════════
247
+ (0, vitest_1.describe)("Acceptance Dashboard", () => {
248
+ (0, vitest_1.it)("generates a complete dashboard report", () => {
249
+ const t = createTelemetry();
250
+ // Seed with FileProtocol decisions
251
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"]);
252
+ for (let i = 0; i < 5; i++) {
253
+ const id = t.recordDecision({
254
+ goal: "safely write config file",
255
+ protocol: "FileProtocol",
256
+ candidates: [{
257
+ candidateId: fp,
258
+ source: i < 4 ? "corpus" : "protocol",
259
+ evidenceSources: i < 4 ? ["corpus"] : ["protocol"],
260
+ actions: ["close_file"],
261
+ explanation: "close",
262
+ }],
263
+ selectedCandidateId: fp,
264
+ });
265
+ if (i < 4)
266
+ t.recordFeedback(id, { decision: "accepted", userReason: "safer", timestamp: Date.now() });
267
+ else
268
+ t.recordFeedback(id, { decision: "rejected", userReason: "incorrect", timestamp: Date.now() });
269
+ }
270
+ // Seed with AuthProtocol
271
+ const ap = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["verify_password"]);
272
+ for (let i = 0; i < 3; i++) {
273
+ const id = t.recordDecision({
274
+ goal: "authenticate user",
275
+ protocol: "AuthProtocol",
276
+ candidates: [{
277
+ candidateId: ap,
278
+ source: "corpus",
279
+ evidenceSources: ["corpus", "protocol"],
280
+ actions: ["verify_password", "generate_jwt"],
281
+ explanation: "auth flow",
282
+ }],
283
+ selectedCandidateId: ap,
284
+ });
285
+ t.recordFeedback(id, { decision: "accepted", userReason: "safer", timestamp: Date.now() });
286
+ }
287
+ const report = (0, analytics_1.generateDashboard)(t);
288
+ (0, vitest_1.expect)(report.summary.totalDecisions).toBe(8);
289
+ (0, vitest_1.expect)(report.summary.withFeedback).toBe(8);
290
+ // 7 accepted out of 8 = 87.5%
291
+ (0, vitest_1.expect)(report.summary.overallAcceptanceRate).toBe(7 / 8);
292
+ (0, vitest_1.expect)(report.byProtocol.length).toBe(2);
293
+ const fileProto = report.byProtocol.find(p => p.protocol === "FileProtocol");
294
+ (0, vitest_1.expect)(fileProto.rate).toBe(4 / 5);
295
+ const authProto = report.byProtocol.find(p => p.protocol === "AuthProtocol");
296
+ (0, vitest_1.expect)(authProto.rate).toBe(1.0);
297
+ (0, vitest_1.expect)(report.topAccepted.length).toBeGreaterThan(0);
298
+ (0, vitest_1.expect)(report.topRejected.length).toBeGreaterThan(0);
299
+ // Dashboard prints without crashing
300
+ (0, analytics_1.printDashboard)(t);
301
+ });
302
+ });
303
+ // ═══════════════════════════════════════════════════════════════
304
+ // Benchmark harness
305
+ // ═══════════════════════════════════════════════════════════════
306
+ (0, vitest_1.describe)("Benchmark harness", () => {
307
+ (0, vitest_1.it)("runs against benchmark fixtures and produces report", async () => {
308
+ const report = await (0, benchmark_harness_1.runBenchmark)();
309
+ (0, vitest_1.expect)(report.cases).toBeGreaterThanOrEqual(5);
310
+ (0, vitest_1.expect)(report.top1Rate).toBeGreaterThanOrEqual(0);
311
+ (0, vitest_1.expect)(report.top1Rate).toBeLessThanOrEqual(1);
312
+ (0, vitest_1.expect)(report.top3Rate).toBeGreaterThanOrEqual(0);
313
+ (0, vitest_1.expect)(report.top3Rate).toBeLessThanOrEqual(1);
314
+ (0, vitest_1.expect)(report.avgLatencyMs).toBeGreaterThan(0);
315
+ (0, vitest_1.expect)(report.avgCandidates).toBeGreaterThan(0);
316
+ // Print for visual inspection
317
+ (0, benchmark_harness_1.printBenchmarkReport)(report);
318
+ }, 30000);
319
+ });
320
+ // ═══════════════════════════════════════════════════════════════
321
+ // 1000 simulated decisions → coherent dashboard
322
+ // ═══════════════════════════════════════════════════════════════
323
+ (0, vitest_1.describe)("1000-simulated-decisions smoke test", () => {
324
+ (0, vitest_1.it)("produces coherent dashboard after 1000 simulated decisions", () => {
325
+ const t = createTelemetry();
326
+ const strategies = ["corpus", "protocol", "antibody"];
327
+ const protocols = ["FileProtocol", "AuthProtocol", "DBProtocol", "IRProtocol"];
328
+ const goals = {
329
+ FileProtocol: ["safely write config file", "read file and close it", "append and close file"],
330
+ AuthProtocol: ["authenticate user", "create user session", "verify and logout"],
331
+ DBProtocol: ["connect and query", "insert record safely", "migrate and clean up"],
332
+ IRProtocol: ["extract and validate", "emit validated code", "record session"],
333
+ };
334
+ const repairs = {
335
+ FileProtocol: ["open_file→write_file→close_file", "open_file→read_file→close_file", "open_file→append→close_file"],
336
+ AuthProtocol: ["verify_password→generate_jwt→create_session", "verify_password→generate_jwt→logout", "verify_password→create_session→logout"],
337
+ DBProtocol: ["connect_db→query_db→disconnect_db", "connect_db→insert→disconnect_db", "connect_db→migrate→disconnect_db"],
338
+ IRProtocol: ["extractIR→validateAction", "validateActionSequence→emitCode", "extractIR→emitCode→recordSession"],
339
+ };
340
+ // Acceptance probabilities per strategy (matching expected hierarchy)
341
+ const acceptProb = { corpus: 0.90, protocol: 0.84, antibody: 0.72 };
342
+ for (let i = 0; i < 1000; i++) {
343
+ const protocol = protocols[i % protocols.length];
344
+ const goalList = goals[protocol];
345
+ const repairList = repairs[protocol];
346
+ const goal = goalList[i % goalList.length];
347
+ const repair = repairList[i % repairList.length];
348
+ const source = strategies[i % strategies.length];
349
+ const cid = (0, planner_telemetry_1.candidateFingerprint)(protocol, repair.split("→"));
350
+ const id = t.recordDecision({
351
+ goal,
352
+ protocol,
353
+ candidates: [{
354
+ candidateId: cid,
355
+ source,
356
+ evidenceSources: [source],
357
+ actions: repair.split("→"),
358
+ explanation: `Repair: ${repair}`,
359
+ }],
360
+ selectedCandidateId: cid,
361
+ cost: { latencyMs: 2 + Math.random() * 10, actionCount: repair.split("→").length },
362
+ });
363
+ // Accept with strategy-specific probability
364
+ if (Math.random() < acceptProb[source]) {
365
+ const reasons = ["safer", "faster", "clearer", "more_auditable"];
366
+ const reason = reasons[Math.floor(Math.random() * reasons.length)];
367
+ const rating = (reason === "safer" || reason === "faster") ? (4 + Math.floor(Math.random() * 2)) : (3 + Math.floor(Math.random() * 2));
368
+ t.recordFeedback(id, { decision: "accepted", userReason: reason, timestamp: Date.now() });
369
+ }
370
+ else {
371
+ t.recordFeedback(id, { decision: "rejected", userReason: Math.random() < 0.5 ? "incorrect" : "irrelevant", timestamp: Date.now() });
372
+ }
373
+ }
374
+ // Verify coherence
375
+ const report = (0, analytics_1.generateDashboard)(t);
376
+ (0, vitest_1.expect)(report.summary.totalDecisions).toBe(1000);
377
+ (0, vitest_1.expect)(report.summary.withFeedback).toBe(1000);
378
+ // Overall acceptance should be between 72% and 90%
379
+ (0, vitest_1.expect)(report.summary.overallAcceptanceRate).toBeGreaterThan(0.70);
380
+ (0, vitest_1.expect)(report.summary.overallAcceptanceRate).toBeLessThan(0.92);
381
+ // Strategy hierarchy: corpus > protocol > antibody
382
+ const stratStats = (0, analytics_1.getStrategyStats)(t);
383
+ const corpus = stratStats.find(s => s.strategy === "corpus");
384
+ const protocol = stratStats.find(s => s.strategy === "protocol");
385
+ const antibody = stratStats.find(s => s.strategy === "antibody");
386
+ (0, vitest_1.expect)(corpus.rate).toBeGreaterThan(protocol.rate);
387
+ (0, vitest_1.expect)(protocol.rate).toBeGreaterThan(antibody.rate);
388
+ // Top accepted repair should be present
389
+ const topAccepted = (0, analytics_1.getTopAcceptedRepairs)(t, 3);
390
+ (0, vitest_1.expect)(topAccepted.length).toBeGreaterThanOrEqual(3);
391
+ // Top rejected repair should be present
392
+ const topRejected = (0, analytics_1.getTopRejectedRepairs)(t, 3);
393
+ (0, vitest_1.expect)(topRejected.length).toBeGreaterThanOrEqual(3);
394
+ // Print dashboard for visual confirmation
395
+ (0, analytics_1.printDashboard)(t);
396
+ // Also print strategy stats as table
397
+ console.log("\nStrategy Acceptance (1000 decisions):");
398
+ for (const s of stratStats) {
399
+ console.log(` ${s.strategy.padEnd(16)} ${(s.rate * 100).toFixed(0)}% (${s.accepted}/${s.total})`);
400
+ }
401
+ });
402
+ });
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Terminal formatting utilities shared across observability modules.
4
+ * ANSI color helpers, padding, charts, and badge rendering.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.B = exports.D = exports.C_ = exports.Y = exports.R = exports.G = exports.COLORS = void 0;
8
+ exports.pad = pad;
9
+ exports.barChart = barChart;
10
+ exports.aclBadge = aclBadge;
11
+ exports.svlLabel = svlLabel;
12
+ exports.describeSVLLayer = describeSVLLayer;
13
+ // ── ANSI colors ──
14
+ exports.COLORS = { reset: "\x1b[0m", green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m", gray: "\x1b[90m", bold: "\x1b[1m", dim: "\x1b[2m" };
15
+ const C = exports.COLORS;
16
+ const G = (s) => `${C.green}${s}${C.reset}`;
17
+ exports.G = G;
18
+ const R = (s) => `${C.red}${s}${C.reset}`;
19
+ exports.R = R;
20
+ const Y = (s) => `${C.yellow}${s}${C.reset}`;
21
+ exports.Y = Y;
22
+ const C_ = (s) => `${C.cyan}${s}${C.reset}`;
23
+ exports.C_ = C_;
24
+ const D = (s) => `${C.gray}${s}${C.reset}`;
25
+ exports.D = D;
26
+ const B = (s) => `${C.bold}${s}${C.reset}`;
27
+ exports.B = B;
28
+ function pad(s, w) {
29
+ let visual = 0;
30
+ for (const ch of s) {
31
+ visual += /[\x1b]/.test(ch) ? 0 : (ch.charCodeAt(0) > 127 ? 2 : 1);
32
+ }
33
+ return s + " ".repeat(Math.max(0, w - visual));
34
+ }
35
+ function barChart(count, total) {
36
+ const pct = total > 0 ? Math.round((count / total) * 100) : 0;
37
+ const barLen = Math.max(1, Math.round(pct / 5));
38
+ const bar = "█".repeat(barLen);
39
+ const empty = "░".repeat(20 - barLen);
40
+ return `${bar}${empty} ${pct}% (${count}/${total})`;
41
+ }
42
+ function aclBadge(level) {
43
+ switch (level) {
44
+ case "ACL-4": return (0, exports.G)("◆ ACL-4");
45
+ case "ACL-3": return (0, exports.C_)("◇ ACL-3");
46
+ case "ACL-2": return (0, exports.Y)("○ ACL-2");
47
+ case "ACL-1": return (0, exports.D)("· ACL-1");
48
+ default: return (0, exports.D)(`? ${level}`);
49
+ }
50
+ }
51
+ function svlLabel(svl) {
52
+ switch (svl) {
53
+ case "SVL-1": return (0, exports.Y)("SVL-1");
54
+ case "SVL-2": return (0, exports.Y)("SVL-2");
55
+ case "SVL-3": return (0, exports.R)("SVL-3");
56
+ case "SVL-4": return (0, exports.R)("SVL-4");
57
+ default: return svl;
58
+ }
59
+ }
60
+ function describeSVLLayer(svl) {
61
+ switch (svl) {
62
+ case "SVL-1": return "符号存在性(禁止幻觉API)";
63
+ case "SVL-2": return "类型有效性(参数类型/数量匹配)";
64
+ case "SVL-3": return "数据流正确性(变量定义/循环引用)";
65
+ case "SVL-4": return "协议合法性(状态机)";
66
+ default: return "未知";
67
+ }
68
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Unit tests for terminal-format.ts — pure formatting functions.
5
+ */
6
+ const vitest_1 = require("vitest");
7
+ const terminal_format_1 = require("./terminal-format");
8
+ (0, vitest_1.describe)("color helpers", () => {
9
+ (0, vitest_1.it)("G wraps text in green ANSI codes", () => {
10
+ (0, vitest_1.expect)((0, terminal_format_1.G)("OK")).toContain(terminal_format_1.COLORS.green);
11
+ (0, vitest_1.expect)((0, terminal_format_1.G)("OK")).toContain(terminal_format_1.COLORS.reset);
12
+ });
13
+ (0, vitest_1.it)("R wraps text in red ANSI codes", () => {
14
+ (0, vitest_1.expect)((0, terminal_format_1.R)("ERR")).toContain(terminal_format_1.COLORS.red);
15
+ });
16
+ (0, vitest_1.it)("Y wraps text in yellow ANSI codes", () => {
17
+ (0, vitest_1.expect)((0, terminal_format_1.Y)("WARN")).toContain(terminal_format_1.COLORS.yellow);
18
+ });
19
+ (0, vitest_1.it)("B wraps text in bold ANSI codes", () => {
20
+ (0, vitest_1.expect)((0, terminal_format_1.B)("TITLE")).toContain(terminal_format_1.COLORS.bold);
21
+ });
22
+ (0, vitest_1.it)("D wraps text in gray", () => {
23
+ (0, vitest_1.expect)((0, terminal_format_1.D)("dim")).toContain(terminal_format_1.COLORS.gray);
24
+ });
25
+ (0, vitest_1.it)("C_ wraps text in cyan", () => {
26
+ (0, vitest_1.expect)((0, terminal_format_1.C_)("info")).toContain(terminal_format_1.COLORS.cyan);
27
+ });
28
+ });
29
+ (0, vitest_1.describe)("pad", () => {
30
+ (0, vitest_1.it)("pads short string to given width", () => {
31
+ (0, vitest_1.expect)((0, terminal_format_1.pad)("ab", 5).length).toBeGreaterThanOrEqual(5);
32
+ });
33
+ (0, vitest_1.it)("does not truncate longer strings", () => {
34
+ const result = (0, terminal_format_1.pad)("hello world", 5);
35
+ (0, vitest_1.expect)(result.length).toBeGreaterThanOrEqual(11);
36
+ });
37
+ });
38
+ (0, vitest_1.describe)("barChart", () => {
39
+ (0, vitest_1.it)("shows full bar at 100%", () => {
40
+ const chart = (0, terminal_format_1.barChart)(10, 10);
41
+ (0, vitest_1.expect)(chart).toContain("100%");
42
+ (0, vitest_1.expect)(chart).toContain("█");
43
+ });
44
+ (0, vitest_1.it)("shows 0% for zero count", () => {
45
+ const chart = (0, terminal_format_1.barChart)(0, 10);
46
+ (0, vitest_1.expect)(chart).toContain("0%");
47
+ });
48
+ (0, vitest_1.it)("returns a non-empty string", () => {
49
+ (0, vitest_1.expect)((0, terminal_format_1.barChart)(5, 10).length).toBeGreaterThan(0);
50
+ });
51
+ });
52
+ (0, vitest_1.describe)("aclBadge", () => {
53
+ (0, vitest_1.it)("returns green for ACL-4", () => {
54
+ const badge = (0, terminal_format_1.aclBadge)("ACL-4");
55
+ (0, vitest_1.expect)(badge).toContain("ACL-4");
56
+ });
57
+ (0, vitest_1.it)("returns dim for unknown level", () => {
58
+ const badge = (0, terminal_format_1.aclBadge)("UNKNOWN");
59
+ (0, vitest_1.expect)(badge.length).toBeGreaterThan(0);
60
+ });
61
+ });
62
+ (0, vitest_1.describe)("svlLabel", () => {
63
+ (0, vitest_1.it)("returns colored SVL-1", () => {
64
+ (0, vitest_1.expect)((0, terminal_format_1.svlLabel)("SVL-1")).toContain("SVL-1");
65
+ });
66
+ (0, vitest_1.it)("returns colored SVL-4", () => {
67
+ (0, vitest_1.expect)((0, terminal_format_1.svlLabel)("SVL-4")).toContain("SVL-4");
68
+ });
69
+ (0, vitest_1.it)("returns raw string for unknown SVL", () => {
70
+ (0, vitest_1.expect)((0, terminal_format_1.svlLabel)("SVL-99")).toBe("SVL-99");
71
+ });
72
+ });
73
+ (0, vitest_1.describe)("describeSVLLayer", () => {
74
+ (0, vitest_1.it)("describes SVL-1 in Chinese", () => {
75
+ (0, vitest_1.expect)((0, terminal_format_1.describeSVLLayer)("SVL-1")).toContain("符号");
76
+ });
77
+ (0, vitest_1.it)("describes SVL-4 as protocol", () => {
78
+ (0, vitest_1.expect)((0, terminal_format_1.describeSVLLayer)("SVL-4")).toContain("协议");
79
+ });
80
+ (0, vitest_1.it)("returns 未知 for unknown level", () => {
81
+ (0, vitest_1.expect)((0, terminal_format_1.describeSVLLayer)("NOPE")).toBe("未知");
82
+ });
83
+ });