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.
- package/README.md +119 -461
- 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 +721 -0
- package/package.json +73 -6
- 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,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P4.5+: Discovery Reward Model
|
|
4
|
+
*
|
|
5
|
+
* Predicts P(candidate_exists | goal, protocol, violation) rather than
|
|
6
|
+
* P(accepted | candidate). This is the signal that should drive
|
|
7
|
+
* Guided Frontier — not "how likely is this path to be accepted?"
|
|
8
|
+
* but "how likely is a path through this state to even be found?"
|
|
9
|
+
*
|
|
10
|
+
* Training data: benchmark attributions (foundCandidate = 1 - missingCandidate)
|
|
11
|
+
* Features: protocol, violation type, state context
|
|
12
|
+
*
|
|
13
|
+
* When 57% of failures are missing_candidate, the most valuable signal
|
|
14
|
+
* for search guidance is discoverability, not acceptability.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.DiscoveryModel = void 0;
|
|
18
|
+
exports.generateDiscoverabilityReport = generateDiscoverabilityReport;
|
|
19
|
+
exports.printDiscoverabilityReport = printDiscoverabilityReport;
|
|
20
|
+
function sigmoid(z) {
|
|
21
|
+
if (z > 20)
|
|
22
|
+
return 1.0;
|
|
23
|
+
if (z < -20)
|
|
24
|
+
return 0.0;
|
|
25
|
+
return 1.0 / (1.0 + Math.exp(-z));
|
|
26
|
+
}
|
|
27
|
+
// ═══════════════════════════════════════════════════════════════
|
|
28
|
+
// Discovery Model
|
|
29
|
+
// ═══════════════════════════════════════════════════════════════
|
|
30
|
+
const KNOWN_PROTOCOLS = ["FileProtocol", "AuthProtocol", "DBProtocol", "IRProtocol", "_global"];
|
|
31
|
+
const KNOWN_VIOLATIONS = ["resource_leak", "missing_prerequisite", "illegal_state_transition"];
|
|
32
|
+
function featuresToArray(f) {
|
|
33
|
+
const protoBits = KNOWN_PROTOCOLS.map(p => f.protocol === p ? 1.0 : 0.0);
|
|
34
|
+
const violBits = KNOWN_VIOLATIONS.map(v => f.violationType === v ? 1.0 : 0.0);
|
|
35
|
+
return [
|
|
36
|
+
f.isResourceLeak,
|
|
37
|
+
f.isMissingPrereq,
|
|
38
|
+
f.isIllegalState,
|
|
39
|
+
f.currentStateCount / 10,
|
|
40
|
+
...protoBits,
|
|
41
|
+
...violBits,
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
const FEATURE_DIM = 4 + KNOWN_PROTOCOLS.length + KNOWN_VIOLATIONS.length; // 4 + 5 + 3 = 12
|
|
45
|
+
class DiscoveryModel {
|
|
46
|
+
constructor(weights, bias) {
|
|
47
|
+
this.weights = weights || new Array(FEATURE_DIM).fill(0);
|
|
48
|
+
this.bias = bias || 0;
|
|
49
|
+
this.trained = weights !== undefined;
|
|
50
|
+
this.trainedSamples = 0;
|
|
51
|
+
}
|
|
52
|
+
get isTrained() { return this.trained; }
|
|
53
|
+
get sampleCount() { return this.trainedSamples; }
|
|
54
|
+
/** Predict probability that a candidate exists for this context. */
|
|
55
|
+
predict(features) {
|
|
56
|
+
return sigmoid(this.score(featuresToArray(features)));
|
|
57
|
+
}
|
|
58
|
+
score(x) {
|
|
59
|
+
return x.reduce((s, v, i) => s + this.weights[i] * v, 0) + this.bias;
|
|
60
|
+
}
|
|
61
|
+
// ── Training ──
|
|
62
|
+
static samplesFromAttributions(attributed) {
|
|
63
|
+
return attributed.map(a => ({
|
|
64
|
+
features: {
|
|
65
|
+
protocol: a.protocol,
|
|
66
|
+
violationType: a.violationType,
|
|
67
|
+
isResourceLeak: a.violationType === "resource_leak" ? 1 : 0,
|
|
68
|
+
isMissingPrereq: a.violationType === "missing_prerequisite" ? 1 : 0,
|
|
69
|
+
isIllegalState: a.violationType === "illegal_state_transition" ? 1 : 0,
|
|
70
|
+
currentStateCount: 1,
|
|
71
|
+
},
|
|
72
|
+
label: a.failureReason !== "missing_candidate" ? 1 : 0,
|
|
73
|
+
goal: a.goal,
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
static train(samples, learningRate = 0.01, epochs = 100) {
|
|
77
|
+
if (samples.length < 10)
|
|
78
|
+
return new DiscoveryModel();
|
|
79
|
+
let w = new Array(FEATURE_DIM).fill(0).map(() => (Math.random() - 0.5) * 0.1);
|
|
80
|
+
let b = 0.0;
|
|
81
|
+
for (let epoch = 0; epoch < epochs; epoch++) {
|
|
82
|
+
const shuffled = [...samples].sort(() => Math.random() - 0.5);
|
|
83
|
+
for (const sample of shuffled) {
|
|
84
|
+
const x = featuresToArray(sample.features);
|
|
85
|
+
const z = w.reduce((s, wi, i) => s + wi * x[i], 0) + b;
|
|
86
|
+
const p = sigmoid(z);
|
|
87
|
+
const error = p - sample.label;
|
|
88
|
+
for (let i = 0; i < FEATURE_DIM; i++) {
|
|
89
|
+
w[i] -= learningRate * error * x[i];
|
|
90
|
+
}
|
|
91
|
+
b -= learningRate * error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const model = new DiscoveryModel(w, b);
|
|
95
|
+
model.trained = true;
|
|
96
|
+
model.trainedSamples = samples.length;
|
|
97
|
+
return model;
|
|
98
|
+
}
|
|
99
|
+
/** Feature importance for interpretability. */
|
|
100
|
+
featureImportance() {
|
|
101
|
+
const names = [
|
|
102
|
+
"isResourceLeak", "isMissingPrereq", "isIllegalState", "stateCount",
|
|
103
|
+
...KNOWN_PROTOCOLS.map(p => `proto:${p}`),
|
|
104
|
+
...KNOWN_VIOLATIONS.map(v => `viol:${v}`),
|
|
105
|
+
];
|
|
106
|
+
return names.map((name, i) => ({ name, weight: this.weights[i] }))
|
|
107
|
+
.sort((a, b) => Math.abs(b.weight) - Math.abs(a.weight));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.DiscoveryModel = DiscoveryModel;
|
|
111
|
+
/**
|
|
112
|
+
* Generate a discoverability report: which protocol/violation combinations
|
|
113
|
+
* are least likely to have candidates found?
|
|
114
|
+
*/
|
|
115
|
+
function generateDiscoverabilityReport(model) {
|
|
116
|
+
const predictions = [];
|
|
117
|
+
for (const proto of KNOWN_PROTOCOLS) {
|
|
118
|
+
for (const viol of KNOWN_VIOLATIONS) {
|
|
119
|
+
const features = {
|
|
120
|
+
protocol: proto,
|
|
121
|
+
violationType: viol,
|
|
122
|
+
isResourceLeak: viol === "resource_leak" ? 1 : 0,
|
|
123
|
+
isMissingPrereq: viol === "missing_prerequisite" ? 1 : 0,
|
|
124
|
+
isIllegalState: viol === "illegal_state_transition" ? 1 : 0,
|
|
125
|
+
currentStateCount: 1,
|
|
126
|
+
};
|
|
127
|
+
const discoverability = model.predict(features);
|
|
128
|
+
predictions.push({
|
|
129
|
+
protocol: proto,
|
|
130
|
+
violationType: viol,
|
|
131
|
+
discoverability,
|
|
132
|
+
priority: 1 - discoverability,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return predictions.sort((a, b) => b.priority - a.priority);
|
|
137
|
+
}
|
|
138
|
+
function printDiscoverabilityReport(predictions) {
|
|
139
|
+
console.log("\n─── Discoverability Report ───");
|
|
140
|
+
console.log("Protocol Violation Discover Priority");
|
|
141
|
+
console.log("─────────────────────────────────────────────────────────────");
|
|
142
|
+
for (const p of predictions.slice(0, 10)) {
|
|
143
|
+
const disc = (p.discoverability * 100).toFixed(0).padStart(4);
|
|
144
|
+
const pri = (p.priority * 100).toFixed(0).padStart(4);
|
|
145
|
+
const icon = p.priority > 0.5 ? "🔴" : p.priority > 0.3 ? "🟡" : "🟢";
|
|
146
|
+
console.log(` ${p.protocol.padEnd(16)} ${p.violationType.padEnd(22)} ${disc}% ${pri}% ${icon}`);
|
|
147
|
+
}
|
|
148
|
+
console.log();
|
|
149
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P4.5-4.7: Guided Frontier + Macro Mining + Discovery Analytics Tests
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const vitest_1 = require("vitest");
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const guided_frontier_1 = require("./guided-frontier");
|
|
43
|
+
const macro_repair_1 = require("./macro-repair");
|
|
44
|
+
const discovery_analytics_1 = require("./discovery-analytics");
|
|
45
|
+
const planner_telemetry_1 = require("./planner-telemetry");
|
|
46
|
+
function mergeProtocolRules(...maps) {
|
|
47
|
+
const m = new Map();
|
|
48
|
+
for (const mp of maps)
|
|
49
|
+
for (const [k, v] of mp)
|
|
50
|
+
m.set(k, v);
|
|
51
|
+
return m;
|
|
52
|
+
}
|
|
53
|
+
const fileRules = new Map([
|
|
54
|
+
["open_file", { pre_states: [], post_states: ["FILE_OPEN"] }],
|
|
55
|
+
["write_file", { pre_states: ["FILE_OPEN"], post_states: [] }],
|
|
56
|
+
["close_file", { pre_states: ["FILE_OPEN"], post_states: [], invalidate: ["FILE_OPEN"] }],
|
|
57
|
+
]);
|
|
58
|
+
const authRules = new Map([
|
|
59
|
+
["verify_password", { pre_states: ["UNAUTHENTICATED"], post_states: ["PASSWORD_VERIFIED"] }],
|
|
60
|
+
["generate_jwt", { pre_states: ["PASSWORD_VERIFIED"], post_states: ["TOKEN_ISSUED"], invalidate: ["PASSWORD_VERIFIED"] }],
|
|
61
|
+
["create_session", { pre_states: ["TOKEN_ISSUED"], post_states: ["SESSION_ACTIVE"], invalidate: ["TOKEN_ISSUED"] }],
|
|
62
|
+
["logout", { pre_states: ["SESSION_ACTIVE"], post_states: ["UNAUTHENTICATED"], invalidate: ["SESSION_ACTIVE"] }],
|
|
63
|
+
]);
|
|
64
|
+
const dbRules = new Map([
|
|
65
|
+
["connect_db", { pre_states: [], post_states: ["DB_CONNECTED"] }],
|
|
66
|
+
["query_db", { pre_states: ["DB_CONNECTED"], post_states: [] }],
|
|
67
|
+
["disconnect_db", { pre_states: ["DB_CONNECTED"], post_states: [], invalidate: ["DB_CONNECTED"] }],
|
|
68
|
+
]);
|
|
69
|
+
const OPT_DIR = path.resolve(__dirname, "..", "test-discovery-optimize");
|
|
70
|
+
process.env.PROGMUNE_PROJECT_DIR = OPT_DIR;
|
|
71
|
+
fs.mkdirSync(OPT_DIR, { recursive: true });
|
|
72
|
+
fs.mkdirSync(path.join(OPT_DIR, ".progmune_corpus", "telemetry"), { recursive: true });
|
|
73
|
+
function seedHighAcceptanceTelemetry(n) {
|
|
74
|
+
const t = new planner_telemetry_1.PlannerTelemetry(path.join(OPT_DIR, ".progmune_corpus", "telemetry", `opt-${Date.now()}.jsonl`));
|
|
75
|
+
// Pattern: "open_file → write_file → close_file" accepted 90% of the time
|
|
76
|
+
for (let i = 0; i < n; i++) {
|
|
77
|
+
const actions = ["open_file", "write_file", "close_file"];
|
|
78
|
+
const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", actions, "resource_leak");
|
|
79
|
+
const id = t.recordDecision({
|
|
80
|
+
goal: "safely write config file",
|
|
81
|
+
protocol: "FileProtocol", violationType: "resource_leak",
|
|
82
|
+
candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions, explanation: "full sequence" }],
|
|
83
|
+
selectedCandidateId: fp,
|
|
84
|
+
cost: { latencyMs: 3 + Math.random() * 5 },
|
|
85
|
+
});
|
|
86
|
+
const accepted = Math.random() < 0.9;
|
|
87
|
+
t.recordFeedback(id, {
|
|
88
|
+
decision: accepted ? "accepted" : "rejected",
|
|
89
|
+
executionResult: accepted ? { success: true, violations: [] } : { success: false, violations: ["resource_leak"] },
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// Auth pattern: accepted 85%
|
|
94
|
+
for (let i = 0; i < n; i++) {
|
|
95
|
+
const actions = ["verify_password", "generate_jwt", "create_session"];
|
|
96
|
+
const fp = (0, planner_telemetry_1.candidateFingerprint)("AuthProtocol", actions, "missing_prerequisite");
|
|
97
|
+
const id = t.recordDecision({
|
|
98
|
+
goal: "authenticate user",
|
|
99
|
+
protocol: "AuthProtocol", violationType: "missing_prerequisite",
|
|
100
|
+
candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions, explanation: "auth flow" }],
|
|
101
|
+
selectedCandidateId: fp,
|
|
102
|
+
});
|
|
103
|
+
const accepted = Math.random() < 0.85;
|
|
104
|
+
t.recordFeedback(id, {
|
|
105
|
+
decision: accepted ? "accepted" : "rejected",
|
|
106
|
+
executionResult: accepted ? { success: true, violations: [] } : undefined,
|
|
107
|
+
timestamp: Date.now(),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return t;
|
|
111
|
+
}
|
|
112
|
+
(0, vitest_1.describe)("P4.5 Reward-Guided Frontier", () => {
|
|
113
|
+
(0, vitest_1.it)("guided search finds paths with priority ordering", () => {
|
|
114
|
+
const rules = mergeProtocolRules(authRules, fileRules, dbRules);
|
|
115
|
+
const paths = (0, guided_frontier_1.guidedSearch)(rules, ["UNAUTHENTICATED"], ["SESSION_ACTIVE"]);
|
|
116
|
+
(0, vitest_1.expect)(paths.length).toBeGreaterThan(0);
|
|
117
|
+
// Should find auth path
|
|
118
|
+
const hasAuth = paths.some(p => p.actions.includes("verify_password") && p.actions.includes("generate_jwt"));
|
|
119
|
+
(0, vitest_1.expect)(hasAuth).toBe(true);
|
|
120
|
+
// Paths should be sorted by priority (descending)
|
|
121
|
+
for (let i = 1; i < paths.length; i++) {
|
|
122
|
+
(0, vitest_1.expect)(paths[i - 1].priority).toBeGreaterThanOrEqual(paths[i].priority);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
(0, vitest_1.it)("multi-start finds paths from different initial states", () => {
|
|
126
|
+
const rules = mergeProtocolRules(fileRules, authRules);
|
|
127
|
+
const paths = (0, guided_frontier_1.guidedSearchMulti)(rules, [
|
|
128
|
+
["FILE_OPEN"],
|
|
129
|
+
["UNAUTHENTICATED"],
|
|
130
|
+
], ["SESSION_ACTIVE"]);
|
|
131
|
+
(0, vitest_1.expect)(paths.length).toBeGreaterThan(0);
|
|
132
|
+
// Should include paths from both starting points
|
|
133
|
+
(0, vitest_1.expect)(paths.every(p => p.found)).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
(0, vitest_1.describe)("P4.6 Macro Repair Mining", () => {
|
|
137
|
+
(0, vitest_1.it)("mines high-acceptance patterns from telemetry", () => {
|
|
138
|
+
const telemetry = seedHighAcceptanceTelemetry(50);
|
|
139
|
+
const macros = (0, macro_repair_1.mineMacroRepairs)(telemetry, 0.7, 3);
|
|
140
|
+
(0, vitest_1.expect)(macros.length).toBeGreaterThanOrEqual(1);
|
|
141
|
+
// File repair pattern should be mined
|
|
142
|
+
const fileMacro = macros.find(m => m.protocol === "FileProtocol");
|
|
143
|
+
(0, vitest_1.expect)(fileMacro).toBeDefined();
|
|
144
|
+
(0, vitest_1.expect)(fileMacro.acceptanceRate).toBeGreaterThan(0.7);
|
|
145
|
+
(0, vitest_1.expect)(fileMacro.actions).toEqual(["open_file", "write_file", "close_file"]);
|
|
146
|
+
(0, macro_repair_1.printMacroReport)(macros);
|
|
147
|
+
});
|
|
148
|
+
(0, vitest_1.it)("persists and loads macros", () => {
|
|
149
|
+
const telemetry = seedHighAcceptanceTelemetry(60);
|
|
150
|
+
const mined = (0, macro_repair_1.mineMacroRepairs)(telemetry, 0.7, 3);
|
|
151
|
+
const fp = (0, macro_repair_1.saveMacroRepairs)(mined);
|
|
152
|
+
(0, vitest_1.expect)(fs.existsSync(fp)).toBe(true);
|
|
153
|
+
const loaded = (0, macro_repair_1.loadMacroRepairs)();
|
|
154
|
+
(0, vitest_1.expect)(loaded.length).toBeGreaterThanOrEqual(mined.length);
|
|
155
|
+
});
|
|
156
|
+
(0, vitest_1.it)("filters out low-frequency patterns", () => {
|
|
157
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(OPT_DIR, ".progmune_corpus", "telemetry", `lowfreq-${Date.now()}.jsonl`));
|
|
158
|
+
// Only 2 samples — below minFrequency=3
|
|
159
|
+
for (let i = 0; i < 2; i++) {
|
|
160
|
+
const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["close_file"], "resource_leak");
|
|
161
|
+
const id = telemetry.recordDecision({
|
|
162
|
+
goal: "test", protocol: "FileProtocol",
|
|
163
|
+
candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions: ["close_file"], explanation: "close" }],
|
|
164
|
+
selectedCandidateId: fp,
|
|
165
|
+
});
|
|
166
|
+
telemetry.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, timestamp: Date.now() });
|
|
167
|
+
}
|
|
168
|
+
const macros = (0, macro_repair_1.mineMacroRepairs)(telemetry, 0.7, 3);
|
|
169
|
+
(0, vitest_1.expect)(macros.length).toBe(0); // not enough frequency
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
(0, vitest_1.describe)("P4.7 Discovery Analytics", () => {
|
|
173
|
+
(0, vitest_1.it)("computes discovery metrics from attributions", () => {
|
|
174
|
+
const attributed = [
|
|
175
|
+
{ caseId: "c1", goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak", expectedRepair: ["close_file"], candidatesReturned: 2, rank: 1, failureReason: "success" },
|
|
176
|
+
{ caseId: "c2", goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak", expectedRepair: ["close_file"], candidatesReturned: 1, rank: null, failureReason: "bad_ranking" },
|
|
177
|
+
{ caseId: "c3", goal: "authenticate", protocol: "AuthProtocol", violationType: "missing_prerequisite", expectedRepair: ["generate_jwt"], candidatesReturned: 0, rank: null, failureReason: "missing_candidate" },
|
|
178
|
+
{ caseId: "c4", goal: "logout user", protocol: "AuthProtocol", violationType: "illegal_state_transition", expectedRepair: ["logout"], candidatesReturned: 0, rank: null, failureReason: "missing_candidate" },
|
|
179
|
+
];
|
|
180
|
+
const metrics = (0, discovery_analytics_1.computeDiscoveryMetrics)(attributed);
|
|
181
|
+
(0, vitest_1.expect)(metrics.totalCases).toBe(4);
|
|
182
|
+
(0, vitest_1.expect)(metrics.overall).toBe(0.5); // 2/4 discovered
|
|
183
|
+
// FileProtocol: 2/2 discovered
|
|
184
|
+
(0, vitest_1.expect)(metrics.byProtocol["FileProtocol"]).toBe(1.0);
|
|
185
|
+
// AuthProtocol: 0/2 discovered
|
|
186
|
+
(0, vitest_1.expect)(metrics.byProtocol["AuthProtocol"]).toBe(0);
|
|
187
|
+
// resource_leak: 2/2, missing_prerequisite: 0/1, illegal_state_transition: 0/1
|
|
188
|
+
(0, vitest_1.expect)(metrics.byViolation["resource_leak"]).toBe(1.0);
|
|
189
|
+
(0, vitest_1.expect)(metrics.byViolation["missing_prerequisite"]).toBe(0);
|
|
190
|
+
});
|
|
191
|
+
(0, vitest_1.it)("generates full analytics report", async () => {
|
|
192
|
+
const telemetry = seedHighAcceptanceTelemetry(30);
|
|
193
|
+
const report = await (0, discovery_analytics_1.generateFullAnalyticsReport)(telemetry);
|
|
194
|
+
(0, vitest_1.expect)(report.discovery.totalCases).toBeGreaterThanOrEqual(49);
|
|
195
|
+
(0, vitest_1.expect)(report.macroCount).toBeGreaterThanOrEqual(1);
|
|
196
|
+
(0, vitest_1.expect)(report.topMacros.length).toBeGreaterThanOrEqual(1);
|
|
197
|
+
(0, discovery_analytics_1.printDiscoveryDashboard)(report);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P3.24-27: Search Trace + Bridge Learning + Discovery Benchmark + Replay
|
|
4
|
+
*
|
|
5
|
+
* P3.24: Record WHY candidates are missing. Decompose 57% missing_candidate
|
|
6
|
+
* into missing_action, missing_transition, depth_limit, bridge_missing.
|
|
7
|
+
*
|
|
8
|
+
* P3.25: Protocol Bridge Learning — cross-protocol state bridges.
|
|
9
|
+
* Auth → File → DB → IR → Queue. Frontier BFS across protocols.
|
|
10
|
+
*
|
|
11
|
+
* P3.26: Discovery Benchmark — three-tier metric:
|
|
12
|
+
* DiscoveryRate (any correct candidate?) → Ranking (Top-1/Top-3) → Execution.
|
|
13
|
+
*
|
|
14
|
+
* P3.27: Counterfactual Replay — off-policy evaluation.
|
|
15
|
+
* Replay historical decisions with new ranker/frontier, compare acceptance.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.traceSearch = traceSearch;
|
|
19
|
+
exports.decomposeMissingCandidate = decomposeMissingCandidate;
|
|
20
|
+
exports.computeDiscoveryReport = computeDiscoveryReport;
|
|
21
|
+
exports.printDiscoveryReport = printDiscoveryReport;
|
|
22
|
+
exports.evaluateOffPolicy = evaluateOffPolicy;
|
|
23
|
+
exports.printReplayEvaluation = printReplayEvaluation;
|
|
24
|
+
exports.learnProtocolBridges = learnProtocolBridges;
|
|
25
|
+
const protocol_coverage_1 = require("./protocol-coverage");
|
|
26
|
+
/**
|
|
27
|
+
* Trace a frontier search and classify WHY candidates are missing.
|
|
28
|
+
*/
|
|
29
|
+
function traceSearch(rules, currentStates, targetStates, expectedRepair, strategy = "frontier", goal, maxDepth = 6) {
|
|
30
|
+
const trace = {
|
|
31
|
+
strategy, goal,
|
|
32
|
+
expandedNodes: [], prunedNodes: [], deadEnds: [],
|
|
33
|
+
maxDepthReached: 0, candidateGenerated: false, candidateCount: 0,
|
|
34
|
+
};
|
|
35
|
+
const visited = new Set();
|
|
36
|
+
const queue = [
|
|
37
|
+
{ states: new Set(currentStates), actions: [], depth: 0 },
|
|
38
|
+
];
|
|
39
|
+
visited.add([...currentStates].sort().join(","));
|
|
40
|
+
while (queue.length > 0) {
|
|
41
|
+
const { states, actions, depth } = queue.shift();
|
|
42
|
+
trace.maxDepthReached = Math.max(trace.maxDepthReached, depth);
|
|
43
|
+
if (depth >= maxDepth) {
|
|
44
|
+
trace.deadEnds.push({ node: [...states].join(","), reason: "depth_limit" });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
let anyRuleApplied = false;
|
|
48
|
+
for (const [fn, rule] of rules) {
|
|
49
|
+
const preOk = rule.pre_states.length === 0 || rule.pre_states.every(p => states.has(p));
|
|
50
|
+
if (!preOk)
|
|
51
|
+
continue;
|
|
52
|
+
anyRuleApplied = true;
|
|
53
|
+
const next = new Set(states);
|
|
54
|
+
if (rule.invalidate)
|
|
55
|
+
rule.invalidate.forEach(s => next.delete(s));
|
|
56
|
+
for (const post of rule.post_states)
|
|
57
|
+
next.add(post);
|
|
58
|
+
const key = [...next].sort().join(",");
|
|
59
|
+
if (visited.has(key))
|
|
60
|
+
continue;
|
|
61
|
+
visited.add(key);
|
|
62
|
+
trace.expandedNodes.push(fn);
|
|
63
|
+
const newActions = [...actions, fn];
|
|
64
|
+
// Check if this reaches the expected repair
|
|
65
|
+
if (expectedRepair.every(fn => newActions.includes(fn))) {
|
|
66
|
+
trace.candidateGenerated = true;
|
|
67
|
+
trace.candidateCount++;
|
|
68
|
+
}
|
|
69
|
+
queue.push({ states: next, actions: newActions, depth: depth + 1 });
|
|
70
|
+
}
|
|
71
|
+
if (!anyRuleApplied && depth > 0) {
|
|
72
|
+
trace.deadEnds.push({ node: [...states].join(","), reason: "precondition_failed" });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Classify missing candidates by analyzing dead ends
|
|
76
|
+
for (const fn of expectedRepair) {
|
|
77
|
+
if (!rules.has(fn)) {
|
|
78
|
+
trace.deadEnds.push({ node: fn, reason: "missing_action" });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return trace;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Decompose a search failure into root causes.
|
|
85
|
+
*/
|
|
86
|
+
function decomposeMissingCandidate(traces) {
|
|
87
|
+
const result = {
|
|
88
|
+
total: traces.length,
|
|
89
|
+
missingAction: 0,
|
|
90
|
+
missingTransition: 0,
|
|
91
|
+
depthLimit: 0,
|
|
92
|
+
bridgeMissing: 0,
|
|
93
|
+
preconditionFailed: 0,
|
|
94
|
+
};
|
|
95
|
+
for (const t of traces) {
|
|
96
|
+
if (t.candidateGenerated)
|
|
97
|
+
continue;
|
|
98
|
+
for (const de of t.deadEnds) {
|
|
99
|
+
switch (de.reason) {
|
|
100
|
+
case "missing_action":
|
|
101
|
+
result.missingAction++;
|
|
102
|
+
break;
|
|
103
|
+
case "missing_transition":
|
|
104
|
+
result.missingTransition++;
|
|
105
|
+
break;
|
|
106
|
+
case "depth_limit":
|
|
107
|
+
result.depthLimit++;
|
|
108
|
+
break;
|
|
109
|
+
case "bridge_missing":
|
|
110
|
+
result.bridgeMissing++;
|
|
111
|
+
break;
|
|
112
|
+
case "precondition_failed":
|
|
113
|
+
result.preconditionFailed++;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
function computeDiscoveryReport(results) {
|
|
121
|
+
const total = results.length;
|
|
122
|
+
const discovered = results.filter(r => r.discovery).length;
|
|
123
|
+
const top1 = results.filter(r => r.top1Hit).length;
|
|
124
|
+
const top3 = results.filter(r => r.top3Hit).length;
|
|
125
|
+
const avgCand = results.reduce((s, r) => s + r.candidateCount, 0) / Math.max(1, total);
|
|
126
|
+
// Aggregate decompositions
|
|
127
|
+
const allTraces = results
|
|
128
|
+
.filter(r => !r.discovery && r.decomposition)
|
|
129
|
+
.map(r => r.decomposition);
|
|
130
|
+
const merged = {
|
|
131
|
+
total: allTraces.length,
|
|
132
|
+
missingAction: allTraces.reduce((s, d) => s + d.missingAction, 0),
|
|
133
|
+
missingTransition: allTraces.reduce((s, d) => s + d.missingTransition, 0),
|
|
134
|
+
depthLimit: allTraces.reduce((s, d) => s + d.depthLimit, 0),
|
|
135
|
+
bridgeMissing: allTraces.reduce((s, d) => s + d.bridgeMissing, 0),
|
|
136
|
+
preconditionFailed: allTraces.reduce((s, d) => s + d.preconditionFailed, 0),
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
cases: total,
|
|
140
|
+
discoveryRate: total > 0 ? discovered / total : 0,
|
|
141
|
+
top3Rate: total > 0 ? top3 / total : 0,
|
|
142
|
+
top1Rate: total > 0 ? top1 / total : 0,
|
|
143
|
+
avgCandidates: avgCand,
|
|
144
|
+
gapBreakdown: merged,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function printDiscoveryReport(report) {
|
|
148
|
+
console.log("\n╔════════════════════════════════════════════════════╗");
|
|
149
|
+
console.log("║ Discovery Benchmark ║");
|
|
150
|
+
console.log("╚════════════════════════════════════════════════════╝\n");
|
|
151
|
+
const dr = (report.discoveryRate * 100).toFixed(0);
|
|
152
|
+
const t1 = (report.top1Rate * 100).toFixed(0);
|
|
153
|
+
const t3 = (report.top3Rate * 100).toFixed(0);
|
|
154
|
+
console.log(`Cases: ${report.cases}`);
|
|
155
|
+
console.log(`Discovery Rate: ${dr}% (any correct candidate found)`);
|
|
156
|
+
console.log(`Top-3 Accuracy: ${t3}%`);
|
|
157
|
+
console.log(`Top-1 Accuracy: ${t1}%`);
|
|
158
|
+
console.log(`Avg Candidates: ${report.avgCandidates.toFixed(1)}`);
|
|
159
|
+
console.log();
|
|
160
|
+
if (report.gapBreakdown.total > 0) {
|
|
161
|
+
console.log("─── Missing Candidate Decomposition ───");
|
|
162
|
+
const g = report.gapBreakdown;
|
|
163
|
+
console.log(` missing_action: ${g.missingAction}`);
|
|
164
|
+
console.log(` missing_transition: ${g.missingTransition}`);
|
|
165
|
+
console.log(` depth_limit: ${g.depthLimit}`);
|
|
166
|
+
console.log(` bridge_missing: ${g.bridgeMissing}`);
|
|
167
|
+
console.log(` precondition_failed: ${g.preconditionFailed}`);
|
|
168
|
+
console.log();
|
|
169
|
+
}
|
|
170
|
+
const discoveryGap = report.discoveryRate - report.top1Rate;
|
|
171
|
+
if (discoveryGap > 0.15) {
|
|
172
|
+
console.log(` ⚠️ Discovery→Top1 gap: ${(discoveryGap * 100).toFixed(0)}% — ranking is the bottleneck`);
|
|
173
|
+
}
|
|
174
|
+
else if (report.discoveryRate < 0.5) {
|
|
175
|
+
console.log(` ⚠️ Discovery < 50% — candidate generation is the bottleneck`);
|
|
176
|
+
}
|
|
177
|
+
console.log();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Off-policy evaluation: compare old system vs new system.
|
|
181
|
+
*
|
|
182
|
+
* Given historical decisions (what was proposed, what was accepted),
|
|
183
|
+
* and a new candidate generator, compute how the new system would
|
|
184
|
+
* have performed on the same decisions.
|
|
185
|
+
*/
|
|
186
|
+
function evaluateOffPolicy(decisions, newCandidateGenerator, matchFn = (c, a) => a.every(fn => c.includes(fn))) {
|
|
187
|
+
let baselineAccepted = 0;
|
|
188
|
+
let newAccepted = 0;
|
|
189
|
+
for (const d of decisions) {
|
|
190
|
+
// Baseline: was the accepted candidate in the original proposals?
|
|
191
|
+
if (d.acceptedActions) {
|
|
192
|
+
const baseMatch = d.candidates.some(c => matchFn(c, d.acceptedActions));
|
|
193
|
+
if (baseMatch)
|
|
194
|
+
baselineAccepted++;
|
|
195
|
+
}
|
|
196
|
+
// New: would the new generator have found the accepted candidate?
|
|
197
|
+
const newCandidates = newCandidateGenerator(d.goal, d.protocol);
|
|
198
|
+
if (d.acceptedActions && newCandidates.some(c => matchFn(c, d.acceptedActions))) {
|
|
199
|
+
newAccepted++;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const total = decisions.length;
|
|
203
|
+
return {
|
|
204
|
+
totalDecisions: total,
|
|
205
|
+
baselineAccepted,
|
|
206
|
+
baselineRate: total > 0 ? baselineAccepted / total : 0,
|
|
207
|
+
newAccepted,
|
|
208
|
+
newRate: total > 0 ? newAccepted / total : 0,
|
|
209
|
+
delta: total > 0 ? (newAccepted - baselineAccepted) / total : 0,
|
|
210
|
+
improvement: newAccepted > baselineAccepted,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function printReplayEvaluation(eval_) {
|
|
214
|
+
console.log("\n╔════════════════════════════════════════════════════╗");
|
|
215
|
+
console.log("║ Counterfactual Replay (Off-Policy) ║");
|
|
216
|
+
console.log("╚════════════════════════════════════════════════════╝\n");
|
|
217
|
+
const base = (eval_.baselineRate * 100).toFixed(1);
|
|
218
|
+
const nw = (eval_.newRate * 100).toFixed(1);
|
|
219
|
+
const delta = (eval_.delta * 100).toFixed(1);
|
|
220
|
+
const sign = eval_.delta > 0 ? "+" : "";
|
|
221
|
+
console.log(`Decisions Replayed: ${eval_.totalDecisions}`);
|
|
222
|
+
console.log(`Baseline (old): ${base}% (${eval_.baselineAccepted}/${eval_.totalDecisions})`);
|
|
223
|
+
console.log(`New System: ${nw}% (${eval_.newAccepted}/${eval_.totalDecisions})`);
|
|
224
|
+
console.log(`Δ: ${sign}${delta}%`);
|
|
225
|
+
console.log();
|
|
226
|
+
if (eval_.improvement) {
|
|
227
|
+
console.log(` ✅ New system outperforms baseline by ${sign}${delta}%`);
|
|
228
|
+
}
|
|
229
|
+
else if (eval_.delta === 0) {
|
|
230
|
+
console.log(" ═ No change. New system matches baseline.");
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.log(` ❌ New system regresses by ${sign}${delta}%`);
|
|
234
|
+
}
|
|
235
|
+
console.log();
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Learn cross-protocol bridges from benchmark failures.
|
|
239
|
+
*
|
|
240
|
+
* When a benchmark expects auth → file → db chains, but the
|
|
241
|
+
* protocols are isolated, infer bridges connecting them.
|
|
242
|
+
*/
|
|
243
|
+
function learnProtocolBridges(crossProtocolFailures) {
|
|
244
|
+
const defs = (0, protocol_coverage_1.loadDefaultProtocolDefinitions)();
|
|
245
|
+
const protoRules = new Map(defs.map(p => [p.name, p.rules]));
|
|
246
|
+
const bridges = [];
|
|
247
|
+
const bridgeCounts = new Map();
|
|
248
|
+
for (const f of crossProtocolFailures) {
|
|
249
|
+
// Determine which protocols are involved
|
|
250
|
+
const involved = new Set();
|
|
251
|
+
for (const fn of f.expectedRepair) {
|
|
252
|
+
for (const [name, rules] of protoRules) {
|
|
253
|
+
if (rules.has(fn))
|
|
254
|
+
involved.add(name);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const protoList = [...involved];
|
|
258
|
+
for (let i = 0; i < protoList.length - 1; i++) {
|
|
259
|
+
const from = protoList[i];
|
|
260
|
+
const to = protoList[i + 1];
|
|
261
|
+
const key = `${from}→${to}`;
|
|
262
|
+
bridgeCounts.set(key, (bridgeCounts.get(key) || 0) + 1);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const maxCount = Math.max(1, ...[...bridgeCounts.values()]);
|
|
266
|
+
for (const [key, count] of bridgeCounts) {
|
|
267
|
+
const [from, to] = key.split("→");
|
|
268
|
+
bridges.push({
|
|
269
|
+
fromProtocol: from, toProtocol: to,
|
|
270
|
+
viaState: "COMPLETED", targetState: "INIT",
|
|
271
|
+
confidence: count / maxCount,
|
|
272
|
+
evidenceCount: count,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return bridges.sort((a, b) => b.confidence - a.confidence);
|
|
276
|
+
}
|