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
package/dist/repair-proposal.js
CHANGED
|
@@ -102,7 +102,7 @@ function suggestInvariantRepair(violation, ledger, namespaceInitialStates = (0,
|
|
|
102
102
|
const proposals = [];
|
|
103
103
|
if (violation.invariant === "before-consistency") {
|
|
104
104
|
// statesBefore is wrong — can be recomputed from rebuildState
|
|
105
|
-
const correctStatesBefore = violation.expected;
|
|
105
|
+
const correctStatesBefore = violation.expected || {};
|
|
106
106
|
const t = ledger[violation.index];
|
|
107
107
|
if (!t)
|
|
108
108
|
return [];
|
|
@@ -114,7 +114,7 @@ function suggestInvariantRepair(violation, ledger, namespaceInitialStates = (0,
|
|
|
114
114
|
try {
|
|
115
115
|
(0, runtime_invariants_1.assertDeltaConsistency)(correctedTransition);
|
|
116
116
|
}
|
|
117
|
-
catch { }
|
|
117
|
+
catch { /* consistency assertion — best-effort */ }
|
|
118
118
|
proposals.push({
|
|
119
119
|
id: `rp_${Date.now()}_${Math.random().toString(36).slice(2, 5)}`,
|
|
120
120
|
violationIndex: violation.index,
|
|
@@ -128,7 +128,7 @@ function suggestInvariantRepair(violation, ledger, namespaceInitialStates = (0,
|
|
|
128
128
|
}
|
|
129
129
|
if (violation.invariant === "delta-consistency") {
|
|
130
130
|
// statesAfter doesn't match applyDelta(statesBefore, acquired, invalidated)
|
|
131
|
-
const correctStatesAfter = violation.expected;
|
|
131
|
+
const correctStatesAfter = violation.expected || {};
|
|
132
132
|
const t = ledger[violation.index];
|
|
133
133
|
if (!t)
|
|
134
134
|
return [];
|
|
@@ -139,7 +139,7 @@ function suggestInvariantRepair(violation, ledger, namespaceInitialStates = (0,
|
|
|
139
139
|
try {
|
|
140
140
|
(0, runtime_invariants_1.assertDeltaConsistency)(correctedTransition);
|
|
141
141
|
}
|
|
142
|
-
catch { }
|
|
142
|
+
catch { /* consistency assertion — best-effort */ }
|
|
143
143
|
proposals.push({
|
|
144
144
|
id: `rp_${Date.now()}_${Math.random().toString(36).slice(2, 5)}`,
|
|
145
145
|
violationIndex: violation.index,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P2: Repair Ranker — Feature Extraction & Linear Ranking
|
|
4
|
+
*
|
|
5
|
+
* FeatureExtractor: RepairCandidate → CandidateFeatures
|
|
6
|
+
* LinearRanker: CandidateFeatures[] → ranked RepairCandidate[]
|
|
7
|
+
*
|
|
8
|
+
* Default weights (P3 — manual):
|
|
9
|
+
* score = 0.4 * protocolSafety + 0.3 * historicalSuccessRate
|
|
10
|
+
* + 0.2 * performance + 0.1 * auditability
|
|
11
|
+
*
|
|
12
|
+
* Future P4: swap LinearRanker for RewardModelRanker — same interface.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.extractFeatures = extractFeatures;
|
|
16
|
+
exports.createLinearRanker = createLinearRanker;
|
|
17
|
+
exports.rankCandidates = rankCandidates;
|
|
18
|
+
/**
|
|
19
|
+
* Extract a feature vector from a repair candidate.
|
|
20
|
+
*
|
|
21
|
+
* All features are in [0, 1] range where possible, so the Ranker
|
|
22
|
+
* can combine them with simple linear weights.
|
|
23
|
+
*/
|
|
24
|
+
function extractFeatures(candidate, ctx, corpusStats) {
|
|
25
|
+
const actionCount = candidate.actions.length;
|
|
26
|
+
const maxActions = corpusStats?.maxActions || Math.max(actionCount, 8);
|
|
27
|
+
// ── protocolSafety ──
|
|
28
|
+
// Candidates that satisfy more constraints are safer.
|
|
29
|
+
// Shorter paths are inherently safer (fewer things can go wrong).
|
|
30
|
+
const safetyFromLength = 1.0 - actionCount / 10;
|
|
31
|
+
const constraintMatch = ctx.constraints.length > 0
|
|
32
|
+
? ctx.constraints.filter(c => c.type === "safety" || c.type === "security").length
|
|
33
|
+
/ Math.max(1, ctx.constraints.length)
|
|
34
|
+
: 0.5;
|
|
35
|
+
const protocolSafety = Math.max(0, Math.min(1, safetyFromLength * 0.6 + constraintMatch * 0.4));
|
|
36
|
+
// ── historicalSuccessRate ──
|
|
37
|
+
// From corpus strategy metadata, or 0 if not available.
|
|
38
|
+
const historicalSuccessRate = candidate.metadata?.historicalSuccessRate || 0;
|
|
39
|
+
// ── actionCount ──
|
|
40
|
+
// Raw count — used by rankPerformance.
|
|
41
|
+
// ── latencyCost ──
|
|
42
|
+
// Inverted: more actions = higher latency cost.
|
|
43
|
+
const latencyCost = Math.min(1, actionCount / maxActions);
|
|
44
|
+
// ── auditability ──
|
|
45
|
+
// Shorter paths are easier to audit.
|
|
46
|
+
const auditability = Math.max(0, 1.0 - actionCount / maxActions);
|
|
47
|
+
// ── corpusEvidence ──
|
|
48
|
+
const corpusEvidence = candidate.metadata?.corpusEvidenceCount || 0;
|
|
49
|
+
// ── goalMatch (P7.3) ──
|
|
50
|
+
// Candidates from goal-template matching get a 1.0 boost.
|
|
51
|
+
// Cross-protocol and frontier candidates get a 0.3 partial boost
|
|
52
|
+
// since they still represent structured protocol knowledge.
|
|
53
|
+
const metaSource = candidate.metadata?.source;
|
|
54
|
+
const goalMatch = metaSource === "goal-template" ? 1.0
|
|
55
|
+
: metaSource === "cross-protocol" ? 0.3
|
|
56
|
+
: 0.0;
|
|
57
|
+
return {
|
|
58
|
+
protocolSafety,
|
|
59
|
+
historicalSuccessRate,
|
|
60
|
+
actionCount,
|
|
61
|
+
latencyCost,
|
|
62
|
+
auditability,
|
|
63
|
+
corpusEvidence,
|
|
64
|
+
source: candidate.source,
|
|
65
|
+
goalMatch,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// ═══════════════════════════════════════════════════════════════
|
|
69
|
+
// Linear Ranker
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════
|
|
71
|
+
/** Default P3 manual weights. Tune these from corpus data. */
|
|
72
|
+
const DEFAULT_WEIGHTS = {
|
|
73
|
+
safety: 0.30,
|
|
74
|
+
successRate: 0.15,
|
|
75
|
+
performance: 0.10,
|
|
76
|
+
auditability: 0.10,
|
|
77
|
+
goalMatch: 0.35, // P7.3: boost goal-template candidates heavily
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Create a linear ranker with configurable weights.
|
|
81
|
+
*
|
|
82
|
+
* Usage:
|
|
83
|
+
* const ranker = createLinearRanker(); // defaults
|
|
84
|
+
* const ranker = createLinearRanker({ safety: 0.5 }); // safety-first
|
|
85
|
+
*/
|
|
86
|
+
function createLinearRanker(weights) {
|
|
87
|
+
const w = { ...DEFAULT_WEIGHTS, ...weights };
|
|
88
|
+
/** Compute performance from features: fewer actions = better. */
|
|
89
|
+
function performanceScore(f) {
|
|
90
|
+
return 1.0 - Math.min(1, f.actionCount / Math.max(1, f.actionCount + 3));
|
|
91
|
+
}
|
|
92
|
+
/** Compute the weighted overall score. */
|
|
93
|
+
function overallScore(f) {
|
|
94
|
+
return (w.safety * f.protocolSafety +
|
|
95
|
+
w.successRate * f.historicalSuccessRate +
|
|
96
|
+
w.performance * performanceScore(f) +
|
|
97
|
+
w.auditability * f.auditability +
|
|
98
|
+
w.goalMatch * (f.goalMatch || 0));
|
|
99
|
+
}
|
|
100
|
+
/** Zip candidates with features and sort by a scoring function. */
|
|
101
|
+
function rankBy(candidates, features, scoreFn) {
|
|
102
|
+
const paired = candidates.map((c, i) => ({
|
|
103
|
+
candidate: c,
|
|
104
|
+
score: scoreFn(features[i]),
|
|
105
|
+
}));
|
|
106
|
+
paired.sort((a, b) => b.score - a.score);
|
|
107
|
+
return paired.map(p => p.candidate);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
score(features) {
|
|
111
|
+
return overallScore(features);
|
|
112
|
+
},
|
|
113
|
+
rankSafety(candidates, features) {
|
|
114
|
+
return rankBy(candidates, features, f => f.protocolSafety);
|
|
115
|
+
},
|
|
116
|
+
rankPerformance(candidates, features) {
|
|
117
|
+
return rankBy(candidates, features, f => performanceScore(f));
|
|
118
|
+
},
|
|
119
|
+
rankAuditability(candidates, features) {
|
|
120
|
+
return rankBy(candidates, features, f => f.auditability);
|
|
121
|
+
},
|
|
122
|
+
rankOverall(candidates, features) {
|
|
123
|
+
return rankBy(candidates, features, f => overallScore(f));
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ═══════════════════════════════════════════════════════════════
|
|
128
|
+
// Convenience: rankCandidates
|
|
129
|
+
// ═══════════════════════════════════════════════════════════════
|
|
130
|
+
/**
|
|
131
|
+
* Rank candidates using the linear ranker in one call.
|
|
132
|
+
* Convenience wrapper around extractFeatures + createLinearRanker.
|
|
133
|
+
*/
|
|
134
|
+
function rankCandidates(candidates, ctx, mode = "overall") {
|
|
135
|
+
const maxActions = Math.max(...candidates.map(c => c.actions.length), 8);
|
|
136
|
+
const features = candidates.map(c => extractFeatures(c, ctx, { maxActions }));
|
|
137
|
+
const ranker = createLinearRanker();
|
|
138
|
+
const ranked = ranker.rankOverall(candidates, features);
|
|
139
|
+
// Assign rank fields
|
|
140
|
+
return ranked.map((c, i) => ({ ...c, rank: i + 1 }));
|
|
141
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P2: Repair Search Strategies — Candidate Producers
|
|
4
|
+
*
|
|
5
|
+
* Each strategy searches a different knowledge source for repair candidates.
|
|
6
|
+
* Strategies MUST NOT score candidates — they find, the Ranker ranks.
|
|
7
|
+
*
|
|
8
|
+
* Three knowledge sources:
|
|
9
|
+
* 1. Corpus — historical trajectory data (empirical)
|
|
10
|
+
* 2. Protocol — SSG state graph BFS (logical)
|
|
11
|
+
* 3. Antibody — learned immune rules (heuristic)
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.AntibodySearchStrategy = exports.ProtocolSearchStrategy = exports.CorpusSearchStrategy = void 0;
|
|
48
|
+
exports.createDefaultStrategies = createDefaultStrategies;
|
|
49
|
+
const fs = __importStar(require("fs"));
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
52
|
+
const ssg_validator_1 = require("./ssg-validator");
|
|
53
|
+
const goal_planner_1 = require("./goal-planner");
|
|
54
|
+
const protocol_frontier_1 = require("./protocol-frontier");
|
|
55
|
+
// ═══════════════════════════════════════════════════════════════
|
|
56
|
+
// Helpers
|
|
57
|
+
// ═══════════════════════════════════════════════════════════════
|
|
58
|
+
/** Convert a string function name to a call Action for the candidate. */
|
|
59
|
+
function fnToAction(name) {
|
|
60
|
+
return { kind: "call", function: name, args: [] };
|
|
61
|
+
}
|
|
62
|
+
/** Generate a stable ID from source + action sequence. */
|
|
63
|
+
function candidateId(source, actions) {
|
|
64
|
+
const sig = actions.map(a => a.kind === "call" ? (a.function || "?") : a.kind).join("-");
|
|
65
|
+
return `${source}-${sig.slice(0, 80)}`;
|
|
66
|
+
}
|
|
67
|
+
/** Find functions that invalidate current states (resource cleanup). */
|
|
68
|
+
function findCleanupFunctions(ctx) {
|
|
69
|
+
const candidates = [];
|
|
70
|
+
// Pass 1: exact match — function invalidates a current state AND all pre-states are satisfied
|
|
71
|
+
for (const [funcName, rule] of ctx.rules) {
|
|
72
|
+
const invalidates = rule.invalidate || [];
|
|
73
|
+
const matchesCurrent = invalidates.some(s => ctx.currentState.includes(s));
|
|
74
|
+
if (matchesCurrent && rule.pre_states.every(p => ctx.currentState.includes(p))) {
|
|
75
|
+
const actions = [fnToAction(funcName)];
|
|
76
|
+
candidates.push({
|
|
77
|
+
id: candidateId("protocol", actions),
|
|
78
|
+
source: "protocol",
|
|
79
|
+
actions,
|
|
80
|
+
explanation: `资源清理: 调用 ${funcName} 以释放 ${invalidates.filter(s => ctx.currentState.includes(s)).join(", ")}`,
|
|
81
|
+
evidence: 0,
|
|
82
|
+
metadata: { pathLength: 1, cleanupTargets: invalidates, source: "cleanup" },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Pass 2 (P0): relaxed match — function invalidates a current state even if not all
|
|
87
|
+
// pre-states are satisfied. This catches cases where the current state snapshot
|
|
88
|
+
// is incomplete (e.g., namespace mismatch).
|
|
89
|
+
// But we still require at least one pre-state to be present — completely unrelated
|
|
90
|
+
// cleanup functions should not be suggested.
|
|
91
|
+
if (candidates.length === 0) {
|
|
92
|
+
for (const [funcName, rule] of ctx.rules) {
|
|
93
|
+
const invalidates = rule.invalidate || [];
|
|
94
|
+
const matchesCurrent = invalidates.some(s => ctx.currentState.includes(s));
|
|
95
|
+
const hasAnyPreState = rule.pre_states.length === 0 ||
|
|
96
|
+
rule.pre_states.some(p => ctx.currentState.includes(p));
|
|
97
|
+
if (matchesCurrent && hasAnyPreState) {
|
|
98
|
+
const actions = [fnToAction(funcName)];
|
|
99
|
+
candidates.push({
|
|
100
|
+
id: candidateId("protocol", actions),
|
|
101
|
+
source: "protocol",
|
|
102
|
+
actions,
|
|
103
|
+
explanation: `资源清理(fuzzy): 调用 ${funcName} 以释放 ${invalidates.filter(s => ctx.currentState.includes(s)).join(", ")}`,
|
|
104
|
+
evidence: 0,
|
|
105
|
+
metadata: { pathLength: 1, cleanupTargets: invalidates, source: "cleanup-fuzzy" },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Pass 3 (P0): last-resort — ANY function that invalidates ANY resource-like state
|
|
111
|
+
// that looks like it could be leaked (contains OPEN, CONNECTED, ACTIVE, LOCKED).
|
|
112
|
+
if (candidates.length === 0) {
|
|
113
|
+
const leakableStates = ctx.currentState.filter(s => /OPEN|CONNECTED|ACTIVE|LOCKED|ALLOCATED|ACQUIRED|HELD/i.test(s));
|
|
114
|
+
if (leakableStates.length > 0) {
|
|
115
|
+
for (const [funcName, rule] of ctx.rules) {
|
|
116
|
+
const invalidates = rule.invalidate || [];
|
|
117
|
+
if (invalidates.some(s => leakableStates.includes(s))) {
|
|
118
|
+
const actions = [fnToAction(funcName)];
|
|
119
|
+
candidates.push({
|
|
120
|
+
id: candidateId("protocol", actions),
|
|
121
|
+
source: "protocol",
|
|
122
|
+
actions,
|
|
123
|
+
explanation: `推测性资源清理: 调用 ${funcName} 以释放疑似泄漏状态 ${leakableStates.join(", ")}`,
|
|
124
|
+
evidence: 0,
|
|
125
|
+
metadata: { pathLength: 1, cleanupTargets: invalidates, source: "cleanup-heuristic" },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return candidates;
|
|
132
|
+
}
|
|
133
|
+
// ═══════════════════════════════════════════════════════════════
|
|
134
|
+
// P3.10: Goal-expanded candidate generation
|
|
135
|
+
// ═══════════════════════════════════════════════════════════════
|
|
136
|
+
/** Expand a goal into protocol candidates using Goal Templates. */
|
|
137
|
+
function expandGoalAsCandidates(goal, ctx) {
|
|
138
|
+
const planner = (0, goal_planner_1.getGoalPlanner)();
|
|
139
|
+
const actionSets = planner.getCandidateActions(goal);
|
|
140
|
+
if (actionSets.length === 0)
|
|
141
|
+
return [];
|
|
142
|
+
return actionSets.map(actions => ({
|
|
143
|
+
id: candidateId("protocol", actions.map(fnToAction)),
|
|
144
|
+
source: "protocol",
|
|
145
|
+
actions: actions.map(fnToAction),
|
|
146
|
+
explanation: `目标展开: "${goal}" → ${actions.join(" → ")}`,
|
|
147
|
+
evidence: 0,
|
|
148
|
+
metadata: { pathLength: actions.length, source: "goal-template" },
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
// ═══════════════════════════════════════════════════════════════
|
|
152
|
+
// P0: Protocol rules loader — fallback for empty rules Maps
|
|
153
|
+
// ═══════════════════════════════════════════════════════════════
|
|
154
|
+
let _cachedProtocolRules = null;
|
|
155
|
+
/** Load protocol rules from protocols.json as a fallback. */
|
|
156
|
+
function loadProtocolRules() {
|
|
157
|
+
if (_cachedProtocolRules)
|
|
158
|
+
return _cachedProtocolRules;
|
|
159
|
+
try {
|
|
160
|
+
const protocolsPath = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "protocols.json");
|
|
161
|
+
if (fs.existsSync(protocolsPath)) {
|
|
162
|
+
const raw = JSON.parse(fs.readFileSync(protocolsPath, "utf-8"));
|
|
163
|
+
_cachedProtocolRules = new Map();
|
|
164
|
+
if (raw.rules) {
|
|
165
|
+
for (const [fn, rule] of Object.entries(raw.rules)) {
|
|
166
|
+
const r = rule;
|
|
167
|
+
_cachedProtocolRules.set(fn, {
|
|
168
|
+
pre_states: r.pre_states || [],
|
|
169
|
+
post_states: r.post_states || [],
|
|
170
|
+
invalidate: r.invalidate,
|
|
171
|
+
namespace: r.namespace,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch { /* use whatever rules are available */ }
|
|
178
|
+
return _cachedProtocolRules || new Map();
|
|
179
|
+
}
|
|
180
|
+
/** Ensure rules Map has entries — fall back to protocols.json if empty. */
|
|
181
|
+
function ensureRules(ctx) {
|
|
182
|
+
if (ctx.rules.size > 0)
|
|
183
|
+
return ctx.rules;
|
|
184
|
+
return loadProtocolRules();
|
|
185
|
+
}
|
|
186
|
+
// ═══════════════════════════════════════════════════════════════
|
|
187
|
+
// Strategy 1: Corpus Search — historical trajectory data
|
|
188
|
+
// ═══════════════════════════════════════════════════════════════
|
|
189
|
+
class CorpusSearchStrategy {
|
|
190
|
+
constructor() {
|
|
191
|
+
this.name = "corpus";
|
|
192
|
+
}
|
|
193
|
+
search(ctx) {
|
|
194
|
+
const all = (0, failure_corpus_1.loadTrajectories)().filter(t => t.result === "violation" || t.result === "repair");
|
|
195
|
+
if (all.length === 0)
|
|
196
|
+
return [];
|
|
197
|
+
// Filter: same violation type OR same protocol
|
|
198
|
+
const relevant = all.filter(t => (t.violation?.type === ctx.violationType) || t.protocol === ctx.protocol);
|
|
199
|
+
if (relevant.length === 0)
|
|
200
|
+
return [];
|
|
201
|
+
// Group by fix path (deduplicate)
|
|
202
|
+
const pathGroups = new Map();
|
|
203
|
+
for (const t of relevant) {
|
|
204
|
+
const fixPath = t.violation?.fixPath;
|
|
205
|
+
if (!fixPath || fixPath.length === 0)
|
|
206
|
+
continue;
|
|
207
|
+
const key = fixPath.join("→");
|
|
208
|
+
if (!pathGroups.has(key))
|
|
209
|
+
pathGroups.set(key, []);
|
|
210
|
+
pathGroups.get(key).push(t);
|
|
211
|
+
}
|
|
212
|
+
const candidates = [];
|
|
213
|
+
for (const [pathKey, records] of pathGroups) {
|
|
214
|
+
const fixPath = pathKey.split("→");
|
|
215
|
+
const successRate = records.reduce((s, t) => s + t.successRate, 0) / records.length;
|
|
216
|
+
candidates.push({
|
|
217
|
+
id: candidateId("corpus", fixPath.map(fnToAction)),
|
|
218
|
+
source: "corpus",
|
|
219
|
+
actions: fixPath.map(fnToAction),
|
|
220
|
+
explanation: `根据 ${records.length} 个历史案例,补全路径: ${fixPath.join(" → ")}`,
|
|
221
|
+
evidence: records.length,
|
|
222
|
+
metadata: {
|
|
223
|
+
historicalSuccessRate: successRate,
|
|
224
|
+
corpusEvidenceCount: records.length,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return candidates;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
exports.CorpusSearchStrategy = CorpusSearchStrategy;
|
|
232
|
+
// ═══════════════════════════════════════════════════════════════
|
|
233
|
+
// Strategy 2: Protocol Search — SSG state graph BFS
|
|
234
|
+
// ═══════════════════════════════════════════════════════════════
|
|
235
|
+
class ProtocolSearchStrategy {
|
|
236
|
+
constructor() {
|
|
237
|
+
this.name = "protocol";
|
|
238
|
+
}
|
|
239
|
+
search(ctx) {
|
|
240
|
+
// P0: Ensure we have rules to work with
|
|
241
|
+
const rules = ensureRules(ctx);
|
|
242
|
+
const effectiveCtx = { ...ctx, rules };
|
|
243
|
+
// Short-circuit: fall back to generic fix path search
|
|
244
|
+
if (effectiveCtx.currentState.length === 0 || effectiveCtx.targetState.length === 0) {
|
|
245
|
+
// Resource cleanup case: no target state means we need to invalidate current states
|
|
246
|
+
if (effectiveCtx.targetState.length === 0 && effectiveCtx.currentState.length > 0) {
|
|
247
|
+
const cleanupCandidates = findCleanupFunctions(effectiveCtx);
|
|
248
|
+
// P3.10: Goal expansion — add prerequisite chains from goal templates
|
|
249
|
+
const goalCandidates = effectiveCtx.goal ? expandGoalAsCandidates(effectiveCtx.goal, effectiveCtx) : [];
|
|
250
|
+
const all = [...cleanupCandidates, ...goalCandidates];
|
|
251
|
+
if (all.length > 0)
|
|
252
|
+
return all;
|
|
253
|
+
}
|
|
254
|
+
// P3.10: Try goal expansion before giving up
|
|
255
|
+
if (effectiveCtx.goal) {
|
|
256
|
+
const goalCandidates = expandGoalAsCandidates(effectiveCtx.goal, effectiveCtx);
|
|
257
|
+
if (goalCandidates.length > 0)
|
|
258
|
+
return goalCandidates;
|
|
259
|
+
}
|
|
260
|
+
// P3.14: Frontier exploration — BFS from current state for any path
|
|
261
|
+
const frontierPaths = (0, protocol_frontier_1.exploreFrontier)(effectiveCtx.rules, effectiveCtx.currentState, 10, 6);
|
|
262
|
+
if (frontierPaths.length > 0) {
|
|
263
|
+
return frontierPaths.map(actions => ({
|
|
264
|
+
id: candidateId("protocol", actions.map(fnToAction)),
|
|
265
|
+
source: "protocol",
|
|
266
|
+
actions: actions.map(fnToAction),
|
|
267
|
+
explanation: `协议前沿探索: ${actions.join(" → ")}`,
|
|
268
|
+
evidence: 0,
|
|
269
|
+
metadata: { pathLength: actions.length, source: "frontier-bfs" },
|
|
270
|
+
}));
|
|
271
|
+
}
|
|
272
|
+
// P3.15: Cross-protocol candidates — expanded to all 9 protocol groups (P7.3)
|
|
273
|
+
const xProtoPaths = (0, protocol_frontier_1.expandCrossProtocolCandidates)(effectiveCtx.goal || "repair", [
|
|
274
|
+
"AuthProtocol", "FileProtocol", "DBProtocol", "IRProtocol",
|
|
275
|
+
"TransactionProtocol", "ConditionalProtocol", "LoopProtocol",
|
|
276
|
+
"CrossProtocol", "StatelessProtocol",
|
|
277
|
+
]);
|
|
278
|
+
if (xProtoPaths.length > 0) {
|
|
279
|
+
return xProtoPaths.map(actions => ({
|
|
280
|
+
id: candidateId("protocol", actions.map(fnToAction)),
|
|
281
|
+
source: "protocol",
|
|
282
|
+
actions: actions.map(fnToAction),
|
|
283
|
+
explanation: `跨协议规划: ${actions.join(" → ")}`,
|
|
284
|
+
evidence: 0,
|
|
285
|
+
metadata: { pathLength: actions.length, source: "cross-protocol" },
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
const fixPath = (0, ssg_validator_1.findFixPathStatic)(effectiveCtx.rules, effectiveCtx.protocol, effectiveCtx.currentState, effectiveCtx.targetState);
|
|
289
|
+
if (fixPath.length === 0)
|
|
290
|
+
return [];
|
|
291
|
+
return [{
|
|
292
|
+
id: candidateId("protocol", fixPath.map(fnToAction)),
|
|
293
|
+
source: "protocol",
|
|
294
|
+
actions: fixPath.map(fnToAction),
|
|
295
|
+
explanation: `按 SSG 协议,需先经过: ${fixPath.join(" → ")}`,
|
|
296
|
+
evidence: 0,
|
|
297
|
+
metadata: { pathLength: fixPath.length },
|
|
298
|
+
}];
|
|
299
|
+
}
|
|
300
|
+
// Full BFS: find multiple distinct paths from currentState to targetState
|
|
301
|
+
const allPaths = [];
|
|
302
|
+
const queue = [
|
|
303
|
+
{ state: [...effectiveCtx.currentState], path: [], depth: 0 },
|
|
304
|
+
];
|
|
305
|
+
const visited = new Set();
|
|
306
|
+
visited.add(effectiveCtx.currentState.join(","));
|
|
307
|
+
const MAX_PATHS = 10;
|
|
308
|
+
const MAX_DEPTH = 8;
|
|
309
|
+
while (queue.length > 0 && allPaths.length < MAX_PATHS) {
|
|
310
|
+
const { state, path, depth } = queue.shift();
|
|
311
|
+
if (depth >= MAX_DEPTH)
|
|
312
|
+
continue;
|
|
313
|
+
// Check if target states are a subset of current state
|
|
314
|
+
if (effectiveCtx.targetState.every(t => state.includes(t)) && path.length > 0) {
|
|
315
|
+
allPaths.push([...path]);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
// Find all functions that can be called from current state
|
|
319
|
+
for (const [funcName, rule] of effectiveCtx.rules) {
|
|
320
|
+
if (rule.pre_states.every((pre) => state.includes(pre))) {
|
|
321
|
+
const newState = [...state];
|
|
322
|
+
if (rule.invalidate)
|
|
323
|
+
rule.invalidate.forEach(s => {
|
|
324
|
+
const idx = newState.indexOf(s);
|
|
325
|
+
if (idx >= 0)
|
|
326
|
+
newState.splice(idx, 1);
|
|
327
|
+
});
|
|
328
|
+
for (const post of rule.post_states) {
|
|
329
|
+
if (!newState.includes(post))
|
|
330
|
+
newState.push(post);
|
|
331
|
+
}
|
|
332
|
+
const stateKey = newState.sort().join(",");
|
|
333
|
+
if (!visited.has(stateKey)) {
|
|
334
|
+
visited.add(stateKey);
|
|
335
|
+
queue.push({
|
|
336
|
+
state: newState,
|
|
337
|
+
path: [...path, funcName],
|
|
338
|
+
depth: depth + 1,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const candidates = [];
|
|
345
|
+
for (let i = 0; i < allPaths.length; i++) {
|
|
346
|
+
const fp = allPaths[i];
|
|
347
|
+
candidates.push({
|
|
348
|
+
id: candidateId("protocol", fp.map(fnToAction)),
|
|
349
|
+
source: "protocol",
|
|
350
|
+
actions: fp.map(fnToAction),
|
|
351
|
+
explanation: `协议路径 ${i + 1}: ${fp.join(" → ")} (${fp.length} 步)`,
|
|
352
|
+
evidence: 0,
|
|
353
|
+
metadata: { pathLength: fp.length, pathIndex: i },
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return candidates;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
exports.ProtocolSearchStrategy = ProtocolSearchStrategy;
|
|
360
|
+
// ═══════════════════════════════════════════════════════════════
|
|
361
|
+
// Strategy 3: Antibody Search — learned immune rules
|
|
362
|
+
// ═══════════════════════════════════════════════════════════════
|
|
363
|
+
class AntibodySearchStrategy {
|
|
364
|
+
constructor() {
|
|
365
|
+
this.name = "antibody";
|
|
366
|
+
}
|
|
367
|
+
search(ctx) {
|
|
368
|
+
const antibodiesDir = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".progmune_corpus", "antibodies");
|
|
369
|
+
if (!fs.existsSync(antibodiesDir))
|
|
370
|
+
return [];
|
|
371
|
+
const candidates = [];
|
|
372
|
+
const files = fs.readdirSync(antibodiesDir).filter(f => f.startsWith("candidates_"));
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
try {
|
|
375
|
+
const raw = JSON.parse(fs.readFileSync(path.join(antibodiesDir, file), "utf-8"));
|
|
376
|
+
if (!Array.isArray(raw))
|
|
377
|
+
continue;
|
|
378
|
+
for (const ab of raw) {
|
|
379
|
+
if (ab.pattern?.violationType !== ctx.violationType)
|
|
380
|
+
continue;
|
|
381
|
+
if (ctx.protocol !== "default" &&
|
|
382
|
+
ab.pattern?.protocol &&
|
|
383
|
+
ab.pattern.protocol !== ctx.protocol)
|
|
384
|
+
continue;
|
|
385
|
+
const fixPath = ab.suggestedFix?.fixPath || [];
|
|
386
|
+
if (fixPath.length === 0)
|
|
387
|
+
continue;
|
|
388
|
+
candidates.push({
|
|
389
|
+
id: candidateId("antibody", fixPath.map(fnToAction)),
|
|
390
|
+
source: "antibody",
|
|
391
|
+
actions: fixPath.map(fnToAction),
|
|
392
|
+
explanation: ab.suggestedFix?.description || `Antibody rule: ${ab.id}`,
|
|
393
|
+
evidence: ab.evidence?.occurrenceCount || 0,
|
|
394
|
+
metadata: {
|
|
395
|
+
avgSuccessRate: ab.evidence?.avgSuccessRate || 0,
|
|
396
|
+
occurrenceCount: ab.evidence?.occurrenceCount || 0,
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
/* skip corrupted files */
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return candidates;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
exports.AntibodySearchStrategy = AntibodySearchStrategy;
|
|
409
|
+
// ═══════════════════════════════════════════════════════════════
|
|
410
|
+
// Factory
|
|
411
|
+
// ═══════════════════════════════════════════════════════════════
|
|
412
|
+
/** Return the three default search strategies. */
|
|
413
|
+
function createDefaultStrategies() {
|
|
414
|
+
return [
|
|
415
|
+
new CorpusSearchStrategy(),
|
|
416
|
+
new ProtocolSearchStrategy(),
|
|
417
|
+
new AntibodySearchStrategy(),
|
|
418
|
+
];
|
|
419
|
+
}
|