progmune-runtime 2.1.5 → 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 +326 -59
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
- package/package.json +74 -7
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P5.4: Continuous Benchmark Expansion 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 continuous_benchmark_1 = require("./continuous-benchmark");
|
|
43
|
+
const knowledge_governance_1 = require("./knowledge-governance");
|
|
44
|
+
const skill_library_1 = require("./skill-library");
|
|
45
|
+
const planner_telemetry_1 = require("./planner-telemetry");
|
|
46
|
+
const CB_DIR = path.resolve(__dirname, "..", "test-continuous-benchmark");
|
|
47
|
+
process.env.PROGMUNE_PROJECT_DIR = CB_DIR;
|
|
48
|
+
fs.mkdirSync(CB_DIR, { recursive: true });
|
|
49
|
+
fs.mkdirSync(path.join(CB_DIR, ".progmune_corpus", "telemetry"), { recursive: true });
|
|
50
|
+
fs.mkdirSync(path.join(CB_DIR, ".progmune_corpus", "knowledge"), { recursive: true });
|
|
51
|
+
fs.mkdirSync(path.join(CB_DIR, ".progmune_corpus", "skills"), { recursive: true });
|
|
52
|
+
(0, vitest_1.describe)("Continuous Benchmark Expansion", () => {
|
|
53
|
+
(0, vitest_1.it)("generates benchmarks from approved patches", () => {
|
|
54
|
+
const store = new knowledge_governance_1.KnowledgePatchStore(path.join(CB_DIR, ".progmune_corpus", "knowledge", `cb-patches-${Date.now()}.json`));
|
|
55
|
+
// Approve a patch
|
|
56
|
+
const patch = store.propose({
|
|
57
|
+
from: "FILE_OPEN", to: "FILE_DIRTY", action: "open_file → write_file",
|
|
58
|
+
protocol: "FileProtocol", confidence: 1.0, evidenceCount: 10, examples: ["test"],
|
|
59
|
+
validation: { benchmarkSupport: 10, trajectorySupport: 10, contradictionCount: 0, status: "verified" },
|
|
60
|
+
});
|
|
61
|
+
store.approve(patch.id, { top1Before: 0.5, top1After: 0.6, top3Before: 0.7, top3After: 0.8 });
|
|
62
|
+
const cases = (0, continuous_benchmark_1.generateBenchmarksFromPatches)(store);
|
|
63
|
+
(0, vitest_1.expect)(cases.length).toBeGreaterThanOrEqual(1);
|
|
64
|
+
(0, vitest_1.expect)(cases[0].source).toBe("patch");
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.it)("generates benchmarks from skills", () => {
|
|
67
|
+
const rules = new Map();
|
|
68
|
+
rules.set("open_file", { pre_states: [], post_states: ["FILE_OPEN"] });
|
|
69
|
+
rules.set("write_file", { pre_states: ["FILE_OPEN"], post_states: [] });
|
|
70
|
+
rules.set("close_file", { pre_states: ["FILE_OPEN"], post_states: [], invalidate: ["FILE_OPEN"] });
|
|
71
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(CB_DIR, ".progmune_corpus", "telemetry", `cb-skills-${Date.now()}.jsonl`));
|
|
72
|
+
// Seed with high-confidence file skill
|
|
73
|
+
for (let i = 0; i < 15; i++) {
|
|
74
|
+
const a = ["open_file", "write_file", "close_file"];
|
|
75
|
+
const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", a, "resource_leak");
|
|
76
|
+
const id = telemetry.recordDecision({
|
|
77
|
+
goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak",
|
|
78
|
+
candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions: a, explanation: "full" }],
|
|
79
|
+
selectedCandidateId: fp,
|
|
80
|
+
});
|
|
81
|
+
telemetry.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, timestamp: Date.now() });
|
|
82
|
+
}
|
|
83
|
+
const lib = new skill_library_1.SkillLibrary();
|
|
84
|
+
lib.learn(telemetry, rules);
|
|
85
|
+
(0, vitest_1.expect)(lib.size).toBeGreaterThanOrEqual(1);
|
|
86
|
+
const cases = (0, continuous_benchmark_1.generateBenchmarksFromSkills)(lib);
|
|
87
|
+
(0, vitest_1.expect)(cases.length).toBeGreaterThanOrEqual(1);
|
|
88
|
+
(0, vitest_1.expect)(cases[0].source).toBe("skill");
|
|
89
|
+
// Resource cleanup variant should also be generated
|
|
90
|
+
(0, vitest_1.expect)(cases.some(c => c.violationType === "resource_leak")).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)("runs continuous benchmark pipeline", async () => {
|
|
93
|
+
const rules = new Map();
|
|
94
|
+
rules.set("open_file", { pre_states: [], post_states: ["FILE_OPEN"] });
|
|
95
|
+
rules.set("write_file", { pre_states: ["FILE_OPEN"], post_states: [] });
|
|
96
|
+
rules.set("close_file", { pre_states: ["FILE_OPEN"], post_states: [], invalidate: ["FILE_OPEN"] });
|
|
97
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(CB_DIR, ".progmune_corpus", "telemetry", `cb-full-${Date.now()}.jsonl`));
|
|
98
|
+
for (let i = 0; i < 20; i++) {
|
|
99
|
+
const a = ["open_file", "write_file", "close_file"];
|
|
100
|
+
const fp = (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", a, "resource_leak");
|
|
101
|
+
const id = telemetry.recordDecision({
|
|
102
|
+
goal: "safely write", protocol: "FileProtocol", violationType: "resource_leak",
|
|
103
|
+
candidates: [{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"], actions: a, explanation: "full" }],
|
|
104
|
+
selectedCandidateId: fp,
|
|
105
|
+
});
|
|
106
|
+
telemetry.recordFeedback(id, { decision: "accepted", executionResult: { success: true, violations: [] }, timestamp: Date.now() });
|
|
107
|
+
}
|
|
108
|
+
const lib = new skill_library_1.SkillLibrary();
|
|
109
|
+
lib.learn(telemetry, rules);
|
|
110
|
+
const store = new knowledge_governance_1.KnowledgePatchStore(path.join(CB_DIR, ".progmune_corpus", "knowledge", `cb-run-${Date.now()}.json`));
|
|
111
|
+
const report = await (0, continuous_benchmark_1.runContinuousBenchmark)(store, lib, path.join(CB_DIR, "expanded-benchmarks"));
|
|
112
|
+
(0, vitest_1.expect)(report.generatedCases).toBeGreaterThanOrEqual(2);
|
|
113
|
+
(0, vitest_1.expect)(report.sourceBreakdown.skills).toBeGreaterThanOrEqual(1);
|
|
114
|
+
(0, continuous_benchmark_1.printContinuousBenchmarkReport)(report);
|
|
115
|
+
}, 60000);
|
|
116
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P0: Corpus Quality Dashboard
|
|
4
|
+
*
|
|
5
|
+
* Reads all FailureRecordV2 files from .progmune_corpus/trajectories/
|
|
6
|
+
* and outputs quality metrics as terminal table + JSON report.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx ts-node src/corpus-stats.ts
|
|
10
|
+
* npx ts-node src/corpus-stats.ts --json
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════
|
|
15
|
+
// Data loading
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════
|
|
17
|
+
function loadAllTrajectories() {
|
|
18
|
+
return (0, failure_corpus_1.loadTrajectories)();
|
|
19
|
+
}
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════
|
|
21
|
+
// Metrics computation
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════
|
|
23
|
+
function jaccardSimilarity(a, b) {
|
|
24
|
+
const sa = new Set(a), sb = new Set(b);
|
|
25
|
+
const intersection = [...sa].filter(x => sb.has(x)).length;
|
|
26
|
+
const union = new Set([...sa, ...sb]).size;
|
|
27
|
+
return union === 0 ? 0 : intersection / union;
|
|
28
|
+
}
|
|
29
|
+
function computeStats(trajectories) {
|
|
30
|
+
const violations = trajectories.filter(t => t.result === "violation");
|
|
31
|
+
// Duplication: fraction of pairs with trajectory similarity > 0.9
|
|
32
|
+
let duplicatePairs = 0;
|
|
33
|
+
let totalPairs = 0;
|
|
34
|
+
for (let i = 0; i < violations.length; i++) {
|
|
35
|
+
for (let j = i + 1; j < violations.length; j++) {
|
|
36
|
+
totalPairs++;
|
|
37
|
+
if (jaccardSimilarity(violations[i].trajectory, violations[j].trajectory) > 0.9) {
|
|
38
|
+
duplicatePairs++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Repair stats: count repair trajectories
|
|
43
|
+
const repairs = trajectories.filter(t => t.result === "repair");
|
|
44
|
+
const totalAttempts = repairs.length;
|
|
45
|
+
const acceptedAttempts = repairs.filter(t => t.successRate > 0.5).length;
|
|
46
|
+
const successfulRepairs = repairs.filter(t => t.successRate > 0.8).length;
|
|
47
|
+
// Violation type counts
|
|
48
|
+
const byViolationType = {};
|
|
49
|
+
for (const t of violations) {
|
|
50
|
+
const vt = t.violation?.type || "other";
|
|
51
|
+
byViolationType[vt] = (byViolationType[vt] || 0) + 1;
|
|
52
|
+
}
|
|
53
|
+
// Protocol counts
|
|
54
|
+
const byProtocol = {};
|
|
55
|
+
for (const t of trajectories) {
|
|
56
|
+
byProtocol[t.protocol] = (byProtocol[t.protocol] || 0) + 1;
|
|
57
|
+
}
|
|
58
|
+
// Context feature combinations
|
|
59
|
+
const byContextFeature = {};
|
|
60
|
+
for (const t of trajectories) {
|
|
61
|
+
const key = [
|
|
62
|
+
`depth=${t.context.nestingDepth}`,
|
|
63
|
+
t.context.exceptionHandled ? "try" : "no-try",
|
|
64
|
+
t.context.insideLoop ? "loop" : "no-loop",
|
|
65
|
+
].join(" ");
|
|
66
|
+
byContextFeature[key] = (byContextFeature[key] || 0) + 1;
|
|
67
|
+
}
|
|
68
|
+
// Top violation × context patterns
|
|
69
|
+
const patternCounts = {};
|
|
70
|
+
for (const t of violations) {
|
|
71
|
+
const vt = t.violation?.type || "other";
|
|
72
|
+
const ctx = t.context;
|
|
73
|
+
const key = `${vt} | depth=${ctx.nestingDepth} ${ctx.exceptionHandled ? "try" : "no-try"} ${ctx.insideLoop ? "loop" : "no-loop"}`;
|
|
74
|
+
patternCounts[key] = (patternCounts[key] || 0) + 1;
|
|
75
|
+
}
|
|
76
|
+
const topPatterns = Object.entries(patternCounts)
|
|
77
|
+
.sort((a, b) => b[1] - a[1])
|
|
78
|
+
.slice(0, 10)
|
|
79
|
+
.map(([p, c]) => {
|
|
80
|
+
const [violationType, ...rest] = p.split(" | ");
|
|
81
|
+
return { violationType, context: rest.join(" | "), count: c };
|
|
82
|
+
});
|
|
83
|
+
const timestamps = trajectories.map(f => f.timestamp).sort();
|
|
84
|
+
return {
|
|
85
|
+
totalFailures: trajectories.length,
|
|
86
|
+
dateRange: {
|
|
87
|
+
earliest: timestamps[0] || "N/A",
|
|
88
|
+
latest: timestamps[timestamps.length - 1] || "N/A",
|
|
89
|
+
},
|
|
90
|
+
byViolationType,
|
|
91
|
+
byProtocol,
|
|
92
|
+
byContextFeature,
|
|
93
|
+
duplicationRate: totalPairs > 0 ? duplicatePairs / totalPairs : 0,
|
|
94
|
+
repairAcceptanceRate: totalAttempts > 0 ? acceptedAttempts / totalAttempts : 0,
|
|
95
|
+
repairSuccessRate: totalAttempts > 0 ? successfulRepairs / totalAttempts : 0,
|
|
96
|
+
totalRepairAttempts: totalAttempts,
|
|
97
|
+
avgPatternSuccessRate: trajectories.length > 0
|
|
98
|
+
? trajectories.reduce((s, t) => s + t.successRate, 0) / trajectories.length
|
|
99
|
+
: 0,
|
|
100
|
+
topPatterns,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// ═══════════════════════════════════════════════════════════════
|
|
104
|
+
// Output
|
|
105
|
+
// ═══════════════════════════════════════════════════════════════
|
|
106
|
+
function formatPercent(v) {
|
|
107
|
+
return `${(v * 100).toFixed(1)}%`;
|
|
108
|
+
}
|
|
109
|
+
function printTable(stats, breakdown) {
|
|
110
|
+
console.log("\n╔══════════════════════════════════════════════╗");
|
|
111
|
+
console.log("║ Trajectory Corpus Dashboard (Schema v1) ║");
|
|
112
|
+
console.log("╚══════════════════════════════════════════════╝");
|
|
113
|
+
console.log(`\n📊 Total trajectories: ${breakdown.total}`);
|
|
114
|
+
console.log(` ✅ Success: ${breakdown.success} ❌ Violation: ${breakdown.violation} 🔧 Repair: ${breakdown.repair} ⭐ Optimal: ${breakdown.optimal}`);
|
|
115
|
+
console.log(`📅 Date range: ${stats.dateRange.earliest} → ${stats.dateRange.latest}`);
|
|
116
|
+
// Violation distribution
|
|
117
|
+
console.log("\n── Violation Types ──");
|
|
118
|
+
const vtEntries = Object.entries(stats.byViolationType).sort((a, b) => b[1] - a[1]);
|
|
119
|
+
for (const [type, count] of vtEntries) {
|
|
120
|
+
const bar = "█".repeat(Math.round(count / Math.max(...vtEntries.map(e => e[1])) * 30));
|
|
121
|
+
console.log(` ${type.padEnd(24)} ${String(count).padStart(4)} ${bar}`);
|
|
122
|
+
}
|
|
123
|
+
// Protocol distribution
|
|
124
|
+
console.log("\n── Protocols ──");
|
|
125
|
+
for (const [proto, count] of Object.entries(stats.byProtocol).sort((a, b) => b[1] - a[1])) {
|
|
126
|
+
console.log(` ${proto.padEnd(20)} ${count}`);
|
|
127
|
+
}
|
|
128
|
+
// Quality metrics
|
|
129
|
+
console.log("\n── Quality Metrics ──");
|
|
130
|
+
const rows = [
|
|
131
|
+
["Duplication rate", formatPercent(stats.duplicationRate), stats.duplicationRate < 0.2 ? "✅" : "⚠️ >20%"],
|
|
132
|
+
["Repair acceptance", formatPercent(stats.repairAcceptanceRate), stats.repairAcceptanceRate > 0.4 ? "✅" : "⚠️ <40%"],
|
|
133
|
+
["Repair success", formatPercent(stats.repairSuccessRate), stats.repairSuccessRate > 0.8 ? "✅" : "⚠️ <80%"],
|
|
134
|
+
["Total repair attempts", String(stats.totalRepairAttempts), ""],
|
|
135
|
+
["Avg pattern success rate", formatPercent(stats.avgPatternSuccessRate), ""],
|
|
136
|
+
];
|
|
137
|
+
for (const [metric, value, flag] of rows) {
|
|
138
|
+
console.log(` ${(metric + ":").padEnd(26)} ${value.padEnd(8)} ${flag}`);
|
|
139
|
+
}
|
|
140
|
+
// Top patterns
|
|
141
|
+
if (stats.topPatterns.length > 0) {
|
|
142
|
+
console.log("\n── Top Violation × Context Patterns ──");
|
|
143
|
+
for (const p of stats.topPatterns) {
|
|
144
|
+
console.log(` ${p.violationType.padEnd(24)} ${p.context.padEnd(30)} x${p.count}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Context features
|
|
148
|
+
console.log("\n── Context Features ──");
|
|
149
|
+
for (const [feat, count] of Object.entries(stats.byContextFeature).sort((a, b) => b[1] - a[1])) {
|
|
150
|
+
console.log(` ${feat.padEnd(30)} ${count}`);
|
|
151
|
+
}
|
|
152
|
+
console.log();
|
|
153
|
+
}
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════
|
|
155
|
+
// Main
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════
|
|
157
|
+
async function main() {
|
|
158
|
+
const useJson = process.argv.includes("--json");
|
|
159
|
+
const trajectories = loadAllTrajectories();
|
|
160
|
+
const breakdown = (0, failure_corpus_1.corpusTrajectoryStats)();
|
|
161
|
+
if (trajectories.length === 0) {
|
|
162
|
+
console.error("✅ Trajectory corpus is empty — run validation to start collecting.");
|
|
163
|
+
process.exit(0);
|
|
164
|
+
}
|
|
165
|
+
const stats = computeStats(trajectories);
|
|
166
|
+
if (useJson) {
|
|
167
|
+
console.log(JSON.stringify({ stats, breakdown }, null, 2));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
printTable(stats, breakdown);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
main();
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P2: Counterfactual Repair Engine (V3)
|
|
4
|
+
*
|
|
5
|
+
* When validation fails, this engine:
|
|
6
|
+
* 1. Searches Failure Corpus v2 for similar violation patterns
|
|
7
|
+
* 2. BFS-searches the SSG for alternative legal state transition paths
|
|
8
|
+
* 3. Ranks alternatives by: historical success rate → path length → reward weights
|
|
9
|
+
* 4. Returns top-3 with human-readable explanations
|
|
10
|
+
*
|
|
11
|
+
* This is V3's killer feature: "告诉你三条修法"
|
|
12
|
+
*
|
|
13
|
+
* Architecture (refactored):
|
|
14
|
+
* Strategies (repair-strategies.ts) → Candidates → Ranker (repair-ranker.ts) → Top-3
|
|
15
|
+
*
|
|
16
|
+
* @requires VALIDATION_FAILURE @produces REPAIR_ALTERNATIVES
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.deduplicateCandidates = deduplicateCandidates;
|
|
53
|
+
exports.getRankerStatus = getRankerStatus;
|
|
54
|
+
exports.suggestAlternatives = suggestAlternatives;
|
|
55
|
+
exports.formatAlternatives = formatAlternatives;
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const zeroshot_strategy_1 = require("./zeroshot-strategy");
|
|
59
|
+
const repair_strategies_1 = require("./repair-strategies");
|
|
60
|
+
const repair_ranker_1 = require("./repair-ranker");
|
|
61
|
+
const learning_ranker_1 = require("./learning-ranker");
|
|
62
|
+
const planner_telemetry_1 = require("./planner-telemetry");
|
|
63
|
+
const logistic_reward_1 = require("./logistic-reward");
|
|
64
|
+
// ═══════════════════════════════════════════════════════════════
|
|
65
|
+
// Cross-source evidence merge
|
|
66
|
+
// ═══════════════════════════════════════════════════════════════
|
|
67
|
+
/**
|
|
68
|
+
* Deduplicate candidates by action signature, merging evidence sources.
|
|
69
|
+
*
|
|
70
|
+
* When the same repair path (e.g., "close_file") comes from
|
|
71
|
+
* corpus + protocol + antibody, all three sources are recorded
|
|
72
|
+
* in `evidenceSources`. This merged candidate has higher credibility
|
|
73
|
+
* than any single-source candidate.
|
|
74
|
+
*
|
|
75
|
+
* This is a key input feature for the future Reward Model (P4).
|
|
76
|
+
*/
|
|
77
|
+
function deduplicateCandidates(candidates) {
|
|
78
|
+
const groups = new Map();
|
|
79
|
+
for (const c of candidates) {
|
|
80
|
+
const key = c.actions
|
|
81
|
+
.map(a => (a.kind === "call" ? a.function : a.kind))
|
|
82
|
+
.join("→");
|
|
83
|
+
const existing = groups.get(key);
|
|
84
|
+
if (existing) {
|
|
85
|
+
// Merge: combine evidence sources and take max evidence count
|
|
86
|
+
const existingSources = existing.evidenceSources || [existing.source];
|
|
87
|
+
const newSource = c.source;
|
|
88
|
+
if (!existingSources.includes(newSource)) {
|
|
89
|
+
existingSources.push(newSource);
|
|
90
|
+
}
|
|
91
|
+
existing.evidenceSources = existingSources;
|
|
92
|
+
existing.evidence = Math.max(existing.evidence || 0, c.evidence || 0);
|
|
93
|
+
// Merge metadata: highest historicalSuccessRate wins
|
|
94
|
+
if (c.metadata?.historicalSuccessRate !== undefined &&
|
|
95
|
+
(existing.metadata?.historicalSuccessRate === undefined ||
|
|
96
|
+
c.metadata.historicalSuccessRate > existing.metadata.historicalSuccessRate)) {
|
|
97
|
+
existing.metadata = { ...existing.metadata, ...c.metadata };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
c.evidenceSources = [c.source];
|
|
102
|
+
groups.set(key, c);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return [...groups.values()];
|
|
106
|
+
}
|
|
107
|
+
// ═══════════════════════════════════════════════════════════════
|
|
108
|
+
// P7.3: Ranker Factory — env-var-driven ranker selection
|
|
109
|
+
// ═══════════════════════════════════════════════════════════════
|
|
110
|
+
let _activeLearningRanker = null;
|
|
111
|
+
let _rankerType = "heuristic";
|
|
112
|
+
let _modelWeight = 0.3;
|
|
113
|
+
let _modelSampleCount = 0;
|
|
114
|
+
let _rankerStartTime = 0;
|
|
115
|
+
/** Get (or create) the LearningRanker singleton with pre-trained model. */
|
|
116
|
+
function getActiveLearningRanker() {
|
|
117
|
+
if (_activeLearningRanker)
|
|
118
|
+
return _activeLearningRanker;
|
|
119
|
+
_rankerType = "learning";
|
|
120
|
+
_rankerStartTime = Date.now();
|
|
121
|
+
_modelWeight = parseFloat(process.env.PROGMUNE_MODEL_WEIGHT || "0.3");
|
|
122
|
+
const baseRanker = (0, repair_ranker_1.createLinearRanker)();
|
|
123
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry();
|
|
124
|
+
// Try to load pre-trained reward model from models/
|
|
125
|
+
let rewardModel;
|
|
126
|
+
try {
|
|
127
|
+
const modelPath = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "models", "reward-model.json");
|
|
128
|
+
if (fs.existsSync(modelPath)) {
|
|
129
|
+
const data = JSON.parse(fs.readFileSync(modelPath, "utf-8"));
|
|
130
|
+
rewardModel = logistic_reward_1.LogisticRewardModel.importWeights(data);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// No pre-trained model → fall back to telemetry-only learning
|
|
135
|
+
}
|
|
136
|
+
_modelSampleCount = (rewardModel ? rewardModel.sampleCount : 0);
|
|
137
|
+
_activeLearningRanker = new learning_ranker_1.LearningRanker(baseRanker, telemetry, { baseWeight: 0.7, feedbackWeight: 0.3, minSamples: 5 }, rewardModel, _modelWeight);
|
|
138
|
+
return _activeLearningRanker;
|
|
139
|
+
}
|
|
140
|
+
/** Return the current ranker status and metrics. */
|
|
141
|
+
function getRankerStatus() {
|
|
142
|
+
return {
|
|
143
|
+
type: _rankerType,
|
|
144
|
+
modelWeight: _rankerType === "learning" ? _modelWeight : 0,
|
|
145
|
+
modelSamples: _rankerType === "learning" ? _modelSampleCount : 0,
|
|
146
|
+
uptimeSeconds: _rankerStartTime > 0 ? Math.round((Date.now() - _rankerStartTime) / 1000) : 0,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// ═══════════════════════════════════════════════════════════════
|
|
150
|
+
// Public API
|
|
151
|
+
// ═══════════════════════════════════════════════════════════════
|
|
152
|
+
/**
|
|
153
|
+
* Generate the top-3 counterfactual repair alternatives for a violation.
|
|
154
|
+
*
|
|
155
|
+
* This is V3's killer feature: "告诉你三条修法"
|
|
156
|
+
*
|
|
157
|
+
* Internally delegates to Strategy → Candidate → Ranker pipeline.
|
|
158
|
+
*/
|
|
159
|
+
async function suggestAlternatives(params) {
|
|
160
|
+
// 1. Build search context
|
|
161
|
+
const ctx = {
|
|
162
|
+
protocol: params.protocol || "default",
|
|
163
|
+
currentState: (params.currentState?.length ?? 0) > 0
|
|
164
|
+
? params.currentState
|
|
165
|
+
: params.violation.currentStates || [],
|
|
166
|
+
targetState: (params.targetState?.length ?? 0) > 0
|
|
167
|
+
? params.targetState
|
|
168
|
+
: (params.violation.requiredStates?.length ?? 0) > 0
|
|
169
|
+
? params.violation.requiredStates
|
|
170
|
+
: [], // Keep empty to trigger cleanup path — don't fake COMPLETED
|
|
171
|
+
violationType: params.violation.violatedConstraint || "protocol_violation",
|
|
172
|
+
constraints: params.constraints || [],
|
|
173
|
+
rules: params.rules || new Map(),
|
|
174
|
+
goal: params.goal,
|
|
175
|
+
};
|
|
176
|
+
// 2. Run all strategies to collect candidates (no scoring in strategies)
|
|
177
|
+
const strategies = (0, repair_strategies_1.createDefaultStrategies)();
|
|
178
|
+
const allCandidates = [];
|
|
179
|
+
for (const strategy of strategies) {
|
|
180
|
+
allCandidates.push(...strategy.search(ctx));
|
|
181
|
+
}
|
|
182
|
+
// P8.3: If no candidates found, try ZeroShotStrategy
|
|
183
|
+
if (allCandidates.length === 0) {
|
|
184
|
+
const zeroShot = new zeroshot_strategy_1.ZeroShotStrategy();
|
|
185
|
+
allCandidates.push(...zeroShot.search(ctx));
|
|
186
|
+
}
|
|
187
|
+
// 3. Deduplicate by action signature, merge evidence sources
|
|
188
|
+
const uniqueCandidates = deduplicateCandidates(allCandidates);
|
|
189
|
+
if (uniqueCandidates.length === 0)
|
|
190
|
+
return [];
|
|
191
|
+
// 4. Extract features and rank
|
|
192
|
+
const maxActions = Math.max(...uniqueCandidates.map(c => c.actions.length), 8);
|
|
193
|
+
const features = uniqueCandidates.map(c => (0, repair_ranker_1.extractFeatures)(c, ctx, { maxActions }));
|
|
194
|
+
// P7.3: Ranker selection via PROGMUNE_RANKER env var
|
|
195
|
+
// "learning" → LearningRanker with pre-trained reward model
|
|
196
|
+
// "heuristic" (default) → LinearRanker with goalMatch weights
|
|
197
|
+
const rankerType = process.env.PROGMUNE_RANKER || "heuristic";
|
|
198
|
+
let ranked;
|
|
199
|
+
if (rankerType === "learning") {
|
|
200
|
+
const learner = getActiveLearningRanker();
|
|
201
|
+
ranked = learner.rank(uniqueCandidates, features, {
|
|
202
|
+
protocol: ctx.protocol,
|
|
203
|
+
violationType: ctx.violationType,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
const ranker = (0, repair_ranker_1.createLinearRanker)();
|
|
208
|
+
ranked = ranker.rankOverall(uniqueCandidates, features);
|
|
209
|
+
}
|
|
210
|
+
// 5. Map back to CounterfactualAlternative (backward-compat)
|
|
211
|
+
const top3 = ranked.slice(0, 3);
|
|
212
|
+
const alternatives = top3.map((c, i) => {
|
|
213
|
+
// Re-extract features for the final ranked position
|
|
214
|
+
const f = features[uniqueCandidates.indexOf(c)] ||
|
|
215
|
+
(0, repair_ranker_1.extractFeatures)(c, ctx, { maxActions });
|
|
216
|
+
// Score: use LearningRanker score if available, otherwise compute from LinearRanker
|
|
217
|
+
const score = c.score !== undefined
|
|
218
|
+
? c.score
|
|
219
|
+
: (0, repair_ranker_1.createLinearRanker)().score(f);
|
|
220
|
+
return {
|
|
221
|
+
rank: i + 1,
|
|
222
|
+
description: c.explanation,
|
|
223
|
+
fixPath: c.actions
|
|
224
|
+
.filter(a => a.kind === "call")
|
|
225
|
+
.map(a => a.function),
|
|
226
|
+
targetState: ctx.targetState,
|
|
227
|
+
score,
|
|
228
|
+
source: c.source === "protocol" ? "ssg_bfs" : c.source,
|
|
229
|
+
historicalSuccessRate: f.historicalSuccessRate,
|
|
230
|
+
corpusEvidenceCount: f.corpusEvidence,
|
|
231
|
+
satisfiedConstraints: ctx.constraints
|
|
232
|
+
.filter(cn => (cn.type === "safety" || cn.type === "security") &&
|
|
233
|
+
c.actions.length <= 5)
|
|
234
|
+
.map(cn => cn.description),
|
|
235
|
+
repairStrategy: c.metadata?.source,
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
return alternatives;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Format alternatives as human-readable text (for LLM prompts or CLI output).
|
|
242
|
+
*/
|
|
243
|
+
function formatAlternatives(alternatives) {
|
|
244
|
+
if (alternatives.length === 0)
|
|
245
|
+
return "未找到修复方案。";
|
|
246
|
+
const lines = [];
|
|
247
|
+
for (const alt of alternatives) {
|
|
248
|
+
const badge = alt.source === "corpus"
|
|
249
|
+
? "📊 历史数据"
|
|
250
|
+
: alt.source === "ssg_bfs"
|
|
251
|
+
? "🔍 协议搜索"
|
|
252
|
+
: alt.source === "antibody"
|
|
253
|
+
? "🛡️ 抗体规则"
|
|
254
|
+
: "🤖 LLM";
|
|
255
|
+
lines.push(`方案 ${alt.rank}: ${alt.description}`);
|
|
256
|
+
lines.push(` 路径: ${alt.fixPath.join(" → ")}`);
|
|
257
|
+
lines.push(` 置信度: ${(alt.score * 100).toFixed(0)}% | ${badge}`);
|
|
258
|
+
if (alt.historicalSuccessRate > 0) {
|
|
259
|
+
lines.push(` 历史成功率: ${(alt.historicalSuccessRate * 100).toFixed(0)}% (${alt.corpusEvidenceCount} 案例)`);
|
|
260
|
+
}
|
|
261
|
+
if (alt.satisfiedConstraints.length > 0) {
|
|
262
|
+
lines.push(` 满足约束: ${alt.satisfiedConstraints.join(", ")}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return lines.join("\n");
|
|
266
|
+
}
|
|
267
|
+
// ═══════════════════════════════════════════════════════════════
|
|
268
|
+
// CLI
|
|
269
|
+
// ═══════════════════════════════════════════════════════════════
|
|
270
|
+
if (require.main === module) {
|
|
271
|
+
const testViolation = {
|
|
272
|
+
svl: 4,
|
|
273
|
+
violatedConstraint: "protocol_violation",
|
|
274
|
+
actionIndex: 1,
|
|
275
|
+
currentStates: ["Open"],
|
|
276
|
+
requiredStates: ["Closed"],
|
|
277
|
+
description: "文件未关闭",
|
|
278
|
+
};
|
|
279
|
+
suggestAlternatives({
|
|
280
|
+
violation: testViolation,
|
|
281
|
+
protocol: "FileProtocol",
|
|
282
|
+
currentState: ["Open"],
|
|
283
|
+
targetState: ["Closed"],
|
|
284
|
+
constraints: [{ type: "safety", value: 0.8, description: "安全写入" }],
|
|
285
|
+
}).then(alts => {
|
|
286
|
+
console.log(formatAlternatives(alts));
|
|
287
|
+
});
|
|
288
|
+
}
|