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,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P9.1+P9.3: Protocol Invariant Mining, Violation Detection & Illegal Transitions
|
|
4
|
+
*
|
|
5
|
+
* Three detection modes:
|
|
6
|
+
* 1. MISSING_STATE: template has N states, test has M<N (resource leak, auth bypass)
|
|
7
|
+
* 2. MISSING_EDGE: template has transition A→B, test doesn't (broken lifecycle)
|
|
8
|
+
* 3. ILLEGAL_EDGE: test has transition that template NEVER allows (use-after-free, double-free)
|
|
9
|
+
*
|
|
10
|
+
* Mode 3 is P9.3: upgrades from "State Completeness" to "Protocol Correctness"
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.detectStructuralViolations = detectStructuralViolations;
|
|
14
|
+
exports.mineInvariants = mineInvariants;
|
|
15
|
+
exports.checkInvariants = checkInvariants;
|
|
16
|
+
exports.detectIllegalTransitions = detectIllegalTransitions;
|
|
17
|
+
exports.printInvariants = printInvariants;
|
|
18
|
+
exports.printViolations = printViolations;
|
|
19
|
+
const state_inference_1 = require("./experimental/state-inference");
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════
|
|
21
|
+
// Core Detection: Structural Violation (P9.1)
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════
|
|
23
|
+
function detectStructuralViolations(testSM, templateSM) {
|
|
24
|
+
const violations = [];
|
|
25
|
+
const templateExits = templateSM.states.filter(s => s.role === "exit");
|
|
26
|
+
const templateBridges = templateSM.states.filter(s => s.role === "bridge");
|
|
27
|
+
// ── MODE 1: Missing State Detection ──
|
|
28
|
+
if (templateSM.stateCount > testSM.stateCount) {
|
|
29
|
+
violations.push({
|
|
30
|
+
invariant: {
|
|
31
|
+
type: "MUST_RELEASE",
|
|
32
|
+
triggerState: "entry",
|
|
33
|
+
requiredState: templateExits.map(e => e.id).join("|"),
|
|
34
|
+
description: "Resource acquired must eventually be released",
|
|
35
|
+
confidence: 0.95,
|
|
36
|
+
},
|
|
37
|
+
sequence: [],
|
|
38
|
+
triggerIndex: 0,
|
|
39
|
+
description: `Missing release: template has ${templateSM.stateCount} states, test has ${testSM.stateCount}. ${templateSM.stateCount - testSM.stateCount} state(s) missing — resource leak detected.`,
|
|
40
|
+
violationSubtype: "missing_release",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (templateBridges.length > 0) {
|
|
44
|
+
const testBridges = testSM.states.filter(s => s.role === "bridge");
|
|
45
|
+
if (testBridges.length < templateBridges.length) {
|
|
46
|
+
violations.push({
|
|
47
|
+
invariant: {
|
|
48
|
+
type: "MUST_PRECEDE",
|
|
49
|
+
triggerState: "bridge",
|
|
50
|
+
requiredState: "exit",
|
|
51
|
+
description: "Verification bridge must precede privileged action",
|
|
52
|
+
confidence: 0.9,
|
|
53
|
+
},
|
|
54
|
+
sequence: [],
|
|
55
|
+
triggerIndex: 0,
|
|
56
|
+
description: `Missing prerequisite: template has ${templateBridges.length} bridge state(s), test has ${testBridges.length}. Verification step skipped.`,
|
|
57
|
+
violationSubtype: "missing_prerequisite",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ── MODE 2: Missing Edge Detection (broken lifecycle) ──
|
|
62
|
+
const templateEdges = extractEdgeSet(templateSM);
|
|
63
|
+
const testEdges = extractEdgeSet(testSM);
|
|
64
|
+
const missingEdges = [...templateEdges].filter(e => !testEdges.has(e));
|
|
65
|
+
if (missingEdges.length > 0 && templateSM.stateCount <= testSM.stateCount + 1) {
|
|
66
|
+
violations.push({
|
|
67
|
+
invariant: {
|
|
68
|
+
type: "MUST_COMMIT",
|
|
69
|
+
triggerState: "bridge",
|
|
70
|
+
requiredState: "exit",
|
|
71
|
+
description: "Transaction must be completed with commit or rollback",
|
|
72
|
+
confidence: 0.85,
|
|
73
|
+
},
|
|
74
|
+
sequence: [],
|
|
75
|
+
triggerIndex: 0,
|
|
76
|
+
description: `Incomplete lifecycle: template has ${templateEdges.size} transitions, test has ${testEdges.size}. Missing ${missingEdges.length} transition(s): ${missingEdges.slice(0, 3).join(", ")}.`,
|
|
77
|
+
violationSubtype: "missing_commit",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// ── MODE 3 (P9.3): Illegal Transition Detection ──
|
|
81
|
+
const illegalEdges = [...testEdges].filter(e => !templateEdges.has(e));
|
|
82
|
+
if (illegalEdges.length > 0) {
|
|
83
|
+
violations.push({
|
|
84
|
+
invariant: {
|
|
85
|
+
type: "MUST_RELEASE",
|
|
86
|
+
triggerState: "any",
|
|
87
|
+
requiredState: "any",
|
|
88
|
+
description: "No transition in the template allows this state change",
|
|
89
|
+
confidence: 0.95,
|
|
90
|
+
},
|
|
91
|
+
sequence: [],
|
|
92
|
+
triggerIndex: 0,
|
|
93
|
+
description: `Illegal transition detected: ${illegalEdges.length} edge(s) present in test but absent from template. Possible use-after-free, double-free, or auth bypass.`,
|
|
94
|
+
violationSubtype: "illegal_transition",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return violations;
|
|
98
|
+
}
|
|
99
|
+
function extractEdgeSet(sm) {
|
|
100
|
+
const edges = new Set();
|
|
101
|
+
for (let i = 0; i < sm.stateTransitions.length; i++) {
|
|
102
|
+
for (let j = 0; j < (sm.stateTransitions[i] || []).length; j++) {
|
|
103
|
+
if (sm.stateTransitions[i][j] > 0)
|
|
104
|
+
edges.add(`${i}→${j}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return edges;
|
|
108
|
+
}
|
|
109
|
+
function mineInvariants(sm) {
|
|
110
|
+
const invariants = [];
|
|
111
|
+
if (sm.states.length === 0)
|
|
112
|
+
return invariants;
|
|
113
|
+
const entryStates = sm.states.filter(s => s.role === "entry");
|
|
114
|
+
const exitStates = sm.states.filter(s => s.role === "exit");
|
|
115
|
+
const bridgeStates = sm.states.filter(s => s.role === "bridge");
|
|
116
|
+
for (const entry of entryStates) {
|
|
117
|
+
for (const exit of exitStates) {
|
|
118
|
+
if (exit.outDegree === 0 && entry.outDegree > 0) {
|
|
119
|
+
if (findPath(sm, entry, exit)) {
|
|
120
|
+
invariants.push({
|
|
121
|
+
type: "MUST_RELEASE",
|
|
122
|
+
triggerState: entry.id,
|
|
123
|
+
requiredState: exit.id,
|
|
124
|
+
description: `${entry.id} ⇒ Eventually ${exit.id} (resource acquired must be released)`,
|
|
125
|
+
confidence: 0.9,
|
|
126
|
+
});
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const bridge of bridgeStates) {
|
|
133
|
+
const reachableExits = exitStates.filter(e => findPath(sm, bridge, e) !== null);
|
|
134
|
+
if (reachableExits.length >= 2) {
|
|
135
|
+
invariants.push({
|
|
136
|
+
type: "MUST_COMMIT",
|
|
137
|
+
triggerState: bridge.id,
|
|
138
|
+
requiredState: reachableExits.map(e => e.id).join(" | "),
|
|
139
|
+
description: `${bridge.id} ⇒ Eventually ${reachableExits.map(e => e.id).join(" | ")}`,
|
|
140
|
+
confidence: 0.85,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const exit of exitStates) {
|
|
145
|
+
const predecessors = bridgeStates.filter(b => findPath(sm, b, exit) !== null);
|
|
146
|
+
if (predecessors.length > 0) {
|
|
147
|
+
invariants.push({
|
|
148
|
+
type: "MUST_PRECEDE",
|
|
149
|
+
triggerState: predecessors.map(p => p.id).join(","),
|
|
150
|
+
requiredState: exit.id,
|
|
151
|
+
description: `${predecessors.map(p => p.id).join(" → ")} must precede ${exit.id}`,
|
|
152
|
+
confidence: 0.8,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return invariants;
|
|
157
|
+
}
|
|
158
|
+
function findPath(sm, from, to) {
|
|
159
|
+
const S = sm.states.length;
|
|
160
|
+
const fromIdx = sm.states.indexOf(from);
|
|
161
|
+
const toIdx = sm.states.indexOf(to);
|
|
162
|
+
if (fromIdx < 0 || toIdx < 0)
|
|
163
|
+
return null;
|
|
164
|
+
const visited = new Set();
|
|
165
|
+
const parent = new Map();
|
|
166
|
+
const queue = [fromIdx];
|
|
167
|
+
visited.add(fromIdx);
|
|
168
|
+
while (queue.length > 0) {
|
|
169
|
+
const curr = queue.shift();
|
|
170
|
+
if (curr === toIdx) {
|
|
171
|
+
const path = [curr];
|
|
172
|
+
let node = curr;
|
|
173
|
+
while (parent.has(node)) {
|
|
174
|
+
node = parent.get(node);
|
|
175
|
+
path.unshift(node);
|
|
176
|
+
}
|
|
177
|
+
return path;
|
|
178
|
+
}
|
|
179
|
+
for (let j = 0; j < S; j++) {
|
|
180
|
+
if (sm.stateTransitions[curr]?.[j] > 0 && !visited.has(j)) {
|
|
181
|
+
visited.add(j);
|
|
182
|
+
parent.set(j, curr);
|
|
183
|
+
queue.push(j);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
// ═══════════════════════════════════════════════════════════════
|
|
190
|
+
// Sequence-based invariant checking (for inline use)
|
|
191
|
+
// ═══════════════════════════════════════════════════════════════
|
|
192
|
+
function checkInvariants(sequence, invariants) {
|
|
193
|
+
if (sequence.length < 2 || invariants.length === 0)
|
|
194
|
+
return [];
|
|
195
|
+
const sm = (0, state_inference_1.inferStateMachine)([sequence]);
|
|
196
|
+
const violations = [];
|
|
197
|
+
for (const inv of invariants) {
|
|
198
|
+
const hasEntry = sm.states.some((s) => s.role === "entry");
|
|
199
|
+
const hasExit = sm.states.some((s) => s.role === "exit");
|
|
200
|
+
const hasBridge = sm.states.some((s) => s.role === "bridge");
|
|
201
|
+
if (hasEntry && !hasExit && inv.type === "MUST_RELEASE") {
|
|
202
|
+
violations.push({
|
|
203
|
+
invariant: inv, sequence, triggerIndex: 0,
|
|
204
|
+
description: `Missing release: ${inv.description}`,
|
|
205
|
+
violationSubtype: "missing_release",
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (hasExit && !hasBridge && inv.type === "MUST_PRECEDE") {
|
|
209
|
+
violations.push({
|
|
210
|
+
invariant: inv, sequence, triggerIndex: 0,
|
|
211
|
+
description: `Missing prerequisite: ${inv.description}`,
|
|
212
|
+
violationSubtype: "missing_prerequisite",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return violations;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Find transitions in testSM that are NEVER allowed in templateSM.
|
|
220
|
+
*
|
|
221
|
+
* This detects:
|
|
222
|
+
* - use-after-free: free → use (edge exists in test, not in template)
|
|
223
|
+
* - double-free: free → free (self-loop not in template)
|
|
224
|
+
* - auth resurrection: logout → access (reversed edge)
|
|
225
|
+
* - rollback→commit (cross-branch transition)
|
|
226
|
+
*/
|
|
227
|
+
function detectIllegalTransitions(testSM, templateSM) {
|
|
228
|
+
const templateEdges = extractEdgeSet(templateSM);
|
|
229
|
+
const testEdges = extractEdgeSet(testSM);
|
|
230
|
+
const illegal = [];
|
|
231
|
+
for (const edge of testEdges) {
|
|
232
|
+
if (templateEdges.has(edge))
|
|
233
|
+
continue;
|
|
234
|
+
const [from, to] = edge.split("→").map(Number);
|
|
235
|
+
// Check if the reverse edge exists in template (reversed transition)
|
|
236
|
+
const reverseEdge = `${to}→${from}`;
|
|
237
|
+
const isReversed = templateEdges.has(reverseEdge);
|
|
238
|
+
// Check if it's a self-loop (possible double-free)
|
|
239
|
+
const isSelfLoop = from === to;
|
|
240
|
+
// Check if the template has ANY edge from this node
|
|
241
|
+
const templateHasFrom = [...templateEdges].some(e => e.startsWith(`${from}→`));
|
|
242
|
+
const templateHasTo = [...templateEdges].some(e => e.endsWith(`→${to}`));
|
|
243
|
+
let reason = "not_in_template";
|
|
244
|
+
if (isSelfLoop && templateEdges.size > 0)
|
|
245
|
+
reason = "double_free";
|
|
246
|
+
else if (isReversed)
|
|
247
|
+
reason = "reversed";
|
|
248
|
+
else if (!templateHasFrom && templateHasTo)
|
|
249
|
+
reason = "not_in_template";
|
|
250
|
+
illegal.push({ from, to, reason });
|
|
251
|
+
}
|
|
252
|
+
return illegal;
|
|
253
|
+
}
|
|
254
|
+
// ═══════════════════════════════════════════════════════════════
|
|
255
|
+
// Reporting
|
|
256
|
+
// ═══════════════════════════════════════════════════════════════
|
|
257
|
+
function printInvariants(invariants) {
|
|
258
|
+
console.log(`\n─── Mined Protocol Invariants (${invariants.length}) ───`);
|
|
259
|
+
for (const inv of invariants) {
|
|
260
|
+
const icon = inv.type === "MUST_RELEASE" ? "🔒" : inv.type === "MUST_COMMIT" ? "🔐" : "🔑";
|
|
261
|
+
console.log(` ${icon} [${inv.confidence.toFixed(0)}] ${inv.description}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function printViolations(violations) {
|
|
265
|
+
if (violations.length === 0) {
|
|
266
|
+
console.log(` ✅ No invariant violations detected.`);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
console.log(`\n─── Invariant Violations (${violations.length}) ───`);
|
|
270
|
+
for (const v of violations) {
|
|
271
|
+
const icon = v.violationSubtype === "illegal_transition" ? "🚫" : "❌";
|
|
272
|
+
console.log(` ${icon} [${v.violationSubtype}] ${v.description}`);
|
|
273
|
+
if (v.sequence.length > 0)
|
|
274
|
+
console.log(` Sequence: ${v.sequence.join(" → ")}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* P9.1: Protocol Invariant Mining & Violation Detection Test
|
|
5
|
+
*
|
|
6
|
+
* The test: can the system detect REAL defect patterns (resource leak,
|
|
7
|
+
* missing commit, auth bypass) using ONLY state-machine invariants,
|
|
8
|
+
* without function names, keywords, or hand-written rules?
|
|
9
|
+
*/
|
|
10
|
+
const vitest_1 = require("vitest");
|
|
11
|
+
const protocol_invariants_1 = require("./protocol-invariants");
|
|
12
|
+
const state_inference_1 = require("./experimental/state-inference");
|
|
13
|
+
// ── Test data: clean (complete) and broken (defect) sequences ──
|
|
14
|
+
const FILE_CLEAN = [
|
|
15
|
+
["open_file", "read_file", "close_file"],
|
|
16
|
+
["open_file", "write_file", "close_file"],
|
|
17
|
+
];
|
|
18
|
+
const FILE_BROKEN_NO_CLOSE = [
|
|
19
|
+
["open_file", "read_file"], // ← resource leak: acquired but never released
|
|
20
|
+
["open_file", "write_file"],
|
|
21
|
+
];
|
|
22
|
+
const TX_CLEAN = [
|
|
23
|
+
["begin_tx", "insert", "commit_tx"],
|
|
24
|
+
["begin_tx", "update", "commit_tx"],
|
|
25
|
+
];
|
|
26
|
+
const TX_BROKEN_NO_COMMIT = [
|
|
27
|
+
["begin_tx", "insert"], // ← lost write: transaction never committed
|
|
28
|
+
["begin_tx", "update"],
|
|
29
|
+
];
|
|
30
|
+
const AUTH_CLEAN = [
|
|
31
|
+
["verify_password", "generate_jwt", "create_session"],
|
|
32
|
+
["verify_password", "create_session"],
|
|
33
|
+
];
|
|
34
|
+
const AUTH_BROKEN_NO_VERIFY = [
|
|
35
|
+
["generate_jwt", "create_session"], // ← auth bypass: no verification
|
|
36
|
+
["create_session"],
|
|
37
|
+
];
|
|
38
|
+
(0, vitest_1.describe)("P9.1 Protocol Invariant Detection", () => {
|
|
39
|
+
(0, vitest_1.it)("mines MUST_RELEASE invariant from acquire→use→release protocol", () => {
|
|
40
|
+
const sm = (0, state_inference_1.inferStateMachine)(FILE_CLEAN);
|
|
41
|
+
(0, state_inference_1.printInferredStateMachine)(sm);
|
|
42
|
+
const invariants = (0, protocol_invariants_1.mineInvariants)(sm);
|
|
43
|
+
(0, protocol_invariants_1.printInvariants)(invariants);
|
|
44
|
+
(0, vitest_1.expect)(invariants.length).toBeGreaterThan(0);
|
|
45
|
+
const releaseInv = invariants.find(i => i.type === "MUST_RELEASE");
|
|
46
|
+
(0, vitest_1.expect)(releaseInv).toBeTruthy();
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.it)("mines MUST_COMMIT invariant from transaction protocol", () => {
|
|
49
|
+
const sm = (0, state_inference_1.inferStateMachine)(TX_CLEAN);
|
|
50
|
+
const invariants = (0, protocol_invariants_1.mineInvariants)(sm);
|
|
51
|
+
(0, protocol_invariants_1.printInvariants)(invariants);
|
|
52
|
+
const commitInv = invariants.find(i => i.type === "MUST_RELEASE" || i.type === "MUST_COMMIT");
|
|
53
|
+
(0, vitest_1.expect)(commitInv).toBeTruthy();
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)("mines MUST_PRECEDE invariant from auth protocol", () => {
|
|
56
|
+
const sm = (0, state_inference_1.inferStateMachine)(AUTH_CLEAN);
|
|
57
|
+
const invariants = (0, protocol_invariants_1.mineInvariants)(sm);
|
|
58
|
+
(0, protocol_invariants_1.printInvariants)(invariants);
|
|
59
|
+
const precedeInv = invariants.find(i => i.type === "MUST_PRECEDE");
|
|
60
|
+
(0, vitest_1.expect)(precedeInv).toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.it)("DETECTS resource leak: structural comparison with template", () => {
|
|
63
|
+
// Template: clean state machine (3 states: entry→bridge→exit)
|
|
64
|
+
const templateSM = (0, state_inference_1.inferStateMachine)(FILE_CLEAN);
|
|
65
|
+
// Broken: open→read without close → only 2 states (entry→bridge)
|
|
66
|
+
const brokenSM = (0, state_inference_1.inferStateMachine)(FILE_BROKEN_NO_CLOSE);
|
|
67
|
+
// Template-vs-broken structural comparison
|
|
68
|
+
const violations = (0, protocol_invariants_1.detectStructuralViolations)(brokenSM, templateSM);
|
|
69
|
+
console.log(`\n Template states: ${templateSM.stateCount} (entry→bridge→exit)`);
|
|
70
|
+
console.log(` Broken states: ${brokenSM.stateCount} (entry→bridge)`);
|
|
71
|
+
(0, protocol_invariants_1.printViolations)(violations);
|
|
72
|
+
// KEY TEST: must detect the missing release
|
|
73
|
+
const hasLeak = violations.some(v => v.violationSubtype === "missing_release");
|
|
74
|
+
(0, vitest_1.expect)(hasLeak).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.it)("DETECTS auth bypass: generate_jwt without verify_password", () => {
|
|
77
|
+
const sm = (0, state_inference_1.inferStateMachine)(AUTH_CLEAN);
|
|
78
|
+
const invariants = (0, protocol_invariants_1.mineInvariants)(sm);
|
|
79
|
+
const scrambled = ["F_0005", "F_0006"]; // generate_jwt → create_session (no verify)
|
|
80
|
+
const violations = (0, protocol_invariants_1.checkInvariants)(scrambled, invariants);
|
|
81
|
+
console.log(`\n Testing: ${scrambled.join(" → ")}`);
|
|
82
|
+
(0, protocol_invariants_1.printViolations)(violations);
|
|
83
|
+
const hasAuthBypass = violations.some(v => v.invariant.type === "MUST_PRECEDE");
|
|
84
|
+
(0, vitest_1.expect)(hasAuthBypass).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
(0, vitest_1.it)("CLEAN sequences produce ZERO violations", () => {
|
|
87
|
+
// Clean file protocol: open → read → close
|
|
88
|
+
const sm = (0, state_inference_1.inferStateMachine)(FILE_CLEAN);
|
|
89
|
+
const invariants = (0, protocol_invariants_1.mineInvariants)(sm);
|
|
90
|
+
// Use one of the clean sequences (scrambled names)
|
|
91
|
+
const scrambled = ["F_0001", "F_0002", "F_0003"]; // 3-step = full lifecycle
|
|
92
|
+
const violations = (0, protocol_invariants_1.checkInvariants)(scrambled, invariants);
|
|
93
|
+
console.log(`\n Testing: ${scrambled.join(" → ")} (clean)`);
|
|
94
|
+
(0, protocol_invariants_1.printViolations)(violations);
|
|
95
|
+
// Clean sequence should have FEWER violations than broken
|
|
96
|
+
// (may still have some if the sequence doesn't match all invariants)
|
|
97
|
+
const brokenScrambled = ["F_0001", "F_0002"]; // 2-step = broken
|
|
98
|
+
const brokenViolations = (0, protocol_invariants_1.checkInvariants)(brokenScrambled, invariants);
|
|
99
|
+
(0, vitest_1.expect)(violations.length).toBeLessThan(brokenViolations.length);
|
|
100
|
+
});
|
|
101
|
+
(0, vitest_1.it)("NAME-SCRAMBLE: invariant mining produces identical results on scrambled names", () => {
|
|
102
|
+
const origInvariants = (0, protocol_invariants_1.mineInvariants)((0, state_inference_1.inferStateMachine)(FILE_CLEAN));
|
|
103
|
+
const scrambledInvariants = (0, protocol_invariants_1.mineInvariants)((0, state_inference_1.inferStateMachine)([
|
|
104
|
+
["F_001", "F_002", "F_003"],
|
|
105
|
+
["F_001", "F_004", "F_003"],
|
|
106
|
+
]));
|
|
107
|
+
(0, vitest_1.expect)(origInvariants.length).toBe(scrambledInvariants.length);
|
|
108
|
+
(0, vitest_1.expect)(origInvariants.map(i => i.type).sort())
|
|
109
|
+
.toEqual(scrambledInvariants.map(i => i.type).sort());
|
|
110
|
+
});
|
|
111
|
+
});
|