progmune-runtime 2.1.6 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -468
- package/dist/ablation-study.js +144 -0
- package/dist/ablation-study.test.js +18 -0
- package/dist/action-runtime.js +3 -1
- package/dist/active-learning.js +211 -0
- package/dist/analytics.js +139 -0
- package/dist/asset-factory.js +309 -0
- package/dist/asset-growth.js +244 -0
- package/dist/asset-promotion.js +382 -0
- package/dist/asset-quality.js +550 -0
- package/dist/audit/business-translator.js +285 -0
- package/dist/audit/cli.js +66 -0
- package/dist/audit/formatters/html.js +379 -0
- package/dist/audit/formatters/json.js +11 -0
- package/dist/audit/formatters/markdown.js +192 -0
- package/dist/audit/formatters/terminal.js +189 -0
- package/dist/audit/index.js +25 -0
- package/dist/audit/report-builder.js +318 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit.js +3 -3
- package/dist/auto-benchmark-generator.js +137 -0
- package/dist/auto-benchmark-generator.test.js +45 -0
- package/dist/auto-protocol-synthesizer.js +362 -0
- package/dist/auto-protocol-synthesizer.test.js +82 -0
- package/dist/autonomous-patch.js +175 -0
- package/dist/autonomous-patch.test.js +128 -0
- package/dist/badge/badge-server.js +98 -0
- package/dist/behavior-miner.js +442 -0
- package/dist/belief-layer.js +475 -0
- package/dist/benchmark-count.js +5 -0
- package/dist/benchmark-generator.js +211 -0
- package/dist/benchmark-harness.js +201 -0
- package/dist/benchmark-pass-rate.js +7 -0
- package/dist/benchmark-report.js +8 -3
- package/dist/benchmark-save.js +14 -1
- package/dist/bootstrap-validation.js +197 -0
- package/dist/bootstrap-validation.test.js +51 -0
- package/dist/branch-ledger.js +1 -1
- package/dist/capability-gap.js +130 -0
- package/dist/certify-html.js +351 -0
- package/dist/certify.js +326 -0
- package/dist/check.js +4 -4
- package/dist/compliance-miner.js +447 -0
- package/dist/continuous-benchmark.js +194 -0
- package/dist/continuous-benchmark.test.js +116 -0
- package/dist/corpus-stats.js +173 -0
- package/dist/counterfactual-engine.js +288 -0
- package/dist/coverage-dashboard.js +109 -0
- package/dist/coverage-system.test.js +205 -0
- package/dist/cross-repo-precision.js +352 -0
- package/dist/cve-benchmark.js +180 -0
- package/dist/cve-benchmark.test.js +28 -0
- package/dist/cve-collector.js +73 -0
- package/dist/data-quality.js +141 -0
- package/dist/decision-engine.js +388 -0
- package/dist/derive-metadata.js +250 -0
- package/dist/difficulty-active.test.js +198 -0
- package/dist/difficulty-map.js +244 -0
- package/dist/discovery-analytics.js +125 -0
- package/dist/discovery-model.js +149 -0
- package/dist/discovery-optimize.test.js +199 -0
- package/dist/discovery-trace.js +276 -0
- package/dist/discovery-trace.test.js +97 -0
- package/dist/emitter.js +83 -1
- package/dist/enterprise-dashboard.js +405 -0
- package/dist/eval-hardening.js +297 -0
- package/dist/eval-hardening.test.js +85 -0
- package/dist/evaluation-campaign.js +359 -0
- package/dist/evaluation-campaign.test.js +181 -0
- package/dist/evidence-growth.js +143 -0
- package/dist/evidence-repository.js +209 -0
- package/dist/evidence-system.js +441 -0
- package/dist/execute.js +15 -7
- package/dist/experimental/software-physics.js +291 -0
- package/dist/experimental/state-inference.js +516 -0
- package/dist/experimental/unsupervised-physics.js +230 -0
- package/dist/extract-ir-python.js +54 -7
- package/dist/extract-ir.js +376 -12
- package/dist/failure-collector.js +2 -2
- package/dist/failure-corpus.js +322 -9
- package/dist/feedback.js +16 -5
- package/dist/feedback.test.js +49 -0
- package/dist/file-lock.js +1 -1
- package/dist/flywheel-batch.js +292 -0
- package/dist/frameworks/express-cli.js +237 -0
- package/dist/frameworks/express-detector.js +445 -0
- package/dist/frameworks/express-detector.test.js +206 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/nestjs-detector.js +302 -0
- package/dist/frameworks/trpc-detector.js +161 -0
- package/dist/frameworks/version-awareness.js +179 -0
- package/dist/function-synonyms.js +164 -0
- package/dist/function-synonyms.test.js +68 -0
- package/dist/generalization.test.js +352 -0
- package/dist/goal-annotator.js +113 -0
- package/dist/goal-planner.js +563 -0
- package/dist/gold-cve.js +164 -0
- package/dist/gold-cve.test.js +104 -0
- package/dist/gold-quality.js +206 -0
- package/dist/gold-tiers.js +241 -0
- package/dist/governance-dashboard.js +327 -0
- package/dist/graph-viz.js +240 -0
- package/dist/guided-frontier.js +195 -0
- package/dist/hierarchical-planner.js +148 -0
- package/dist/identifier-parser.js +260 -0
- package/dist/immune-metrics.js +93 -0
- package/dist/immune-receiver.js +158 -0
- package/dist/immune-reporter.js +1 -1
- package/dist/improvement-orchestrator.js +206 -0
- package/dist/inject-p0-vocabulary.js +300 -0
- package/dist/intent-parser.js +218 -0
- package/dist/invariant-algebra.js +476 -0
- package/dist/invariant-calculus.js +533 -0
- package/dist/ir-utils.js +70 -0
- package/dist/ir-utils.test.js +50 -0
- package/dist/knowledge-api.js +312 -0
- package/dist/knowledge-evolution.js +452 -0
- package/dist/knowledge-explorer.js +506 -0
- package/dist/knowledge-flywheel.js +274 -0
- package/dist/knowledge-governance.js +338 -0
- package/dist/knowledge-governance.test.js +150 -0
- package/dist/knowledge-graph.js +181 -0
- package/dist/knowledge-guided-synth.js +246 -0
- package/dist/knowledge-loop.test.js +77 -0
- package/dist/knowledge-object.js +316 -0
- package/dist/knowledge-package.js +98 -0
- package/dist/kpi-dashboard.js +561 -0
- package/dist/l3-cross-function.js +280 -0
- package/dist/learning-ranker.js +148 -0
- package/dist/learning-ranker.test.js +291 -0
- package/dist/ledger/accountability.js +322 -0
- package/dist/ledger/chain-builder.js +185 -0
- package/dist/ledger/cli.js +222 -0
- package/dist/ledger/index.js +13 -0
- package/dist/ledger/signatures.js +193 -0
- package/dist/ledger/types.js +9 -0
- package/dist/llm.js +74 -3
- package/dist/load-benchmarks.js +8 -3
- package/dist/logger.js +66 -0
- package/dist/logger.test.js +37 -0
- package/dist/logistic-reward.js +339 -0
- package/dist/logistic-reward.test.js +180 -0
- package/dist/macro-graph.js +193 -0
- package/dist/macro-repair.js +183 -0
- package/dist/mcp-server.mjs +1202 -483
- package/dist/memory-layer.js +42 -5
- package/dist/multi-repo-precision.js +422 -0
- package/dist/name-free-protocol.js +425 -0
- package/dist/name-free-protocol.test.js +170 -0
- package/dist/name-scrambling.js +138 -0
- package/dist/name-scrambling.test.js +16 -0
- package/dist/p3-observability.test.js +281 -0
- package/dist/p5-orchestrator.test.js +225 -0
- package/dist/pairwise-preference.js +294 -0
- package/dist/pairwise-preference.test.js +140 -0
- package/dist/planner-constraints.js +104 -0
- package/dist/planner-prompts.js +155 -0
- package/dist/planner-telemetry.js +415 -0
- package/dist/planner-trace.js +214 -0
- package/dist/planner.js +162 -167
- package/dist/plsb/artifact.js +116 -0
- package/dist/plsb/cli.js +71 -0
- package/dist/plsb/index.js +19 -0
- package/dist/plsb/leaderboard.js +249 -0
- package/dist/plsb/report-md.js +156 -0
- package/dist/plsb/schema.js +179 -0
- package/dist/plsb-benchmark.js +284 -0
- package/dist/plsb-benchmark.test.js +119 -0
- package/dist/policy/cli.js +134 -0
- package/dist/policy/engine.js +333 -0
- package/dist/policy/index.js +12 -0
- package/dist/policy/types.js +59 -0
- package/dist/policy-miner.js +505 -0
- package/dist/precision-analyze.js +229 -0
- package/dist/precision-benchmark.js +147 -0
- package/dist/precision-label-c.js +134 -0
- package/dist/precision-label.js +193 -0
- package/dist/precision-report-c.js +149 -0
- package/dist/precision-report.js +246 -0
- package/dist/progmune-status.js +108 -0
- package/dist/proof-engine.js +479 -0
- package/dist/proof-provenance.js +315 -0
- package/dist/protocol-coverage.js +294 -0
- package/dist/protocol-detector.js +1189 -0
- package/dist/protocol-embedding-expanded.js +297 -0
- package/dist/protocol-embedding-expanded.test.js +97 -0
- package/dist/protocol-embedding.js +195 -0
- package/dist/protocol-embedding.test.js +82 -0
- package/dist/protocol-extractor-v2.js +354 -0
- package/dist/protocol-extractor-v2.test.js +140 -0
- package/dist/protocol-extractor.js +310 -0
- package/dist/protocol-extractor.test.js +113 -0
- package/dist/protocol-foundation.js +322 -0
- package/dist/protocol-foundation.test.js +163 -0
- package/dist/protocol-frontier.js +243 -0
- package/dist/protocol-frontier.test.js +92 -0
- package/dist/protocol-gap-analyzer.js +228 -0
- package/dist/protocol-gap-analyzer.test.js +49 -0
- package/dist/protocol-invariants.js +276 -0
- package/dist/protocol-invariants.test.js +111 -0
- package/dist/protocol-knowledge.js +464 -0
- package/dist/protocol-miner.js +343 -0
- package/dist/protocol-mining.js +207 -0
- package/dist/protocol-mining.test.js +37 -0
- package/dist/protocol-registry.js +1 -1
- package/dist/protocol-security-benchmark.js +222 -0
- package/dist/protocol-vulnerability.js +257 -0
- package/dist/protocol-vulnerability.test.js +60 -0
- package/dist/python-benchmark.js +120 -0
- package/dist/python-emitter.js +163 -45
- package/dist/python-protocol-extractor.js +187 -0
- package/dist/python-protocol-extractor.test.js +116 -0
- package/dist/realworld-benchmark.js +646 -0
- package/dist/realworld-benchmark.test.js +36 -0
- package/dist/repair-arch.test.js +411 -0
- package/dist/repair-evolution.test.js +454 -0
- package/dist/repair-executor.js +719 -0
- package/dist/repair-proposal.js +4 -4
- package/dist/repair-ranker.js +141 -0
- package/dist/repair-strategies.js +419 -0
- package/dist/repair-taxonomy.js +234 -0
- package/dist/repair-types.js +12 -0
- package/dist/repo-evaluator.js +250 -0
- package/dist/repo-evaluator.test.js +128 -0
- package/dist/resource-abstraction.js +242 -0
- package/dist/resource-detector.js +211 -0
- package/dist/result.test.js +43 -0
- package/dist/reward-system.js +411 -0
- package/dist/reward-system.test.js +175 -0
- package/dist/risk-model.js +215 -0
- package/dist/rule-miner.js +234 -7
- package/dist/rule-specificity.js +254 -0
- package/dist/runtime-types.js +27 -0
- package/dist/scaffold.js +208 -0
- package/dist/scale-collector.test.js +101 -0
- package/dist/scale-trajectory-collector.js +128 -0
- package/dist/sdk.js +250 -0
- package/dist/search-planner.js +4 -41
- package/dist/semantic-snapshot.js +1 -1
- package/dist/semantic-topology.js +121 -0
- package/dist/semantic-trace.js +310 -317
- package/dist/sequence-extractor.js +343 -0
- package/dist/skill-library.js +245 -0
- package/dist/skill-planner.test.js +189 -0
- package/dist/software-physics.js +291 -0
- package/dist/software-physics.test.js +81 -0
- package/dist/ssg-precision.js +478 -0
- package/dist/ssg-validator.js +71 -21
- package/dist/state-inference-doubleblind.test.js +160 -0
- package/dist/state-inference.js +516 -0
- package/dist/state-inference.test.js +115 -0
- package/dist/state-machine-fingerprint.js +345 -0
- package/dist/state-machine-fingerprint.test.js +120 -0
- package/dist/state-miner.js +386 -0
- package/dist/state-name-inference.js +213 -0
- package/dist/state-name-inference.test.js +69 -0
- package/dist/strategy-planner.js +262 -96
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
- package/package.json +74 -7
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P4.0: Logistic Reward Model Tests
|
|
4
|
+
*
|
|
5
|
+
* Verifying:
|
|
6
|
+
* 1. Model trains on telemetry data and converges
|
|
7
|
+
* 2. Feature importance is interpretable
|
|
8
|
+
* 3. Score produces valid probabilities [0,1]
|
|
9
|
+
* 4. Off-policy comparison shows improvement over baseline
|
|
10
|
+
* 5. Export/import roundtrip preserves weights
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
const vitest_1 = require("vitest");
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const logistic_reward_1 = require("./logistic-reward");
|
|
50
|
+
const planner_telemetry_1 = require("./planner-telemetry");
|
|
51
|
+
const LR_DIR = path.resolve(__dirname, "..", "test-logistic-reward");
|
|
52
|
+
process.env.PROGMUNE_PROJECT_DIR = LR_DIR;
|
|
53
|
+
fs.mkdirSync(LR_DIR, { recursive: true });
|
|
54
|
+
fs.mkdirSync(path.join(LR_DIR, ".progmune_corpus", "telemetry"), { recursive: true });
|
|
55
|
+
function seedTrainingData(telemetry, samples) {
|
|
56
|
+
// Pattern: safe repairs (close_file) are usually accepted + executed successfully
|
|
57
|
+
// Pattern: leaky repairs (skip close) are usually rejected or fail execution
|
|
58
|
+
for (let i = 0; i < samples; i++) {
|
|
59
|
+
const safe = i % 3 !== 0; // 2/3 are safe repairs
|
|
60
|
+
const fp = safe
|
|
61
|
+
? (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "write_file", "close_file"], "resource_leak")
|
|
62
|
+
: (0, planner_telemetry_1.candidateFingerprint)("FileProtocol", ["open_file", "write_file"], "resource_leak");
|
|
63
|
+
const id = telemetry.recordDecision({
|
|
64
|
+
goal: `train goal ${i}`,
|
|
65
|
+
protocol: "FileProtocol", violationType: "resource_leak",
|
|
66
|
+
candidates: [
|
|
67
|
+
{ candidateId: fp, source: "protocol", evidenceSources: ["protocol"],
|
|
68
|
+
actions: safe ? ["open_file", "write_file", "close_file"] : ["open_file", "write_file"],
|
|
69
|
+
explanation: safe ? "safe close" : "skip close" },
|
|
70
|
+
],
|
|
71
|
+
selectedCandidateId: fp,
|
|
72
|
+
});
|
|
73
|
+
// Safe: 90% accepted + executed. Leaky: 80% rejected.
|
|
74
|
+
const acceptRoll = Math.random();
|
|
75
|
+
if (safe) {
|
|
76
|
+
const accepted = acceptRoll < 0.9;
|
|
77
|
+
telemetry.recordFeedback(id, {
|
|
78
|
+
decision: accepted ? "accepted" : "rejected",
|
|
79
|
+
executionResult: accepted ? { success: true, violations: [] } : { success: false, violations: ["resource_leak"] },
|
|
80
|
+
timestamp: Date.now(),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const accepted = acceptRoll < 0.2;
|
|
85
|
+
telemetry.recordFeedback(id, {
|
|
86
|
+
decision: accepted ? "accepted" : "rejected",
|
|
87
|
+
executionResult: accepted ? { success: false, violations: ["resource_leak"] } : undefined,
|
|
88
|
+
timestamp: Date.now(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
(0, vitest_1.describe)("LogisticRewardModel", () => {
|
|
94
|
+
(0, vitest_1.it)("trains on telemetry data and converges", () => {
|
|
95
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(LR_DIR, ".progmune_corpus", "telemetry", `lr-train-${Date.now()}.jsonl`));
|
|
96
|
+
seedTrainingData(telemetry, 200);
|
|
97
|
+
const model = logistic_reward_1.LogisticRewardModel.train(telemetry);
|
|
98
|
+
(0, vitest_1.expect)(model.isTrained).toBe(true);
|
|
99
|
+
(0, vitest_1.expect)(model.sampleCount).toBeGreaterThanOrEqual(50);
|
|
100
|
+
(0, vitest_1.expect)(model.finalLoss).toBeLessThan(1.0); // should be better than random
|
|
101
|
+
// Weights should be non-zero after training
|
|
102
|
+
(0, vitest_1.expect)(model.weights.some(w => Math.abs(w) > 1e-6)).toBe(true);
|
|
103
|
+
model.printWeights();
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.it)("produces valid probability scores [0,1]", () => {
|
|
106
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(LR_DIR, ".progmune_corpus", "telemetry", `lr-score-${Date.now()}.jsonl`));
|
|
107
|
+
seedTrainingData(telemetry, 100);
|
|
108
|
+
const model = logistic_reward_1.LogisticRewardModel.train(telemetry);
|
|
109
|
+
// Safe repair should score higher than leaky repair
|
|
110
|
+
const safeFeatures = {
|
|
111
|
+
protocolSafety: 1.0, historicalSuccessRate: 0.8, actionCount: 3,
|
|
112
|
+
latencyCost: 0.4, auditability: 0.75, corpusEvidence: 5, source: "protocol",
|
|
113
|
+
};
|
|
114
|
+
const leakyFeatures = {
|
|
115
|
+
protocolSafety: 0.3, historicalSuccessRate: 0.3, actionCount: 2,
|
|
116
|
+
latencyCost: 0.3, auditability: 0.4, corpusEvidence: 1, source: "corpus",
|
|
117
|
+
};
|
|
118
|
+
const safeScore = model.score(safeFeatures, { acceptanceRate: 0.85, executionSuccessRate: 0.9 });
|
|
119
|
+
const leakyScore = model.score(leakyFeatures, { acceptanceRate: 0.15, executionSuccessRate: 0.1 });
|
|
120
|
+
(0, vitest_1.expect)(safeScore).toBeGreaterThanOrEqual(0);
|
|
121
|
+
(0, vitest_1.expect)(safeScore).toBeLessThanOrEqual(1);
|
|
122
|
+
(0, vitest_1.expect)(leakyScore).toBeGreaterThanOrEqual(0);
|
|
123
|
+
(0, vitest_1.expect)(leakyScore).toBeLessThanOrEqual(1);
|
|
124
|
+
// Safe should score higher than leaky
|
|
125
|
+
(0, vitest_1.expect)(safeScore).toBeGreaterThan(leakyScore);
|
|
126
|
+
});
|
|
127
|
+
(0, vitest_1.it)("falls back gracefully with insufficient data", () => {
|
|
128
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(LR_DIR, ".progmune_corpus", "telemetry", `lr-fallback-${Date.now()}.jsonl`));
|
|
129
|
+
// Only 5 samples — below minSamples=50
|
|
130
|
+
seedTrainingData(telemetry, 5);
|
|
131
|
+
const model = logistic_reward_1.LogisticRewardModel.train(telemetry);
|
|
132
|
+
(0, vitest_1.expect)(model.isTrained).toBe(false);
|
|
133
|
+
(0, vitest_1.expect)(model.sampleCount).toBe(5);
|
|
134
|
+
// Should still produce valid scores (weights are initialized to 0)
|
|
135
|
+
const score = model.score({ protocolSafety: 0.5, historicalSuccessRate: 0.5, actionCount: 2, latencyCost: 0.3, auditability: 0.5, corpusEvidence: 0, source: "protocol" }, { acceptanceRate: 0.5, executionSuccessRate: 0.5 });
|
|
136
|
+
(0, vitest_1.expect)(score).toBeCloseTo(0.5, 1); // sigmoid(0) = 0.5
|
|
137
|
+
});
|
|
138
|
+
(0, vitest_1.it)("feature importance is interpretable", () => {
|
|
139
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(LR_DIR, ".progmune_corpus", "telemetry", `lr-importance-${Date.now()}.jsonl`));
|
|
140
|
+
seedTrainingData(telemetry, 150);
|
|
141
|
+
const model = logistic_reward_1.LogisticRewardModel.train(telemetry);
|
|
142
|
+
const importance = model.featureImportance();
|
|
143
|
+
(0, vitest_1.expect)(importance.length).toBe(7);
|
|
144
|
+
// Top features should have positive importance
|
|
145
|
+
(0, vitest_1.expect)(importance[0].importance).toBeGreaterThan(0);
|
|
146
|
+
model.printWeights();
|
|
147
|
+
});
|
|
148
|
+
(0, vitest_1.it)("export/import roundtrip preserves weights", () => {
|
|
149
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(LR_DIR, ".progmune_corpus", "telemetry", `lr-export-${Date.now()}.jsonl`));
|
|
150
|
+
seedTrainingData(telemetry, 100);
|
|
151
|
+
const original = logistic_reward_1.LogisticRewardModel.train(telemetry);
|
|
152
|
+
const exported = original.exportWeights();
|
|
153
|
+
const imported = logistic_reward_1.LogisticRewardModel.importWeights(exported);
|
|
154
|
+
(0, vitest_1.expect)(imported.isTrained).toBe(true);
|
|
155
|
+
(0, vitest_1.expect)(imported.sampleCount).toBe(original.sampleCount);
|
|
156
|
+
(0, vitest_1.expect)(imported.weights).toEqual(original.weights);
|
|
157
|
+
(0, vitest_1.expect)(imported.bias).toBe(original.bias);
|
|
158
|
+
// Scores should be identical
|
|
159
|
+
const features = { protocolSafety: 0.7, historicalSuccessRate: 0.5, actionCount: 2, latencyCost: 0.3, auditability: 0.6, corpusEvidence: 3, source: "protocol" };
|
|
160
|
+
const stats = { acceptanceRate: 0.8, executionSuccessRate: 0.9 };
|
|
161
|
+
(0, vitest_1.expect)(imported.score(features, stats)).toBe(original.score(features, stats));
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
(0, vitest_1.describe)("Model Comparison", () => {
|
|
165
|
+
(0, vitest_1.it)("compares LogisticReward against baseline", () => {
|
|
166
|
+
const telemetry = new planner_telemetry_1.PlannerTelemetry(path.join(LR_DIR, ".progmune_corpus", "telemetry", `lr-compare-${Date.now()}.jsonl`));
|
|
167
|
+
seedTrainingData(telemetry, 300);
|
|
168
|
+
const comparisons = (0, logistic_reward_1.compareModels)(telemetry);
|
|
169
|
+
(0, vitest_1.expect)(comparisons.length).toBeGreaterThanOrEqual(1);
|
|
170
|
+
const lr = comparisons.find(c => c.model === "LogisticReward");
|
|
171
|
+
if (lr.trained) {
|
|
172
|
+
(0, vitest_1.expect)(lr.accuracy).toBeGreaterThan(0.5); // better than random
|
|
173
|
+
(0, vitest_1.expect)(lr.logLoss).toBeLessThan(1.0);
|
|
174
|
+
}
|
|
175
|
+
console.log("\n─── Model Comparison ───");
|
|
176
|
+
for (const c of comparisons) {
|
|
177
|
+
console.log(` ${c.model.padEnd(22)} acc=${(c.accuracy * 100).toFixed(1)}% logLoss=${c.logLoss.toFixed(4)}`);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P5.0: Hierarchical Macro Graph
|
|
4
|
+
*
|
|
5
|
+
* Lifts MacroRepairs from a flat catalog into a composable skill graph.
|
|
6
|
+
* Each MacroNode is a "skill" with preconditions, actions, postconditions,
|
|
7
|
+
* and reward, enabling hierarchical planning.
|
|
8
|
+
*
|
|
9
|
+
* AlphaGo Zero analogy:
|
|
10
|
+
* Primitive action = single function call
|
|
11
|
+
* Macro = 定式 (joseki) — a proven sequence that achieves a known outcome
|
|
12
|
+
* MacroGraph = opening book + pattern library
|
|
13
|
+
*
|
|
14
|
+
* Planner search depth is reduced by an order of magnitude when it
|
|
15
|
+
* can search macro nodes instead of individual actions.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.MacroGraphBuilder = void 0;
|
|
19
|
+
const macro_repair_1 = require("./macro-repair");
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════
|
|
21
|
+
// State Inference
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════
|
|
23
|
+
/** Infer pre/post conditions — only preconditions NOT produced by the chain are true preconditions. */
|
|
24
|
+
function inferConditions(actions, rules) {
|
|
25
|
+
const allPre = new Set();
|
|
26
|
+
const produced = new Set();
|
|
27
|
+
const invalidated = new Set();
|
|
28
|
+
let current = new Set();
|
|
29
|
+
for (const fn of actions) {
|
|
30
|
+
const rule = rules.get(fn);
|
|
31
|
+
if (!rule)
|
|
32
|
+
continue;
|
|
33
|
+
// Collect all preconditions needed at any step
|
|
34
|
+
for (const p of rule.pre_states) {
|
|
35
|
+
if (p.length > 0)
|
|
36
|
+
allPre.add(p);
|
|
37
|
+
}
|
|
38
|
+
// Apply: invalidate current, then produce
|
|
39
|
+
if (rule.invalidate)
|
|
40
|
+
rule.invalidate.forEach(s => { invalidated.add(s); current.delete(s); });
|
|
41
|
+
for (const p of rule.post_states) {
|
|
42
|
+
current.add(p);
|
|
43
|
+
produced.add(p);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// True preconditions: needed but NOT produced by any action in the chain
|
|
47
|
+
const preconditions = [...allPre].filter(p => !produced.has(p));
|
|
48
|
+
// Postconditions: active states + invalidated states
|
|
49
|
+
const postconditions = [...current, ...invalidated].filter(s => s.length > 0);
|
|
50
|
+
return { preconditions, postconditions };
|
|
51
|
+
}
|
|
52
|
+
// ═══════════════════════════════════════════════════════════════
|
|
53
|
+
// Macro Graph Builder
|
|
54
|
+
// ═══════════════════════════════════════════════════════════════
|
|
55
|
+
class MacroGraphBuilder {
|
|
56
|
+
constructor() {
|
|
57
|
+
this._graph = { nodes: new Map(), edges: [] };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Learn macro nodes from telemetry data.
|
|
61
|
+
* Mines MacroRepairs and converts them into MacroNodes with state conditions.
|
|
62
|
+
*/
|
|
63
|
+
learnMacros(telemetry, rules, minAcceptance = 0.7, minFrequency = 3) {
|
|
64
|
+
const macros = (0, macro_repair_1.mineMacroRepairs)(telemetry, minAcceptance, minFrequency);
|
|
65
|
+
for (const macro of macros) {
|
|
66
|
+
const { preconditions, postconditions } = inferConditions(macro.actions, rules);
|
|
67
|
+
const nodeId = macro.id;
|
|
68
|
+
if (this._graph.nodes.has(nodeId))
|
|
69
|
+
continue;
|
|
70
|
+
this._graph.nodes.set(nodeId, {
|
|
71
|
+
id: nodeId,
|
|
72
|
+
name: macro.actions.join(" → "),
|
|
73
|
+
protocol: macro.protocol,
|
|
74
|
+
preconditions,
|
|
75
|
+
actions: macro.actions,
|
|
76
|
+
postconditions,
|
|
77
|
+
reward: macro.acceptanceRate * 0.7 + macro.executionSuccessRate * 0.3,
|
|
78
|
+
frequency: macro.frequency,
|
|
79
|
+
source: macro,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Link macros: find composable pairs (post of A matches pre of B)
|
|
83
|
+
this.linkMacros();
|
|
84
|
+
return this._graph;
|
|
85
|
+
}
|
|
86
|
+
/** Link macros into a composable graph based on state matching. */
|
|
87
|
+
linkMacros() {
|
|
88
|
+
const nodeList = [...this._graph.nodes.values()];
|
|
89
|
+
for (const a of nodeList) {
|
|
90
|
+
for (const b of nodeList) {
|
|
91
|
+
if (a.id === b.id)
|
|
92
|
+
continue;
|
|
93
|
+
// Check if A's postconditions satisfy B's preconditions
|
|
94
|
+
const overlap = b.preconditions.filter(p => a.postconditions.includes(p));
|
|
95
|
+
if (overlap.length > 0 || a.postconditions.length === 0 || b.preconditions.length === 0) {
|
|
96
|
+
this._graph.edges.push({
|
|
97
|
+
from: a.id, to: b.id,
|
|
98
|
+
frequency: Math.min(a.frequency, b.frequency),
|
|
99
|
+
successRate: a.reward * b.reward,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Compose a chain of macros from start state to goal state.
|
|
107
|
+
*
|
|
108
|
+
* Uses the macro graph to find multi-step skill chains,
|
|
109
|
+
* reducing the planner's search depth compared to action-level BFS.
|
|
110
|
+
*/
|
|
111
|
+
compose(currentStates, targetStates, maxDepth = 5) {
|
|
112
|
+
const chains = [];
|
|
113
|
+
const currentSet = new Set(currentStates);
|
|
114
|
+
const targetSet = new Set(targetStates);
|
|
115
|
+
// Find macros whose preconditions are satisfied by current state
|
|
116
|
+
const startable = [...this._graph.nodes.values()].filter(n => n.preconditions.length === 0 || n.preconditions.every(p => currentSet.has(p)));
|
|
117
|
+
// BFS over macro nodes
|
|
118
|
+
const visited = new Set();
|
|
119
|
+
const queue = startable.map(m => ({ macros: [m], states: new Set([...currentStates, ...m.postconditions]), depth: 1 }));
|
|
120
|
+
while (queue.length > 0 && chains.length < 10) {
|
|
121
|
+
const { macros, states, depth } = queue.shift();
|
|
122
|
+
if (depth > maxDepth)
|
|
123
|
+
continue;
|
|
124
|
+
// Check if target reached
|
|
125
|
+
if (targetSet.size > 0 && targetStates.every(t => states.has(t))) {
|
|
126
|
+
chains.push(macros);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
// Find next macro
|
|
130
|
+
for (const node of this._graph.nodes.values()) {
|
|
131
|
+
if (macros.some(m => m.id === node.id))
|
|
132
|
+
continue; // no cycles
|
|
133
|
+
const preOk = node.preconditions.length === 0 || node.preconditions.every(p => states.has(p));
|
|
134
|
+
if (!preOk)
|
|
135
|
+
continue;
|
|
136
|
+
const nextStates = new Set(states);
|
|
137
|
+
for (const p of node.postconditions)
|
|
138
|
+
nextStates.add(p);
|
|
139
|
+
const key = macros.map(m => m.id).join("→") + "→" + node.id;
|
|
140
|
+
if (visited.has(key))
|
|
141
|
+
continue;
|
|
142
|
+
visited.add(key);
|
|
143
|
+
queue.push({ macros: [...macros, node], states: nextStates, depth: depth + 1 });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Sort by total reward
|
|
147
|
+
chains.sort((a, b) => {
|
|
148
|
+
const rewardA = a.reduce((s, m) => s + m.reward, 0) / a.length;
|
|
149
|
+
const rewardB = b.reduce((s, m) => s + m.reward, 0) / b.length;
|
|
150
|
+
return rewardB - rewardA;
|
|
151
|
+
});
|
|
152
|
+
return chains;
|
|
153
|
+
}
|
|
154
|
+
/** Get all macro chains from the graph. */
|
|
155
|
+
getAllMacroChains(maxDepth = 3) {
|
|
156
|
+
const chains = [];
|
|
157
|
+
const nodeList = [...this._graph.nodes.values()];
|
|
158
|
+
for (const start of nodeList) {
|
|
159
|
+
// Find chains starting from this node (using graph edges)
|
|
160
|
+
const visited = new Set();
|
|
161
|
+
const queue = [{ macros: [start], depth: 1 }];
|
|
162
|
+
while (queue.length > 0 && chains.length < 50) {
|
|
163
|
+
const { macros, depth } = queue.shift();
|
|
164
|
+
if (depth > maxDepth)
|
|
165
|
+
continue;
|
|
166
|
+
if (macros.length > 1)
|
|
167
|
+
chains.push(macros);
|
|
168
|
+
const last = macros[macros.length - 1];
|
|
169
|
+
const nextEdges = this._graph.edges.filter(e => e.from === last.id);
|
|
170
|
+
for (const edge of nextEdges) {
|
|
171
|
+
const next = this._graph.nodes.get(edge.to);
|
|
172
|
+
if (!next)
|
|
173
|
+
continue;
|
|
174
|
+
const key = macros.map(m => m.id).join("→") + "→" + next.id;
|
|
175
|
+
if (visited.has(key))
|
|
176
|
+
continue;
|
|
177
|
+
visited.add(key);
|
|
178
|
+
queue.push({ macros: [...macros, next], depth: depth + 1 });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
chains.sort((a, b) => {
|
|
183
|
+
const rA = a.reduce((s, m) => s + m.reward, 0) / a.length;
|
|
184
|
+
const rB = b.reduce((s, m) => s + m.reward, 0) / b.length;
|
|
185
|
+
return rB - rA;
|
|
186
|
+
});
|
|
187
|
+
return chains;
|
|
188
|
+
}
|
|
189
|
+
get graph() { return this._graph; }
|
|
190
|
+
get nodeCount() { return this._graph.nodes.size; }
|
|
191
|
+
get edgeCount() { return this._graph.edges.length; }
|
|
192
|
+
}
|
|
193
|
+
exports.MacroGraphBuilder = MacroGraphBuilder;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P4.6: Macro Repair Mining
|
|
4
|
+
*
|
|
5
|
+
* Mines high-acceptance trajectory patterns from Telemetry
|
|
6
|
+
* and converts them into reusable MacroRepair templates.
|
|
7
|
+
*
|
|
8
|
+
* A MacroRepair is a frequently-accepted action sequence that
|
|
9
|
+
* can be directly suggested as a repair candidate — serving
|
|
10
|
+
* as a fourth candidate source alongside Corpus/Protocol/Antibody.
|
|
11
|
+
*
|
|
12
|
+
* Example mined macro:
|
|
13
|
+
* verify_password → generate_jwt → create_session
|
|
14
|
+
* (acceptance: 92%, frequency: 45)
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.mineMacroRepairs = mineMacroRepairs;
|
|
51
|
+
exports.saveMacroRepairs = saveMacroRepairs;
|
|
52
|
+
exports.loadMacroRepairs = loadMacroRepairs;
|
|
53
|
+
exports.printMacroReport = printMacroReport;
|
|
54
|
+
const planner_telemetry_1 = require("./planner-telemetry");
|
|
55
|
+
const fs = __importStar(require("fs"));
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const MACRO_DIR = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".progmune_corpus", "macros");
|
|
58
|
+
function ensureDir(dir) {
|
|
59
|
+
if (!fs.existsSync(dir))
|
|
60
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
// ═══════════════════════════════════════════════════════════════
|
|
63
|
+
// Mining
|
|
64
|
+
// ═══════════════════════════════════════════════════════════════
|
|
65
|
+
/**
|
|
66
|
+
* Mine high-acceptance action sequences from telemetry data.
|
|
67
|
+
*
|
|
68
|
+
* Scans all decisions with feedback, groups by action signature,
|
|
69
|
+
* and identifies sequences that meet minimum acceptance + frequency thresholds.
|
|
70
|
+
*/
|
|
71
|
+
function mineMacroRepairs(telemetry, minAcceptance = 0.7, minFrequency = 3) {
|
|
72
|
+
const decisions = telemetry.all();
|
|
73
|
+
// Group by action signature + protocol
|
|
74
|
+
const groups = new Map();
|
|
75
|
+
for (const d of decisions) {
|
|
76
|
+
if (!d.feedback || !d.selectedCandidateId || !d.protocol)
|
|
77
|
+
continue;
|
|
78
|
+
const sel = d.candidates.find(c => c.candidateId === d.selectedCandidateId);
|
|
79
|
+
if (!sel || sel.actions.length === 0)
|
|
80
|
+
continue;
|
|
81
|
+
const key = `${d.protocol}:${sel.actions.join("→")}`;
|
|
82
|
+
const entry = groups.get(key);
|
|
83
|
+
if (entry) {
|
|
84
|
+
entry.count++;
|
|
85
|
+
if (d.feedback.decision === "accepted")
|
|
86
|
+
entry.accepted++;
|
|
87
|
+
else
|
|
88
|
+
entry.rejected++;
|
|
89
|
+
if (d.feedback.executionResult?.success === true)
|
|
90
|
+
entry.execSuccess++;
|
|
91
|
+
else if (d.feedback.executionResult?.success === false)
|
|
92
|
+
entry.execFailure++;
|
|
93
|
+
if (d.cost?.latencyMs)
|
|
94
|
+
entry.totalLatency += d.cost.latencyMs;
|
|
95
|
+
entry.goals.set(d.goal, (entry.goals.get(d.goal) || 0) + 1);
|
|
96
|
+
entry.violationTypes.set(d.violationType || "unknown", (entry.violationTypes.get(d.violationType || "unknown") || 0) + 1);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
groups.set(key, {
|
|
100
|
+
accepted: d.feedback.decision === "accepted" ? 1 : 0,
|
|
101
|
+
rejected: d.feedback.decision === "rejected" ? 1 : 0,
|
|
102
|
+
execSuccess: d.feedback.executionResult?.success === true ? 1 : 0,
|
|
103
|
+
execFailure: d.feedback.executionResult?.success === false ? 1 : 0,
|
|
104
|
+
totalLatency: d.cost?.latencyMs || 0,
|
|
105
|
+
count: 1,
|
|
106
|
+
goals: new Map([[d.goal, 1]]),
|
|
107
|
+
violationTypes: new Map([[d.violationType || "unknown", 1]]),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const macros = [];
|
|
112
|
+
for (const [key, entry] of groups) {
|
|
113
|
+
if (entry.count < minFrequency)
|
|
114
|
+
continue;
|
|
115
|
+
const totalFeedback = entry.accepted + entry.rejected;
|
|
116
|
+
const acceptanceRate = totalFeedback > 0 ? entry.accepted / totalFeedback : 0;
|
|
117
|
+
if (acceptanceRate < minAcceptance)
|
|
118
|
+
continue;
|
|
119
|
+
const execTotal = entry.execSuccess + entry.execFailure;
|
|
120
|
+
const executionSuccessRate = execTotal > 0 ? entry.execSuccess / execTotal : 0;
|
|
121
|
+
const [protocol, actionStr] = key.split(":");
|
|
122
|
+
const actions = actionStr.split("→");
|
|
123
|
+
const topGoal = [...entry.goals.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] || "unknown";
|
|
124
|
+
const topViolation = [...entry.violationTypes.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] || "unknown";
|
|
125
|
+
macros.push({
|
|
126
|
+
id: `macro-${(0, planner_telemetry_1.candidateFingerprint)(protocol, actions, topViolation)}`,
|
|
127
|
+
actions,
|
|
128
|
+
protocol,
|
|
129
|
+
violationType: topViolation,
|
|
130
|
+
acceptanceRate,
|
|
131
|
+
executionSuccessRate,
|
|
132
|
+
frequency: entry.count,
|
|
133
|
+
avgLatencyMs: entry.count > 0 ? entry.totalLatency / entry.count : 0,
|
|
134
|
+
goal: topGoal,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return macros.sort((a, b) => b.acceptanceRate - a.acceptanceRate);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Persist mined macros for reuse across sessions.
|
|
141
|
+
*/
|
|
142
|
+
function saveMacroRepairs(macros) {
|
|
143
|
+
ensureDir(MACRO_DIR);
|
|
144
|
+
const filepath = path.join(MACRO_DIR, `macros-${new Date().toISOString().slice(0, 10)}.json`);
|
|
145
|
+
fs.writeFileSync(filepath, JSON.stringify(macros, null, 2));
|
|
146
|
+
return filepath;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Load previously mined macros.
|
|
150
|
+
*/
|
|
151
|
+
function loadMacroRepairs() {
|
|
152
|
+
if (!fs.existsSync(MACRO_DIR))
|
|
153
|
+
return [];
|
|
154
|
+
const macros = [];
|
|
155
|
+
const files = fs.readdirSync(MACRO_DIR).filter(f => f.endsWith(".json"));
|
|
156
|
+
for (const file of files) {
|
|
157
|
+
try {
|
|
158
|
+
const data = JSON.parse(fs.readFileSync(path.join(MACRO_DIR, file), "utf-8"));
|
|
159
|
+
if (Array.isArray(data))
|
|
160
|
+
macros.push(...data);
|
|
161
|
+
}
|
|
162
|
+
catch { /* skip */ }
|
|
163
|
+
}
|
|
164
|
+
return macros.sort((a, b) => b.acceptanceRate - a.acceptanceRate);
|
|
165
|
+
}
|
|
166
|
+
function printMacroReport(macros) {
|
|
167
|
+
console.log("\n─── Macro Repair Mining Report ───");
|
|
168
|
+
console.log(`Mined ${macros.length} high-acceptance repair templates\n`);
|
|
169
|
+
if (macros.length === 0) {
|
|
170
|
+
console.log(" No macros meet the minimum thresholds. Collect more feedback data.");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
console.log("Top 10 Macros:");
|
|
174
|
+
console.log("Accept ExecOk Freq Actions");
|
|
175
|
+
console.log("──────────────────────────────────────────────────");
|
|
176
|
+
for (const m of macros.slice(0, 10)) {
|
|
177
|
+
const acc = (m.acceptanceRate * 100).toFixed(0).padStart(4);
|
|
178
|
+
const exec = (m.executionSuccessRate * 100).toFixed(0).padStart(4);
|
|
179
|
+
const freq = String(m.frequency).padStart(4);
|
|
180
|
+
console.log(` ${acc}% ${exec}% ${freq} ${m.actions.join(" → ")}`);
|
|
181
|
+
}
|
|
182
|
+
console.log();
|
|
183
|
+
}
|