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.
- package/README.md +108 -468
- package/dist/ablation-study.js +144 -0
- package/dist/ablation-study.test.js +18 -0
- package/dist/action-runtime.js +3 -1
- package/dist/active-learning.js +211 -0
- package/dist/analytics.js +139 -0
- package/dist/asset-factory.js +309 -0
- package/dist/asset-growth.js +244 -0
- package/dist/asset-promotion.js +382 -0
- package/dist/asset-quality.js +550 -0
- package/dist/audit/business-translator.js +285 -0
- package/dist/audit/cli.js +66 -0
- package/dist/audit/formatters/html.js +379 -0
- package/dist/audit/formatters/json.js +11 -0
- package/dist/audit/formatters/markdown.js +192 -0
- package/dist/audit/formatters/terminal.js +189 -0
- package/dist/audit/index.js +25 -0
- package/dist/audit/report-builder.js +318 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit.js +3 -3
- package/dist/auto-benchmark-generator.js +137 -0
- package/dist/auto-benchmark-generator.test.js +45 -0
- package/dist/auto-protocol-synthesizer.js +362 -0
- package/dist/auto-protocol-synthesizer.test.js +82 -0
- package/dist/autonomous-patch.js +175 -0
- package/dist/autonomous-patch.test.js +128 -0
- package/dist/badge/badge-server.js +98 -0
- package/dist/behavior-miner.js +442 -0
- package/dist/belief-layer.js +475 -0
- package/dist/benchmark-count.js +5 -0
- package/dist/benchmark-generator.js +211 -0
- package/dist/benchmark-harness.js +201 -0
- package/dist/benchmark-pass-rate.js +7 -0
- package/dist/benchmark-report.js +8 -3
- package/dist/benchmark-save.js +14 -1
- package/dist/bootstrap-validation.js +197 -0
- package/dist/bootstrap-validation.test.js +51 -0
- package/dist/branch-ledger.js +1 -1
- package/dist/capability-gap.js +130 -0
- package/dist/certify-html.js +351 -0
- package/dist/certify.js +326 -0
- package/dist/check.js +4 -4
- package/dist/compliance-miner.js +447 -0
- package/dist/continuous-benchmark.js +194 -0
- package/dist/continuous-benchmark.test.js +116 -0
- package/dist/corpus-stats.js +173 -0
- package/dist/counterfactual-engine.js +288 -0
- package/dist/coverage-dashboard.js +109 -0
- package/dist/coverage-system.test.js +205 -0
- package/dist/cross-repo-precision.js +352 -0
- package/dist/cve-benchmark.js +180 -0
- package/dist/cve-benchmark.test.js +28 -0
- package/dist/cve-collector.js +73 -0
- package/dist/data-quality.js +141 -0
- package/dist/decision-engine.js +388 -0
- package/dist/derive-metadata.js +250 -0
- package/dist/difficulty-active.test.js +198 -0
- package/dist/difficulty-map.js +244 -0
- package/dist/discovery-analytics.js +125 -0
- package/dist/discovery-model.js +149 -0
- package/dist/discovery-optimize.test.js +199 -0
- package/dist/discovery-trace.js +276 -0
- package/dist/discovery-trace.test.js +97 -0
- package/dist/emitter.js +83 -1
- package/dist/enterprise-dashboard.js +405 -0
- package/dist/eval-hardening.js +297 -0
- package/dist/eval-hardening.test.js +85 -0
- package/dist/evaluation-campaign.js +359 -0
- package/dist/evaluation-campaign.test.js +181 -0
- package/dist/evidence-growth.js +143 -0
- package/dist/evidence-repository.js +209 -0
- package/dist/evidence-system.js +441 -0
- package/dist/execute.js +15 -7
- package/dist/experimental/software-physics.js +291 -0
- package/dist/experimental/state-inference.js +516 -0
- package/dist/experimental/unsupervised-physics.js +230 -0
- package/dist/extract-ir-python.js +54 -7
- package/dist/extract-ir.js +376 -12
- package/dist/failure-collector.js +2 -2
- package/dist/failure-corpus.js +322 -9
- package/dist/feedback.js +16 -5
- package/dist/feedback.test.js +49 -0
- package/dist/file-lock.js +1 -1
- package/dist/flywheel-batch.js +292 -0
- package/dist/frameworks/express-cli.js +237 -0
- package/dist/frameworks/express-detector.js +445 -0
- package/dist/frameworks/express-detector.test.js +206 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/nestjs-detector.js +302 -0
- package/dist/frameworks/trpc-detector.js +161 -0
- package/dist/frameworks/version-awareness.js +179 -0
- package/dist/function-synonyms.js +164 -0
- package/dist/function-synonyms.test.js +68 -0
- package/dist/generalization.test.js +352 -0
- package/dist/goal-annotator.js +113 -0
- package/dist/goal-planner.js +563 -0
- package/dist/gold-cve.js +164 -0
- package/dist/gold-cve.test.js +104 -0
- package/dist/gold-quality.js +206 -0
- package/dist/gold-tiers.js +241 -0
- package/dist/governance-dashboard.js +327 -0
- package/dist/graph-viz.js +240 -0
- package/dist/guided-frontier.js +195 -0
- package/dist/hierarchical-planner.js +148 -0
- package/dist/identifier-parser.js +260 -0
- package/dist/immune-metrics.js +93 -0
- package/dist/immune-receiver.js +158 -0
- package/dist/immune-reporter.js +1 -1
- package/dist/improvement-orchestrator.js +206 -0
- package/dist/inject-p0-vocabulary.js +300 -0
- package/dist/intent-parser.js +218 -0
- package/dist/invariant-algebra.js +476 -0
- package/dist/invariant-calculus.js +533 -0
- package/dist/ir-utils.js +70 -0
- package/dist/ir-utils.test.js +50 -0
- package/dist/knowledge-api.js +312 -0
- package/dist/knowledge-evolution.js +452 -0
- package/dist/knowledge-explorer.js +506 -0
- package/dist/knowledge-flywheel.js +274 -0
- package/dist/knowledge-governance.js +338 -0
- package/dist/knowledge-governance.test.js +150 -0
- package/dist/knowledge-graph.js +181 -0
- package/dist/knowledge-guided-synth.js +246 -0
- package/dist/knowledge-loop.test.js +77 -0
- package/dist/knowledge-object.js +316 -0
- package/dist/knowledge-package.js +98 -0
- package/dist/kpi-dashboard.js +561 -0
- package/dist/l3-cross-function.js +280 -0
- package/dist/learning-ranker.js +148 -0
- package/dist/learning-ranker.test.js +291 -0
- package/dist/ledger/accountability.js +322 -0
- package/dist/ledger/chain-builder.js +185 -0
- package/dist/ledger/cli.js +222 -0
- package/dist/ledger/index.js +13 -0
- package/dist/ledger/signatures.js +193 -0
- package/dist/ledger/types.js +9 -0
- package/dist/llm.js +74 -3
- package/dist/load-benchmarks.js +8 -3
- package/dist/logger.js +66 -0
- package/dist/logger.test.js +37 -0
- package/dist/logistic-reward.js +339 -0
- package/dist/logistic-reward.test.js +180 -0
- package/dist/macro-graph.js +193 -0
- package/dist/macro-repair.js +183 -0
- package/dist/mcp-server.mjs +1202 -483
- package/dist/memory-layer.js +42 -5
- package/dist/multi-repo-precision.js +422 -0
- package/dist/name-free-protocol.js +425 -0
- package/dist/name-free-protocol.test.js +170 -0
- package/dist/name-scrambling.js +138 -0
- package/dist/name-scrambling.test.js +16 -0
- package/dist/p3-observability.test.js +281 -0
- package/dist/p5-orchestrator.test.js +225 -0
- package/dist/pairwise-preference.js +294 -0
- package/dist/pairwise-preference.test.js +140 -0
- package/dist/planner-constraints.js +104 -0
- package/dist/planner-prompts.js +155 -0
- package/dist/planner-telemetry.js +415 -0
- package/dist/planner-trace.js +214 -0
- package/dist/planner.js +162 -167
- package/dist/plsb/artifact.js +116 -0
- package/dist/plsb/cli.js +71 -0
- package/dist/plsb/index.js +19 -0
- package/dist/plsb/leaderboard.js +249 -0
- package/dist/plsb/report-md.js +156 -0
- package/dist/plsb/schema.js +179 -0
- package/dist/plsb-benchmark.js +284 -0
- package/dist/plsb-benchmark.test.js +119 -0
- package/dist/policy/cli.js +134 -0
- package/dist/policy/engine.js +333 -0
- package/dist/policy/index.js +12 -0
- package/dist/policy/types.js +59 -0
- package/dist/policy-miner.js +505 -0
- package/dist/precision-analyze.js +229 -0
- package/dist/precision-benchmark.js +147 -0
- package/dist/precision-label-c.js +134 -0
- package/dist/precision-label.js +193 -0
- package/dist/precision-report-c.js +149 -0
- package/dist/precision-report.js +246 -0
- package/dist/progmune-status.js +108 -0
- package/dist/proof-engine.js +479 -0
- package/dist/proof-provenance.js +315 -0
- package/dist/protocol-coverage.js +294 -0
- package/dist/protocol-detector.js +1189 -0
- package/dist/protocol-embedding-expanded.js +297 -0
- package/dist/protocol-embedding-expanded.test.js +97 -0
- package/dist/protocol-embedding.js +195 -0
- package/dist/protocol-embedding.test.js +82 -0
- package/dist/protocol-extractor-v2.js +354 -0
- package/dist/protocol-extractor-v2.test.js +140 -0
- package/dist/protocol-extractor.js +310 -0
- package/dist/protocol-extractor.test.js +113 -0
- package/dist/protocol-foundation.js +322 -0
- package/dist/protocol-foundation.test.js +163 -0
- package/dist/protocol-frontier.js +243 -0
- package/dist/protocol-frontier.test.js +92 -0
- package/dist/protocol-gap-analyzer.js +228 -0
- package/dist/protocol-gap-analyzer.test.js +49 -0
- package/dist/protocol-invariants.js +276 -0
- package/dist/protocol-invariants.test.js +111 -0
- package/dist/protocol-knowledge.js +464 -0
- package/dist/protocol-miner.js +343 -0
- package/dist/protocol-mining.js +207 -0
- package/dist/protocol-mining.test.js +37 -0
- package/dist/protocol-registry.js +1 -1
- package/dist/protocol-security-benchmark.js +222 -0
- package/dist/protocol-vulnerability.js +257 -0
- package/dist/protocol-vulnerability.test.js +60 -0
- package/dist/python-benchmark.js +120 -0
- package/dist/python-emitter.js +163 -45
- package/dist/python-protocol-extractor.js +187 -0
- package/dist/python-protocol-extractor.test.js +116 -0
- package/dist/realworld-benchmark.js +646 -0
- package/dist/realworld-benchmark.test.js +36 -0
- package/dist/repair-arch.test.js +411 -0
- package/dist/repair-evolution.test.js +454 -0
- package/dist/repair-executor.js +719 -0
- package/dist/repair-proposal.js +4 -4
- package/dist/repair-ranker.js +141 -0
- package/dist/repair-strategies.js +419 -0
- package/dist/repair-taxonomy.js +234 -0
- package/dist/repair-types.js +12 -0
- package/dist/repo-evaluator.js +250 -0
- package/dist/repo-evaluator.test.js +128 -0
- package/dist/resource-abstraction.js +242 -0
- package/dist/resource-detector.js +211 -0
- package/dist/result.test.js +43 -0
- package/dist/reward-system.js +411 -0
- package/dist/reward-system.test.js +175 -0
- package/dist/risk-model.js +215 -0
- package/dist/rule-miner.js +234 -7
- package/dist/rule-specificity.js +254 -0
- package/dist/runtime-types.js +27 -0
- package/dist/scaffold.js +208 -0
- package/dist/scale-collector.test.js +101 -0
- package/dist/scale-trajectory-collector.js +128 -0
- package/dist/sdk.js +250 -0
- package/dist/search-planner.js +4 -41
- package/dist/semantic-snapshot.js +1 -1
- package/dist/semantic-topology.js +121 -0
- package/dist/semantic-trace.js +310 -317
- package/dist/sequence-extractor.js +343 -0
- package/dist/skill-library.js +245 -0
- package/dist/skill-planner.test.js +189 -0
- package/dist/software-physics.js +291 -0
- package/dist/software-physics.test.js +81 -0
- package/dist/ssg-precision.js +478 -0
- package/dist/ssg-validator.js +71 -21
- package/dist/state-inference-doubleblind.test.js +160 -0
- package/dist/state-inference.js +516 -0
- package/dist/state-inference.test.js +115 -0
- package/dist/state-machine-fingerprint.js +345 -0
- package/dist/state-machine-fingerprint.test.js +120 -0
- package/dist/state-miner.js +386 -0
- package/dist/state-name-inference.js +213 -0
- package/dist/state-name-inference.test.js +69 -0
- package/dist/strategy-planner.js +262 -96
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- 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
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
- package/package.json +74 -7
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- 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; }
|