progmune-runtime 2.1.6 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/README.md +119 -461
  2. package/dist/ablation-study.js +144 -0
  3. package/dist/ablation-study.test.js +18 -0
  4. package/dist/action-runtime.js +3 -1
  5. package/dist/active-learning.js +211 -0
  6. package/dist/analytics.js +139 -0
  7. package/dist/asset-factory.js +309 -0
  8. package/dist/asset-growth.js +244 -0
  9. package/dist/asset-promotion.js +382 -0
  10. package/dist/asset-quality.js +550 -0
  11. package/dist/audit/business-translator.js +285 -0
  12. package/dist/audit/cli.js +66 -0
  13. package/dist/audit/formatters/html.js +379 -0
  14. package/dist/audit/formatters/json.js +11 -0
  15. package/dist/audit/formatters/markdown.js +192 -0
  16. package/dist/audit/formatters/terminal.js +189 -0
  17. package/dist/audit/index.js +25 -0
  18. package/dist/audit/report-builder.js +318 -0
  19. package/dist/audit/types.js +8 -0
  20. package/dist/audit.js +3 -3
  21. package/dist/auto-benchmark-generator.js +137 -0
  22. package/dist/auto-benchmark-generator.test.js +45 -0
  23. package/dist/auto-protocol-synthesizer.js +362 -0
  24. package/dist/auto-protocol-synthesizer.test.js +82 -0
  25. package/dist/autonomous-patch.js +175 -0
  26. package/dist/autonomous-patch.test.js +128 -0
  27. package/dist/badge/badge-server.js +98 -0
  28. package/dist/behavior-miner.js +442 -0
  29. package/dist/belief-layer.js +475 -0
  30. package/dist/benchmark-count.js +5 -0
  31. package/dist/benchmark-generator.js +211 -0
  32. package/dist/benchmark-harness.js +201 -0
  33. package/dist/benchmark-pass-rate.js +7 -0
  34. package/dist/benchmark-report.js +8 -3
  35. package/dist/benchmark-save.js +14 -1
  36. package/dist/bootstrap-validation.js +197 -0
  37. package/dist/bootstrap-validation.test.js +51 -0
  38. package/dist/branch-ledger.js +1 -1
  39. package/dist/capability-gap.js +130 -0
  40. package/dist/certify-html.js +351 -0
  41. package/dist/certify.js +326 -0
  42. package/dist/check.js +4 -4
  43. package/dist/compliance-miner.js +447 -0
  44. package/dist/continuous-benchmark.js +194 -0
  45. package/dist/continuous-benchmark.test.js +116 -0
  46. package/dist/corpus-stats.js +173 -0
  47. package/dist/counterfactual-engine.js +288 -0
  48. package/dist/coverage-dashboard.js +109 -0
  49. package/dist/coverage-system.test.js +205 -0
  50. package/dist/cross-repo-precision.js +352 -0
  51. package/dist/cve-benchmark.js +180 -0
  52. package/dist/cve-benchmark.test.js +28 -0
  53. package/dist/cve-collector.js +73 -0
  54. package/dist/data-quality.js +141 -0
  55. package/dist/decision-engine.js +388 -0
  56. package/dist/derive-metadata.js +250 -0
  57. package/dist/difficulty-active.test.js +198 -0
  58. package/dist/difficulty-map.js +244 -0
  59. package/dist/discovery-analytics.js +125 -0
  60. package/dist/discovery-model.js +149 -0
  61. package/dist/discovery-optimize.test.js +199 -0
  62. package/dist/discovery-trace.js +276 -0
  63. package/dist/discovery-trace.test.js +97 -0
  64. package/dist/emitter.js +83 -1
  65. package/dist/enterprise-dashboard.js +405 -0
  66. package/dist/eval-hardening.js +297 -0
  67. package/dist/eval-hardening.test.js +85 -0
  68. package/dist/evaluation-campaign.js +359 -0
  69. package/dist/evaluation-campaign.test.js +181 -0
  70. package/dist/evidence-growth.js +143 -0
  71. package/dist/evidence-repository.js +209 -0
  72. package/dist/evidence-system.js +441 -0
  73. package/dist/execute.js +15 -7
  74. package/dist/experimental/software-physics.js +291 -0
  75. package/dist/experimental/state-inference.js +516 -0
  76. package/dist/experimental/unsupervised-physics.js +230 -0
  77. package/dist/extract-ir-python.js +54 -7
  78. package/dist/extract-ir.js +376 -12
  79. package/dist/failure-collector.js +2 -2
  80. package/dist/failure-corpus.js +322 -9
  81. package/dist/feedback.js +16 -5
  82. package/dist/feedback.test.js +49 -0
  83. package/dist/file-lock.js +1 -1
  84. package/dist/flywheel-batch.js +292 -0
  85. package/dist/frameworks/express-cli.js +237 -0
  86. package/dist/frameworks/express-detector.js +445 -0
  87. package/dist/frameworks/express-detector.test.js +206 -0
  88. package/dist/frameworks/index.js +30 -0
  89. package/dist/frameworks/nestjs-detector.js +302 -0
  90. package/dist/frameworks/trpc-detector.js +161 -0
  91. package/dist/frameworks/version-awareness.js +179 -0
  92. package/dist/function-synonyms.js +164 -0
  93. package/dist/function-synonyms.test.js +68 -0
  94. package/dist/generalization.test.js +352 -0
  95. package/dist/goal-annotator.js +113 -0
  96. package/dist/goal-planner.js +563 -0
  97. package/dist/gold-cve.js +164 -0
  98. package/dist/gold-cve.test.js +104 -0
  99. package/dist/gold-quality.js +206 -0
  100. package/dist/gold-tiers.js +241 -0
  101. package/dist/governance-dashboard.js +327 -0
  102. package/dist/graph-viz.js +240 -0
  103. package/dist/guided-frontier.js +195 -0
  104. package/dist/hierarchical-planner.js +148 -0
  105. package/dist/identifier-parser.js +260 -0
  106. package/dist/immune-metrics.js +93 -0
  107. package/dist/immune-receiver.js +158 -0
  108. package/dist/immune-reporter.js +1 -1
  109. package/dist/improvement-orchestrator.js +206 -0
  110. package/dist/inject-p0-vocabulary.js +300 -0
  111. package/dist/intent-parser.js +218 -0
  112. package/dist/invariant-algebra.js +476 -0
  113. package/dist/invariant-calculus.js +533 -0
  114. package/dist/ir-utils.js +70 -0
  115. package/dist/ir-utils.test.js +50 -0
  116. package/dist/knowledge-api.js +312 -0
  117. package/dist/knowledge-evolution.js +452 -0
  118. package/dist/knowledge-explorer.js +506 -0
  119. package/dist/knowledge-flywheel.js +274 -0
  120. package/dist/knowledge-governance.js +338 -0
  121. package/dist/knowledge-governance.test.js +150 -0
  122. package/dist/knowledge-graph.js +181 -0
  123. package/dist/knowledge-guided-synth.js +246 -0
  124. package/dist/knowledge-loop.test.js +77 -0
  125. package/dist/knowledge-object.js +316 -0
  126. package/dist/knowledge-package.js +98 -0
  127. package/dist/kpi-dashboard.js +561 -0
  128. package/dist/l3-cross-function.js +280 -0
  129. package/dist/learning-ranker.js +148 -0
  130. package/dist/learning-ranker.test.js +291 -0
  131. package/dist/ledger/accountability.js +322 -0
  132. package/dist/ledger/chain-builder.js +185 -0
  133. package/dist/ledger/cli.js +222 -0
  134. package/dist/ledger/index.js +13 -0
  135. package/dist/ledger/signatures.js +193 -0
  136. package/dist/ledger/types.js +9 -0
  137. package/dist/llm.js +74 -3
  138. package/dist/load-benchmarks.js +8 -3
  139. package/dist/logger.js +66 -0
  140. package/dist/logger.test.js +37 -0
  141. package/dist/logistic-reward.js +339 -0
  142. package/dist/logistic-reward.test.js +180 -0
  143. package/dist/macro-graph.js +193 -0
  144. package/dist/macro-repair.js +183 -0
  145. package/dist/mcp-server.mjs +1202 -483
  146. package/dist/memory-layer.js +42 -5
  147. package/dist/multi-repo-precision.js +422 -0
  148. package/dist/name-free-protocol.js +425 -0
  149. package/dist/name-free-protocol.test.js +170 -0
  150. package/dist/name-scrambling.js +138 -0
  151. package/dist/name-scrambling.test.js +16 -0
  152. package/dist/p3-observability.test.js +281 -0
  153. package/dist/p5-orchestrator.test.js +225 -0
  154. package/dist/pairwise-preference.js +294 -0
  155. package/dist/pairwise-preference.test.js +140 -0
  156. package/dist/planner-constraints.js +104 -0
  157. package/dist/planner-prompts.js +155 -0
  158. package/dist/planner-telemetry.js +415 -0
  159. package/dist/planner-trace.js +214 -0
  160. package/dist/planner.js +162 -167
  161. package/dist/plsb/artifact.js +116 -0
  162. package/dist/plsb/cli.js +71 -0
  163. package/dist/plsb/index.js +19 -0
  164. package/dist/plsb/leaderboard.js +249 -0
  165. package/dist/plsb/report-md.js +156 -0
  166. package/dist/plsb/schema.js +179 -0
  167. package/dist/plsb-benchmark.js +284 -0
  168. package/dist/plsb-benchmark.test.js +119 -0
  169. package/dist/policy/cli.js +134 -0
  170. package/dist/policy/engine.js +333 -0
  171. package/dist/policy/index.js +12 -0
  172. package/dist/policy/types.js +59 -0
  173. package/dist/policy-miner.js +505 -0
  174. package/dist/precision-analyze.js +229 -0
  175. package/dist/precision-benchmark.js +147 -0
  176. package/dist/precision-label-c.js +134 -0
  177. package/dist/precision-label.js +193 -0
  178. package/dist/precision-report-c.js +149 -0
  179. package/dist/precision-report.js +246 -0
  180. package/dist/progmune-status.js +108 -0
  181. package/dist/proof-engine.js +479 -0
  182. package/dist/proof-provenance.js +315 -0
  183. package/dist/protocol-coverage.js +294 -0
  184. package/dist/protocol-detector.js +1189 -0
  185. package/dist/protocol-embedding-expanded.js +297 -0
  186. package/dist/protocol-embedding-expanded.test.js +97 -0
  187. package/dist/protocol-embedding.js +195 -0
  188. package/dist/protocol-embedding.test.js +82 -0
  189. package/dist/protocol-extractor-v2.js +354 -0
  190. package/dist/protocol-extractor-v2.test.js +140 -0
  191. package/dist/protocol-extractor.js +310 -0
  192. package/dist/protocol-extractor.test.js +113 -0
  193. package/dist/protocol-foundation.js +322 -0
  194. package/dist/protocol-foundation.test.js +163 -0
  195. package/dist/protocol-frontier.js +243 -0
  196. package/dist/protocol-frontier.test.js +92 -0
  197. package/dist/protocol-gap-analyzer.js +228 -0
  198. package/dist/protocol-gap-analyzer.test.js +49 -0
  199. package/dist/protocol-invariants.js +276 -0
  200. package/dist/protocol-invariants.test.js +111 -0
  201. package/dist/protocol-knowledge.js +464 -0
  202. package/dist/protocol-miner.js +343 -0
  203. package/dist/protocol-mining.js +207 -0
  204. package/dist/protocol-mining.test.js +37 -0
  205. package/dist/protocol-registry.js +1 -1
  206. package/dist/protocol-security-benchmark.js +222 -0
  207. package/dist/protocol-vulnerability.js +257 -0
  208. package/dist/protocol-vulnerability.test.js +60 -0
  209. package/dist/python-benchmark.js +120 -0
  210. package/dist/python-emitter.js +163 -45
  211. package/dist/python-protocol-extractor.js +187 -0
  212. package/dist/python-protocol-extractor.test.js +116 -0
  213. package/dist/realworld-benchmark.js +646 -0
  214. package/dist/realworld-benchmark.test.js +36 -0
  215. package/dist/repair-arch.test.js +411 -0
  216. package/dist/repair-evolution.test.js +454 -0
  217. package/dist/repair-executor.js +719 -0
  218. package/dist/repair-proposal.js +4 -4
  219. package/dist/repair-ranker.js +141 -0
  220. package/dist/repair-strategies.js +419 -0
  221. package/dist/repair-taxonomy.js +234 -0
  222. package/dist/repair-types.js +12 -0
  223. package/dist/repo-evaluator.js +250 -0
  224. package/dist/repo-evaluator.test.js +128 -0
  225. package/dist/resource-abstraction.js +242 -0
  226. package/dist/resource-detector.js +211 -0
  227. package/dist/result.test.js +43 -0
  228. package/dist/reward-system.js +411 -0
  229. package/dist/reward-system.test.js +175 -0
  230. package/dist/risk-model.js +215 -0
  231. package/dist/rule-miner.js +234 -7
  232. package/dist/rule-specificity.js +254 -0
  233. package/dist/runtime-types.js +27 -0
  234. package/dist/scaffold.js +208 -0
  235. package/dist/scale-collector.test.js +101 -0
  236. package/dist/scale-trajectory-collector.js +128 -0
  237. package/dist/sdk.js +250 -0
  238. package/dist/search-planner.js +4 -41
  239. package/dist/semantic-snapshot.js +1 -1
  240. package/dist/semantic-topology.js +121 -0
  241. package/dist/semantic-trace.js +310 -317
  242. package/dist/sequence-extractor.js +343 -0
  243. package/dist/skill-library.js +245 -0
  244. package/dist/skill-planner.test.js +189 -0
  245. package/dist/software-physics.js +291 -0
  246. package/dist/software-physics.test.js +81 -0
  247. package/dist/ssg-precision.js +478 -0
  248. package/dist/ssg-validator.js +71 -21
  249. package/dist/state-inference-doubleblind.test.js +160 -0
  250. package/dist/state-inference.js +516 -0
  251. package/dist/state-inference.test.js +115 -0
  252. package/dist/state-machine-fingerprint.js +345 -0
  253. package/dist/state-machine-fingerprint.test.js +120 -0
  254. package/dist/state-miner.js +386 -0
  255. package/dist/state-name-inference.js +213 -0
  256. package/dist/state-name-inference.test.js +69 -0
  257. package/dist/strategy-planner.js +262 -96
  258. package/dist/strategy-planner.test.js +135 -0
  259. package/dist/telemetry-analytics.test.js +402 -0
  260. package/dist/terminal-format.js +68 -0
  261. package/dist/terminal-format.test.js +83 -0
  262. package/dist/topology-factory.js +196 -0
  263. package/dist/topology-representation.js +242 -0
  264. package/dist/topology-representation.test.js +27 -0
  265. package/dist/trajectory-augmentation.js +254 -0
  266. package/dist/trajectory-augmentation.test.js +63 -0
  267. package/dist/trajectory-corpus.js +440 -0
  268. package/dist/trajectory-corpus.test.js +32 -0
  269. package/dist/trajectory-feedback.test.js +116 -0
  270. package/dist/transition-synthesizer.js +286 -0
  271. package/dist/transition-synthesizer.test.js +123 -0
  272. package/dist/trust/api-semantic-mapper.js +809 -0
  273. package/dist/trust/call-graph-propagator.js +225 -0
  274. package/dist/trust/cli.js +122 -0
  275. package/dist/trust/compliance-scorer.js +283 -0
  276. package/dist/trust/confidence-calculator.js +261 -0
  277. package/dist/trust/engine.js +1145 -0
  278. package/dist/trust/explainability.js +85 -0
  279. package/dist/trust/formatters/ci.js +42 -0
  280. package/dist/trust/formatters/json.js +11 -0
  281. package/dist/trust/formatters/terminal.js +152 -0
  282. package/dist/trust/index.js +39 -0
  283. package/dist/trust/phase1-verify.js +171 -0
  284. package/dist/trust/protocol-domain-validator.js +697 -0
  285. package/dist/trust/score-calculator.js +282 -0
  286. package/dist/trust/ssg-bridge.js +641 -0
  287. package/dist/trust/ssg-bridge.test.js +269 -0
  288. package/dist/trust/types.js +67 -0
  289. package/dist/trust/violation-trace.js +335 -0
  290. package/dist/trust-api.js +179 -0
  291. package/dist/trust-calibration.js +279 -0
  292. package/dist/unknown-protocol-discovery.js +339 -0
  293. package/dist/unknown-protocol-discovery.test.js +102 -0
  294. package/dist/unsupervised-physics.js +230 -0
  295. package/dist/unsupervised-physics.test.js +95 -0
  296. package/dist/utils.test.js +37 -0
  297. package/dist/validator.js +187 -10
  298. package/dist/verification-intelligence.js +475 -0
  299. package/dist/verify-api.js +432 -0
  300. package/dist/vi-impact-report.js +293 -0
  301. package/dist/wl-fingerprint.js +162 -0
  302. package/dist/wl-fingerprint.test.js +130 -0
  303. package/dist/zeroshot-strategy.js +139 -0
  304. package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
  305. package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +721 -0
  306. package/package.json +73 -6
  307. package/protocols.json +1956 -50
  308. package/.dockerignore +0 -14
  309. package/.mcp.json +0 -11
  310. package/.progmune_allowlist +0 -50
  311. package/.test_report/test_report.md +0 -87
  312. package/Dockerfile +0 -9
  313. package/FAQ.md +0 -167
  314. package/WHITEPAPER.md +0 -540
  315. package/demo-project/auth.ts +0 -55
  316. package/demo-project/tsconfig.json +0 -8
  317. package/dist/acl-breakdown.js +0 -13
  318. package/dist/all-sessions.js +0 -11
  319. package/dist/antibody-stats.js +0 -11
  320. package/dist/branch-tree-count.js +0 -14
  321. package/dist/common-fixpath.js +0 -12
  322. package/dist/constraint-types.js +0 -12
  323. package/dist/exec-metrics.js +0 -11
  324. package/dist/failure-report.js +0 -11
  325. package/dist/fast-path-hits.js +0 -13
  326. package/dist/fingerprint-list.js +0 -15
  327. package/dist/gen-history-log.js +0 -13
  328. package/dist/heatmap-data.js +0 -11
  329. package/dist/recent-session.js +0 -12
  330. package/dist/svl-distribution.js +0 -11
  331. package/dist/terminal-status.js +0 -11
  332. package/dist/token-savings.js +0 -11
  333. package/dist/total-repairs.js +0 -12
  334. package/dist/unresolved-count.js +0 -12
  335. package/dist/valid-fingerprints.js +0 -13
  336. package/dist/verify-ledgers.js +0 -11
  337. package/docs/whitepaper-style.css +0 -77
  338. package/docs/whitepaper-v2.1.md +0 -609
  339. package/docs/whitepaper-v2.2.md +0 -1064
  340. package/docs/whitepaper-v2.2.pdf +0 -0
  341. package/fly.toml +0 -31
  342. package/public/dashboard.html +0 -119
  343. package/server/hub.js +0 -116
  344. package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
  345. package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
  346. package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
  347. package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
  348. package/test/replay-golden.ts +0 -84
  349. package/test_benchmark.js +0 -165
  350. package/test_comprehensive.mjs +0 -638
  351. package/test_concurrency.js +0 -129
  352. package/test_ir_robustness.js +0 -85
  353. package/test_semantic_contracts.js +0 -269
  354. package/test_ssg_stress.js +0 -156
  355. package/test_svl3.js +0 -58
  356. package/tsconfig.json +0 -17
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ /**
3
+ * P3.11-13: Pairwise Preference System
4
+ *
5
+ * Upgrades from pointwise (accepted/rejected) to pairwise (A > B)
6
+ * preference data — the primitive format for RLHF.
7
+ *
8
+ * P3.11: RepairPreference data structure + collection
9
+ * P3.12: Enhanced benchmark with acceptableTop3 + unacceptableRepairs
10
+ * P3.13: PreferenceRanker using pairwise win rates
11
+ *
12
+ * Key insight: Top-3 (37%) vs Top-1 (12%) gap = 25%.
13
+ * Correct answers are in the candidate pool but ranked wrong.
14
+ * Pairwise preference is how we fix this.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.PAIRWISE_BENCHMARK_CASES = exports.PreferenceRanker = void 0;
51
+ exports.createPreferenceStore = createPreferenceStore;
52
+ exports.recordPreference = recordPreference;
53
+ exports.getWinRate = getWinRate;
54
+ exports.savePreferences = savePreferences;
55
+ exports.runRankerStressTest = runRankerStressTest;
56
+ exports.printRankerStressReport = printRankerStressReport;
57
+ const fs = __importStar(require("fs"));
58
+ const path = __importStar(require("path"));
59
+ const planner_telemetry_1 = require("./planner-telemetry");
60
+ const repair_ranker_1 = require("./repair-ranker");
61
+ function createPreferenceStore() {
62
+ return {
63
+ preferences: [],
64
+ winCounts: new Map(),
65
+ comparisonCounts: new Map(),
66
+ };
67
+ }
68
+ /** Record a pairwise preference: winner > loser. */
69
+ function recordPreference(store, winner, loser, goal, protocol) {
70
+ const pref = { winner, loser, goal, protocol, timestamp: Date.now() };
71
+ store.preferences.push(pref);
72
+ store.winCounts.set(winner, (store.winCounts.get(winner) || 0) + 1);
73
+ store.comparisonCounts.set(winner, (store.comparisonCounts.get(winner) || 0) + 1);
74
+ store.comparisonCounts.set(loser, (store.comparisonCounts.get(loser) || 0) + 1);
75
+ }
76
+ /** Win rate: wins / total comparisons. Default 0.5 for unknowns. */
77
+ function getWinRate(store, fingerprint, minComparisons = 3) {
78
+ const wins = store.winCounts.get(fingerprint) || 0;
79
+ const total = store.comparisonCounts.get(fingerprint) || 0;
80
+ if (total < minComparisons)
81
+ return 0.5;
82
+ return wins / total;
83
+ }
84
+ /** Persist preferences to disk. */
85
+ function savePreferences(store, dir) {
86
+ const outDir = dir || path.resolve(process.cwd(), ".progmune_corpus", "preferences");
87
+ if (!fs.existsSync(outDir))
88
+ fs.mkdirSync(outDir, { recursive: true });
89
+ fs.writeFileSync(path.join(outDir, `prefs-${new Date().toISOString().slice(0, 10)}.json`), JSON.stringify(store.preferences, null, 2));
90
+ }
91
+ /**
92
+ * Run a stress test: how well does the ranker distinguish
93
+ * acceptable repairs from unacceptable ones?
94
+ */
95
+ function runRankerStressTest(cases, candidateGenerator, ranker) {
96
+ const results = [];
97
+ for (const tc of cases) {
98
+ const candidates = candidateGenerator(tc.goal, tc.protocol);
99
+ let ranked = candidates;
100
+ if (ranker) {
101
+ const ctx = { protocol: tc.protocol, currentState: [], targetState: [], violationType: tc.violationType, constraints: [], rules: new Map() };
102
+ const features = candidates.map(c => (0, repair_ranker_1.extractFeatures)(c, ctx));
103
+ ranked = ranker(candidates, features);
104
+ }
105
+ const top1 = ranked[0];
106
+ const top3 = ranked.slice(0, 3);
107
+ const top1Correct = top1
108
+ ? tc.expectedTop1.every(fn => top1.actions.some(a => a.kind === "call" && a.function === fn))
109
+ : false;
110
+ // Count acceptable patterns in top 3
111
+ let acceptableFound = 0;
112
+ for (const pattern of tc.acceptableTop3) {
113
+ const found = top3.some(c => pattern.every(fn => c.actions.some(a => a.kind === "call" && a.function === fn)));
114
+ if (found)
115
+ acceptableFound++;
116
+ }
117
+ const top3Coverage = tc.acceptableTop3.length > 0 ? acceptableFound / tc.acceptableTop3.length : 0;
118
+ // Check for unacceptable repairs
119
+ const unacceptableFound = tc.unacceptableRepairs.some(pattern => ranked.some(c => pattern.every(fn => c.actions.some(a => a.kind === "call" && a.function === fn))));
120
+ results.push({
121
+ goal: tc.goal,
122
+ top1Correct,
123
+ top3Coverage,
124
+ unacceptableFound,
125
+ totalCandidates: candidates.length,
126
+ preferenceRankerWinRate: 0,
127
+ });
128
+ }
129
+ return {
130
+ cases: cases.length,
131
+ top1Accuracy: results.filter(r => r.top1Correct).length / Math.max(1, cases.length),
132
+ top3Acceptability: results.reduce((s, r) => s + r.top3Coverage, 0) / Math.max(1, cases.length),
133
+ unacceptableFiltered: results.filter(r => !r.unacceptableFound).length / Math.max(1, cases.length),
134
+ avgCandidates: results.reduce((s, r) => s + r.totalCandidates, 0) / Math.max(1, cases.length),
135
+ };
136
+ }
137
+ function printRankerStressReport(report) {
138
+ console.log("\n╔════════════════════════════════════════════════════╗");
139
+ console.log("║ Ranker Stress Test Report ║");
140
+ console.log("╚════════════════════════════════════════════════════╝\n");
141
+ console.log(`Cases: ${report.cases}`);
142
+ console.log(`Top-1 Accuracy: ${(report.top1Accuracy * 100).toFixed(0)}%`);
143
+ console.log(`Top-3 Acceptability: ${(report.top3Acceptability * 100).toFixed(0)}%`);
144
+ console.log(`Unacceptable Filtered: ${(report.unacceptableFiltered * 100).toFixed(0)}%`);
145
+ console.log(`Avg Candidates: ${report.avgCandidates.toFixed(1)}`);
146
+ const top3Top1Gap = report.top3Acceptability - report.top1Accuracy;
147
+ console.log(`\n Top-3/Top-1 Gap: ${(top3Top1Gap * 100).toFixed(0)}%`);
148
+ if (top3Top1Gap > 0.2) {
149
+ console.log(" ⚠️ Large gap: candidates found but ranked wrong. Priority = ranking.");
150
+ }
151
+ else {
152
+ console.log(" ✅ Small gap: ranking is working well.");
153
+ }
154
+ console.log();
155
+ }
156
+ // ═══════════════════════════════════════════════════════════════
157
+ // P3.13: Preference Ranker
158
+ // ═══════════════════════════════════════════════════════════════
159
+ /**
160
+ * PreferenceRanker: ranks candidates by pairwise win rate.
161
+ *
162
+ * Given historical preference data (A > B, B > C, ...),
163
+ * computes Elo-like scores from pairwise comparisons.
164
+ *
165
+ * score = winRate * 0.6 + heuristicScore * 0.4
166
+ *
167
+ * Where winRate comes from the preference store and
168
+ * heuristicScore comes from the base LinearRanker.
169
+ */
170
+ class PreferenceRanker {
171
+ constructor(store, minComparisons = 3) {
172
+ this.store = store || createPreferenceStore();
173
+ this.minComparisons = minComparisons;
174
+ }
175
+ /** Get the pairwise win rate for a candidate's fingerprint. */
176
+ winRate(candidate, protocol, violationType) {
177
+ const actions = candidate.actions
178
+ .filter(a => a.kind === "call")
179
+ .map(a => a.function);
180
+ const fp = (0, planner_telemetry_1.candidateFingerprint)(protocol, actions, violationType);
181
+ return getWinRate(this.store, fp, this.minComparisons);
182
+ }
183
+ /**
184
+ * Rank candidates by combining pairwise win rate with heuristic score.
185
+ *
186
+ * score = winRate * 0.6 + heuristicScore * 0.4
187
+ *
188
+ * Where heuristicScore comes from LinearRanker (protocolSafety, performance, etc.)
189
+ * and winRate comes from historical pairwise preferences.
190
+ */
191
+ rank(candidates, features, protocol, violationType) {
192
+ const baseRanker = (0, repair_ranker_1.createLinearRanker)();
193
+ const heuristicScores = features.map(f => baseRanker.score(f));
194
+ const scored = candidates.map((c, i) => ({
195
+ candidate: c,
196
+ score: this.winRate(c, protocol, violationType) * 0.6 +
197
+ heuristicScores[i] * 0.4,
198
+ }));
199
+ scored.sort((a, b) => b.score - a.score);
200
+ return scored.map(s => s.candidate);
201
+ }
202
+ get preferences() {
203
+ return this.store.preferences;
204
+ }
205
+ }
206
+ exports.PreferenceRanker = PreferenceRanker;
207
+ // ═══════════════════════════════════════════════════════════════
208
+ // Pairwise Preference Benchmarks
209
+ // ═══════════════════════════════════════════════════════════════
210
+ /** Pre-built pairwise benchmark cases for ranker stress testing. */
211
+ exports.PAIRWISE_BENCHMARK_CASES = [
212
+ {
213
+ goal: "safely write config file",
214
+ protocol: "FileProtocol",
215
+ expectedTop1: ["open_file", "write_file", "close_file"],
216
+ acceptableTop3: [
217
+ ["open_file", "write_file", "close_file"],
218
+ ["open_file", "write_file", "flush", "close_file"],
219
+ ],
220
+ unacceptableRepairs: [
221
+ ["write_file"], // skip open
222
+ ["open_file", "write_file"], // missing close
223
+ ],
224
+ violationType: "resource_leak",
225
+ },
226
+ {
227
+ goal: "authenticate user",
228
+ protocol: "AuthProtocol",
229
+ expectedTop1: ["verify_password", "generate_jwt", "create_session"],
230
+ acceptableTop3: [
231
+ ["verify_password", "generate_jwt", "create_session"],
232
+ ["verify_password", "generate_jwt"],
233
+ ],
234
+ unacceptableRepairs: [
235
+ ["generate_jwt"], // skip verify
236
+ ["create_session"], // skip verify+jwt
237
+ ["logout"], // wrong direction
238
+ ],
239
+ violationType: "missing_prerequisite",
240
+ },
241
+ {
242
+ goal: "logout user",
243
+ protocol: "AuthProtocol",
244
+ expectedTop1: ["verify_password", "generate_jwt", "create_session", "logout"],
245
+ acceptableTop3: [
246
+ ["verify_password", "generate_jwt", "create_session", "logout"],
247
+ ],
248
+ unacceptableRepairs: [
249
+ ["logout"], // skip prerequisites entirely
250
+ ],
251
+ violationType: "illegal_state_transition",
252
+ },
253
+ {
254
+ goal: "query database safely",
255
+ protocol: "DBProtocol",
256
+ expectedTop1: ["connect_db", "query_db", "disconnect_db"],
257
+ acceptableTop3: [
258
+ ["connect_db", "query_db", "disconnect_db"],
259
+ ],
260
+ unacceptableRepairs: [
261
+ ["query_db"], // no connection
262
+ ["connect_db", "query_db"], // missing disconnect
263
+ ],
264
+ violationType: "missing_prerequisite",
265
+ },
266
+ {
267
+ goal: "extract IR and validate",
268
+ protocol: "IRProtocol",
269
+ expectedTop1: ["extractIR", "validateAction"],
270
+ acceptableTop3: [
271
+ ["extractIR", "validateAction"],
272
+ ["extractIR", "validateAction", "validateActionSequence"],
273
+ ],
274
+ unacceptableRepairs: [
275
+ ["validateAction"], // skip extract
276
+ ["emitCode"], // skip entire pipeline
277
+ ],
278
+ violationType: "missing_prerequisite",
279
+ },
280
+ {
281
+ goal: "full IR pipeline",
282
+ protocol: "IRProtocol",
283
+ expectedTop1: ["extractIR", "validateAction", "validateActionSequence", "emitCode", "recordSession"],
284
+ acceptableTop3: [
285
+ ["extractIR", "validateAction", "validateActionSequence", "emitCode", "recordSession"],
286
+ ["extractIR", "validateAction", "validateActionSequence", "emitCode"],
287
+ ],
288
+ unacceptableRepairs: [
289
+ ["extractIR", "emitCode"], // skip validation
290
+ ["recordSession"], // skip everything
291
+ ],
292
+ violationType: "missing_prerequisite",
293
+ },
294
+ ];
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ /**
3
+ * P3.11-13: Pairwise Preference Tests
4
+ *
5
+ * Verifying:
6
+ * 1. Pairwise preference recording and win rate computation
7
+ * 2. Ranker stress test with acceptable/unacceptable patterns
8
+ * 3. PreferenceRanker using pairwise win rates
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ const vitest_1 = require("vitest");
12
+ const pairwise_preference_1 = require("./pairwise-preference");
13
+ const planner_telemetry_1 = require("./planner-telemetry");
14
+ // ═══════════════════════════════════════════════════════════════
15
+ // P3.11: Pairwise Preference
16
+ // ═══════════════════════════════════════════════════════════════
17
+ (0, vitest_1.describe)("Pairwise Preference", () => {
18
+ (0, vitest_1.it)("records and queries win rates", () => {
19
+ const store = (0, pairwise_preference_1.createPreferenceStore)();
20
+ const fpA = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "write_file", "close_file"], "resource_leak");
21
+ const fpB = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "write_file"], "resource_leak");
22
+ const fpC = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["atomic_write"], "resource_leak");
23
+ // A beats B 8 times
24
+ for (let i = 0; i < 8; i++) {
25
+ (0, pairwise_preference_1.recordPreference)(store, fpA, fpB, "safely write config file", "FileProtocol");
26
+ }
27
+ // B beats A 2 times
28
+ for (let i = 0; i < 2; i++) {
29
+ (0, pairwise_preference_1.recordPreference)(store, fpB, fpA, "safely write config file", "FileProtocol");
30
+ }
31
+ // A beats C 5 times
32
+ for (let i = 0; i < 5; i++) {
33
+ (0, pairwise_preference_1.recordPreference)(store, fpA, fpC, "safely write config file", "FileProtocol");
34
+ }
35
+ (0, vitest_1.expect)(store.preferences.length).toBe(15);
36
+ // A: 8+5=13 wins / 10+5=15 comparisons = 86.7%
37
+ const aRate = (0, pairwise_preference_1.getWinRate)(store, fpA, 3);
38
+ (0, vitest_1.expect)(aRate).toBeCloseTo(13 / 15, 2);
39
+ // B: 2 wins / 10 comparisons = 20%
40
+ const bRate = (0, pairwise_preference_1.getWinRate)(store, fpB, 3);
41
+ (0, vitest_1.expect)(bRate).toBe(0.2);
42
+ // C: 0 wins / 5 comparisons = 0%
43
+ const cRate = (0, pairwise_preference_1.getWinRate)(store, fpC, 3);
44
+ (0, vitest_1.expect)(cRate).toBe(0);
45
+ // Unknown fingerprint: default 0.5
46
+ const unknown = (0, pairwise_preference_1.getWinRate)(store, "unknown-fp", 3);
47
+ (0, vitest_1.expect)(unknown).toBe(0.5);
48
+ });
49
+ (0, vitest_1.it)("defaults to 0.5 for fingerprints with insufficient comparisons", () => {
50
+ const store = (0, pairwise_preference_1.createPreferenceStore)();
51
+ const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"], "resource_leak");
52
+ (0, pairwise_preference_1.recordPreference)(store, fp, "other", "test", "FileProtocol");
53
+ // 1 win, 1 comparison → need 3 minimum
54
+ (0, vitest_1.expect)((0, pairwise_preference_1.getWinRate)(store, fp, 3)).toBe(0.5);
55
+ // 1 win, 1 comparison → enough for min 1
56
+ (0, vitest_1.expect)((0, pairwise_preference_1.getWinRate)(store, fp, 1)).toBe(1.0);
57
+ });
58
+ });
59
+ // ═══════════════════════════════════════════════════════════════
60
+ // P3.12: Ranker Stress Test
61
+ // ═══════════════════════════════════════════════════════════════
62
+ function fakeCandidateGenerator(goal, _protocol) {
63
+ if (goal.includes("safely write")) {
64
+ return [
65
+ { id: "safe", source: "protocol", actions: fnActions(["open_file", "write_file", "close_file"]), explanation: "safe" },
66
+ { id: "flush", source: "corpus", actions: fnActions(["open_file", "write_file", "flush", "close_file"]), explanation: "safe+flush" },
67
+ { id: "leak", source: "corpus", actions: fnActions(["open_file", "write_file"]), explanation: "leaky" },
68
+ { id: "bare", source: "antibody", actions: fnActions(["write_file"]), explanation: "bare" },
69
+ ];
70
+ }
71
+ if (goal.includes("authenticate")) {
72
+ return [
73
+ { id: "full", source: "protocol", actions: fnActions(["verify_password", "generate_jwt", "create_session"]), explanation: "full" },
74
+ { id: "partial", source: "protocol", actions: fnActions(["verify_password", "generate_jwt"]), explanation: "partial" },
75
+ { id: "skip", source: "antibody", actions: fnActions(["generate_jwt"]), explanation: "skip-verify" },
76
+ { id: "wrong", source: "corpus", actions: fnActions(["logout"]), explanation: "wrong" },
77
+ ];
78
+ }
79
+ return [];
80
+ }
81
+ function fnActions(fns) {
82
+ return fns.map(fn => ({ kind: "call", function: fn, args: [] }));
83
+ }
84
+ (0, vitest_1.describe)("Ranker Stress Test", () => {
85
+ (0, vitest_1.it)("measures top-1 accuracy and top-3 acceptability", () => {
86
+ const testCases = pairwise_preference_1.PAIRWISE_BENCHMARK_CASES.slice(0, 2); // first 2
87
+ const report = (0, pairwise_preference_1.runRankerStressTest)(testCases, fakeCandidateGenerator);
88
+ (0, vitest_1.expect)(report.cases).toBe(2);
89
+ (0, vitest_1.expect)(report.top1Accuracy).toBeGreaterThanOrEqual(0);
90
+ (0, vitest_1.expect)(report.top3Acceptability).toBeGreaterThanOrEqual(0);
91
+ (0, vitest_1.expect)(report.unacceptableFiltered).toBeGreaterThanOrEqual(0);
92
+ // With our fake generator: safe+flush both in top 3 for file case, full+partial for auth
93
+ (0, vitest_1.expect)(report.top3Acceptability).toBeGreaterThan(0.5);
94
+ (0, pairwise_preference_1.printRankerStressReport)(report);
95
+ });
96
+ (0, vitest_1.it)("all benchmark cases have expectedTop1, acceptableTop3, unacceptableRepairs", () => {
97
+ for (const c of pairwise_preference_1.PAIRWISE_BENCHMARK_CASES) {
98
+ (0, vitest_1.expect)(c.expectedTop1.length).toBeGreaterThan(0);
99
+ (0, vitest_1.expect)(c.acceptableTop3.length).toBeGreaterThan(0);
100
+ (0, vitest_1.expect)(c.unacceptableRepairs.length).toBeGreaterThan(0);
101
+ }
102
+ });
103
+ });
104
+ // ═══════════════════════════════════════════════════════════════
105
+ // P3.13: PreferenceRanker
106
+ // ═══════════════════════════════════════════════════════════════
107
+ (0, vitest_1.describe)("PreferenceRanker", () => {
108
+ (0, vitest_1.it)("ranks candidates by pairwise win rate", () => {
109
+ const store = (0, pairwise_preference_1.createPreferenceStore)();
110
+ const safeFp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "write_file", "close_file"], "resource_leak");
111
+ const leakFp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "write_file"], "resource_leak");
112
+ // Safe beats leak 9 times, leak beats safe 1 time
113
+ for (let i = 0; i < 9; i++)
114
+ (0, pairwise_preference_1.recordPreference)(store, safeFp, leakFp, "write file", "FileProtocol");
115
+ for (let i = 0; i < 1; i++)
116
+ (0, pairwise_preference_1.recordPreference)(store, leakFp, safeFp, "write file", "FileProtocol");
117
+ const ranker = new pairwise_preference_1.PreferenceRanker(store);
118
+ const safe = { id: "safe", source: "protocol", actions: fnActions(["open_file", "write_file", "close_file"]), explanation: "safe" };
119
+ const leak = { id: "leak", source: "corpus", actions: fnActions(["open_file", "write_file"]), explanation: "leaky" };
120
+ const features = [
121
+ { protocolSafety: 1.0, historicalSuccessRate: 0.5, actionCount: 3, latencyCost: 0.6, auditability: 0.8, corpusEvidence: 0, source: "protocol" },
122
+ { protocolSafety: 0.3, historicalSuccessRate: 0.5, actionCount: 2, latencyCost: 0.4, auditability: 0.5, corpusEvidence: 0, source: "corpus" },
123
+ ];
124
+ const ranked = ranker.rank([leak, safe], features, "FileProtocol", "resource_leak");
125
+ // Safe should rank higher (90% win rate vs 10%)
126
+ (0, vitest_1.expect)(ranked[0].id).toBe("safe");
127
+ (0, vitest_1.expect)(ranked[1].id).toBe("leak");
128
+ });
129
+ (0, vitest_1.it)("defaults to heuristic when no preference data", () => {
130
+ const ranker = new pairwise_preference_1.PreferenceRanker();
131
+ const safe = { id: "safe", source: "protocol", actions: fnActions(["open_file", "write_file", "close_file"]), explanation: "safe" };
132
+ const leak = { id: "leak", source: "antibody", actions: fnActions(["open_file", "write_file"]), explanation: "missing close" };
133
+ // Safe has higher protocolSafety, leak has lower (missing close = unsafe)
134
+ const safeFeatures = { protocolSafety: 1.0, historicalSuccessRate: 0.5, actionCount: 3, latencyCost: 0.6, auditability: 0.8, corpusEvidence: 0, source: "protocol" };
135
+ const leakFeatures = { protocolSafety: 0.2, historicalSuccessRate: 0.3, actionCount: 2, latencyCost: 0.4, auditability: 0.4, corpusEvidence: 0, source: "antibody" };
136
+ // Without preference data, falls back to heuristic
137
+ const ranked = ranker.rank([leak, safe], [leakFeatures, safeFeatures], "FileProtocol");
138
+ (0, vitest_1.expect)(ranked[0].id).toBe("safe");
139
+ });
140
+ });
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * Planner Constraints — mined rules injected into the search space.
4
+ *
5
+ * Bridges Rule Miner → Planner: MinedRule patterns directly influence
6
+ * function scoring, filtering, and prioritization in the capability graph.
7
+ *
8
+ * Three levels of constraint:
9
+ * L1 (soft): Adjust function scores based on rule confidence
10
+ * L2 (medium): Deprioritize functions matching high-risk patterns
11
+ * L3 (hard): Blacklist functions that consistently cause violations
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.deriveConstraints = deriveConstraints;
15
+ exports.applyConstraints = applyConstraints;
16
+ exports.formatConstraints = formatConstraints;
17
+ exports.getConstraints = getConstraints;
18
+ exports.clearConstraintsCache = clearConstraintsCache;
19
+ const rule_miner_1 = require("./rule-miner");
20
+ /**
21
+ * Derive planner constraints from mined rules.
22
+ * Each mined rule becomes a scoring constraint that modifies
23
+ * how functions are weighted during capability graph construction.
24
+ */
25
+ function deriveConstraints() {
26
+ const rules = (0, rule_miner_1.mineRules)();
27
+ const constraints = [];
28
+ for (const rule of rules) {
29
+ // High-confidence rules → stronger penalties
30
+ const normalizedConf = Math.min(1, rule.confidence / 50); // 50+ occurrences = max confidence
31
+ // Pattern-based constraints
32
+ if (rule.function === "symbol_existence") {
33
+ constraints.push({
34
+ pattern: "symbol_existence",
35
+ penalty: Math.max(0.3, 1 - normalizedConf * 0.5), // 0.3-1.0
36
+ reason: rule.reason,
37
+ confidence: rule.confidence,
38
+ });
39
+ }
40
+ if (rule.function === "protocol") {
41
+ constraints.push({
42
+ pattern: "protocol",
43
+ penalty: Math.max(0.4, 1 - normalizedConf * 0.4),
44
+ reason: rule.reason,
45
+ confidence: rule.confidence,
46
+ });
47
+ }
48
+ if (rule.function === "type_mismatch") {
49
+ constraints.push({
50
+ pattern: "type_mismatch",
51
+ penalty: Math.max(0.5, 1 - normalizedConf * 0.3),
52
+ reason: rule.reason,
53
+ confidence: rule.confidence,
54
+ });
55
+ }
56
+ if (rule.function === "dataflow") {
57
+ constraints.push({
58
+ pattern: "dataflow",
59
+ penalty: Math.max(0.5, 1 - normalizedConf * 0.3),
60
+ reason: rule.reason,
61
+ confidence: rule.confidence,
62
+ });
63
+ }
64
+ }
65
+ return constraints;
66
+ }
67
+ /**
68
+ * Apply constraints to adjust a function's score.
69
+ * Returns a multiplier in [0, 1] — multiply the raw score by this.
70
+ */
71
+ function applyConstraints(funcName, funcPurpose, constraints) {
72
+ let multiplier = 1.0;
73
+ const matched = [];
74
+ const searchText = (funcName + " " + funcPurpose).toLowerCase();
75
+ for (const c of constraints) {
76
+ // Match: function name/purpose contains the pattern
77
+ if (searchText.includes(c.pattern.toLowerCase())) {
78
+ multiplier *= c.penalty;
79
+ matched.push(`${c.pattern}(${(c.confidence)}x)`);
80
+ }
81
+ }
82
+ return { multiplier: Math.max(0.2, multiplier), matchedRules: matched };
83
+ }
84
+ /**
85
+ * Get a human-readable summary of active constraints.
86
+ */
87
+ function formatConstraints(constraints) {
88
+ if (constraints.length === 0)
89
+ return "";
90
+ const lines = ["\n📋 规则约束 (Rule → Planner):"];
91
+ for (const c of constraints.slice(0, 5)) {
92
+ const level = c.penalty < 0.4 ? "🔴" : c.penalty < 0.7 ? "🟡" : "🟢";
93
+ lines.push(` ${level} ${c.pattern}: ×${c.penalty.toFixed(2)} (${c.reason.slice(0, 40)})`);
94
+ }
95
+ return lines.join("\n");
96
+ }
97
+ // Cache constraints (derived once per session)
98
+ let _constraints = null;
99
+ function getConstraints() {
100
+ if (!_constraints)
101
+ _constraints = deriveConstraints();
102
+ return _constraints;
103
+ }
104
+ function clearConstraintsCache() { _constraints = null; }