progmune-runtime 2.1.6 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -461
- package/dist/ablation-study.js +144 -0
- package/dist/ablation-study.test.js +18 -0
- package/dist/action-runtime.js +3 -1
- package/dist/active-learning.js +211 -0
- package/dist/analytics.js +139 -0
- package/dist/asset-factory.js +309 -0
- package/dist/asset-growth.js +244 -0
- package/dist/asset-promotion.js +382 -0
- package/dist/asset-quality.js +550 -0
- package/dist/audit/business-translator.js +285 -0
- package/dist/audit/cli.js +66 -0
- package/dist/audit/formatters/html.js +379 -0
- package/dist/audit/formatters/json.js +11 -0
- package/dist/audit/formatters/markdown.js +192 -0
- package/dist/audit/formatters/terminal.js +189 -0
- package/dist/audit/index.js +25 -0
- package/dist/audit/report-builder.js +318 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit.js +3 -3
- package/dist/auto-benchmark-generator.js +137 -0
- package/dist/auto-benchmark-generator.test.js +45 -0
- package/dist/auto-protocol-synthesizer.js +362 -0
- package/dist/auto-protocol-synthesizer.test.js +82 -0
- package/dist/autonomous-patch.js +175 -0
- package/dist/autonomous-patch.test.js +128 -0
- package/dist/badge/badge-server.js +98 -0
- package/dist/behavior-miner.js +442 -0
- package/dist/belief-layer.js +475 -0
- package/dist/benchmark-count.js +5 -0
- package/dist/benchmark-generator.js +211 -0
- package/dist/benchmark-harness.js +201 -0
- package/dist/benchmark-pass-rate.js +7 -0
- package/dist/benchmark-report.js +8 -3
- package/dist/benchmark-save.js +14 -1
- package/dist/bootstrap-validation.js +197 -0
- package/dist/bootstrap-validation.test.js +51 -0
- package/dist/branch-ledger.js +1 -1
- package/dist/capability-gap.js +130 -0
- package/dist/certify-html.js +351 -0
- package/dist/certify.js +326 -0
- package/dist/check.js +4 -4
- package/dist/compliance-miner.js +447 -0
- package/dist/continuous-benchmark.js +194 -0
- package/dist/continuous-benchmark.test.js +116 -0
- package/dist/corpus-stats.js +173 -0
- package/dist/counterfactual-engine.js +288 -0
- package/dist/coverage-dashboard.js +109 -0
- package/dist/coverage-system.test.js +205 -0
- package/dist/cross-repo-precision.js +352 -0
- package/dist/cve-benchmark.js +180 -0
- package/dist/cve-benchmark.test.js +28 -0
- package/dist/cve-collector.js +73 -0
- package/dist/data-quality.js +141 -0
- package/dist/decision-engine.js +388 -0
- package/dist/derive-metadata.js +250 -0
- package/dist/difficulty-active.test.js +198 -0
- package/dist/difficulty-map.js +244 -0
- package/dist/discovery-analytics.js +125 -0
- package/dist/discovery-model.js +149 -0
- package/dist/discovery-optimize.test.js +199 -0
- package/dist/discovery-trace.js +276 -0
- package/dist/discovery-trace.test.js +97 -0
- package/dist/emitter.js +83 -1
- package/dist/enterprise-dashboard.js +405 -0
- package/dist/eval-hardening.js +297 -0
- package/dist/eval-hardening.test.js +85 -0
- package/dist/evaluation-campaign.js +359 -0
- package/dist/evaluation-campaign.test.js +181 -0
- package/dist/evidence-growth.js +143 -0
- package/dist/evidence-repository.js +209 -0
- package/dist/evidence-system.js +441 -0
- package/dist/execute.js +15 -7
- package/dist/experimental/software-physics.js +291 -0
- package/dist/experimental/state-inference.js +516 -0
- package/dist/experimental/unsupervised-physics.js +230 -0
- package/dist/extract-ir-python.js +54 -7
- package/dist/extract-ir.js +376 -12
- package/dist/failure-collector.js +2 -2
- package/dist/failure-corpus.js +322 -9
- package/dist/feedback.js +16 -5
- package/dist/feedback.test.js +49 -0
- package/dist/file-lock.js +1 -1
- package/dist/flywheel-batch.js +292 -0
- package/dist/frameworks/express-cli.js +237 -0
- package/dist/frameworks/express-detector.js +445 -0
- package/dist/frameworks/express-detector.test.js +206 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/nestjs-detector.js +302 -0
- package/dist/frameworks/trpc-detector.js +161 -0
- package/dist/frameworks/version-awareness.js +179 -0
- package/dist/function-synonyms.js +164 -0
- package/dist/function-synonyms.test.js +68 -0
- package/dist/generalization.test.js +352 -0
- package/dist/goal-annotator.js +113 -0
- package/dist/goal-planner.js +563 -0
- package/dist/gold-cve.js +164 -0
- package/dist/gold-cve.test.js +104 -0
- package/dist/gold-quality.js +206 -0
- package/dist/gold-tiers.js +241 -0
- package/dist/governance-dashboard.js +327 -0
- package/dist/graph-viz.js +240 -0
- package/dist/guided-frontier.js +195 -0
- package/dist/hierarchical-planner.js +148 -0
- package/dist/identifier-parser.js +260 -0
- package/dist/immune-metrics.js +93 -0
- package/dist/immune-receiver.js +158 -0
- package/dist/immune-reporter.js +1 -1
- package/dist/improvement-orchestrator.js +206 -0
- package/dist/inject-p0-vocabulary.js +300 -0
- package/dist/intent-parser.js +218 -0
- package/dist/invariant-algebra.js +476 -0
- package/dist/invariant-calculus.js +533 -0
- package/dist/ir-utils.js +70 -0
- package/dist/ir-utils.test.js +50 -0
- package/dist/knowledge-api.js +312 -0
- package/dist/knowledge-evolution.js +452 -0
- package/dist/knowledge-explorer.js +506 -0
- package/dist/knowledge-flywheel.js +274 -0
- package/dist/knowledge-governance.js +338 -0
- package/dist/knowledge-governance.test.js +150 -0
- package/dist/knowledge-graph.js +181 -0
- package/dist/knowledge-guided-synth.js +246 -0
- package/dist/knowledge-loop.test.js +77 -0
- package/dist/knowledge-object.js +316 -0
- package/dist/knowledge-package.js +98 -0
- package/dist/kpi-dashboard.js +561 -0
- package/dist/l3-cross-function.js +280 -0
- package/dist/learning-ranker.js +148 -0
- package/dist/learning-ranker.test.js +291 -0
- package/dist/ledger/accountability.js +322 -0
- package/dist/ledger/chain-builder.js +185 -0
- package/dist/ledger/cli.js +222 -0
- package/dist/ledger/index.js +13 -0
- package/dist/ledger/signatures.js +193 -0
- package/dist/ledger/types.js +9 -0
- package/dist/llm.js +74 -3
- package/dist/load-benchmarks.js +8 -3
- package/dist/logger.js +66 -0
- package/dist/logger.test.js +37 -0
- package/dist/logistic-reward.js +339 -0
- package/dist/logistic-reward.test.js +180 -0
- package/dist/macro-graph.js +193 -0
- package/dist/macro-repair.js +183 -0
- package/dist/mcp-server.mjs +1202 -483
- package/dist/memory-layer.js +42 -5
- package/dist/multi-repo-precision.js +422 -0
- package/dist/name-free-protocol.js +425 -0
- package/dist/name-free-protocol.test.js +170 -0
- package/dist/name-scrambling.js +138 -0
- package/dist/name-scrambling.test.js +16 -0
- package/dist/p3-observability.test.js +281 -0
- package/dist/p5-orchestrator.test.js +225 -0
- package/dist/pairwise-preference.js +294 -0
- package/dist/pairwise-preference.test.js +140 -0
- package/dist/planner-constraints.js +104 -0
- package/dist/planner-prompts.js +155 -0
- package/dist/planner-telemetry.js +415 -0
- package/dist/planner-trace.js +214 -0
- package/dist/planner.js +162 -167
- package/dist/plsb/artifact.js +116 -0
- package/dist/plsb/cli.js +71 -0
- package/dist/plsb/index.js +19 -0
- package/dist/plsb/leaderboard.js +249 -0
- package/dist/plsb/report-md.js +156 -0
- package/dist/plsb/schema.js +179 -0
- package/dist/plsb-benchmark.js +284 -0
- package/dist/plsb-benchmark.test.js +119 -0
- package/dist/policy/cli.js +134 -0
- package/dist/policy/engine.js +333 -0
- package/dist/policy/index.js +12 -0
- package/dist/policy/types.js +59 -0
- package/dist/policy-miner.js +505 -0
- package/dist/precision-analyze.js +229 -0
- package/dist/precision-benchmark.js +147 -0
- package/dist/precision-label-c.js +134 -0
- package/dist/precision-label.js +193 -0
- package/dist/precision-report-c.js +149 -0
- package/dist/precision-report.js +246 -0
- package/dist/progmune-status.js +108 -0
- package/dist/proof-engine.js +479 -0
- package/dist/proof-provenance.js +315 -0
- package/dist/protocol-coverage.js +294 -0
- package/dist/protocol-detector.js +1189 -0
- package/dist/protocol-embedding-expanded.js +297 -0
- package/dist/protocol-embedding-expanded.test.js +97 -0
- package/dist/protocol-embedding.js +195 -0
- package/dist/protocol-embedding.test.js +82 -0
- package/dist/protocol-extractor-v2.js +354 -0
- package/dist/protocol-extractor-v2.test.js +140 -0
- package/dist/protocol-extractor.js +310 -0
- package/dist/protocol-extractor.test.js +113 -0
- package/dist/protocol-foundation.js +322 -0
- package/dist/protocol-foundation.test.js +163 -0
- package/dist/protocol-frontier.js +243 -0
- package/dist/protocol-frontier.test.js +92 -0
- package/dist/protocol-gap-analyzer.js +228 -0
- package/dist/protocol-gap-analyzer.test.js +49 -0
- package/dist/protocol-invariants.js +276 -0
- package/dist/protocol-invariants.test.js +111 -0
- package/dist/protocol-knowledge.js +464 -0
- package/dist/protocol-miner.js +343 -0
- package/dist/protocol-mining.js +207 -0
- package/dist/protocol-mining.test.js +37 -0
- package/dist/protocol-registry.js +1 -1
- package/dist/protocol-security-benchmark.js +222 -0
- package/dist/protocol-vulnerability.js +257 -0
- package/dist/protocol-vulnerability.test.js +60 -0
- package/dist/python-benchmark.js +120 -0
- package/dist/python-emitter.js +163 -45
- package/dist/python-protocol-extractor.js +187 -0
- package/dist/python-protocol-extractor.test.js +116 -0
- package/dist/realworld-benchmark.js +646 -0
- package/dist/realworld-benchmark.test.js +36 -0
- package/dist/repair-arch.test.js +411 -0
- package/dist/repair-evolution.test.js +454 -0
- package/dist/repair-executor.js +719 -0
- package/dist/repair-proposal.js +4 -4
- package/dist/repair-ranker.js +141 -0
- package/dist/repair-strategies.js +419 -0
- package/dist/repair-taxonomy.js +234 -0
- package/dist/repair-types.js +12 -0
- package/dist/repo-evaluator.js +250 -0
- package/dist/repo-evaluator.test.js +128 -0
- package/dist/resource-abstraction.js +242 -0
- package/dist/resource-detector.js +211 -0
- package/dist/result.test.js +43 -0
- package/dist/reward-system.js +411 -0
- package/dist/reward-system.test.js +175 -0
- package/dist/risk-model.js +215 -0
- package/dist/rule-miner.js +234 -7
- package/dist/rule-specificity.js +254 -0
- package/dist/runtime-types.js +27 -0
- package/dist/scaffold.js +208 -0
- package/dist/scale-collector.test.js +101 -0
- package/dist/scale-trajectory-collector.js +128 -0
- package/dist/sdk.js +250 -0
- package/dist/search-planner.js +4 -41
- package/dist/semantic-snapshot.js +1 -1
- package/dist/semantic-topology.js +121 -0
- package/dist/semantic-trace.js +310 -317
- package/dist/sequence-extractor.js +343 -0
- package/dist/skill-library.js +245 -0
- package/dist/skill-planner.test.js +189 -0
- package/dist/software-physics.js +291 -0
- package/dist/software-physics.test.js +81 -0
- package/dist/ssg-precision.js +478 -0
- package/dist/ssg-validator.js +71 -21
- package/dist/state-inference-doubleblind.test.js +160 -0
- package/dist/state-inference.js +516 -0
- package/dist/state-inference.test.js +115 -0
- package/dist/state-machine-fingerprint.js +345 -0
- package/dist/state-machine-fingerprint.test.js +120 -0
- package/dist/state-miner.js +386 -0
- package/dist/state-name-inference.js +213 -0
- package/dist/state-name-inference.test.js +69 -0
- package/dist/strategy-planner.js +262 -96
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +721 -0
- package/package.json +73 -6
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 11: Policy Engine CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx ts-node src/policy/cli.ts check <file.ts>
|
|
7
|
+
* npx ts-node src/policy/cli.ts check <file.ts> --author alice@example.com
|
|
8
|
+
* npx ts-node src/policy/cli.ts check <file.ts> --json
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
const certify_1 = require("../certify");
|
|
12
|
+
const accountability_1 = require("../ledger/accountability");
|
|
13
|
+
const engine_1 = require("./engine");
|
|
14
|
+
const C = {
|
|
15
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
16
|
+
green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m",
|
|
17
|
+
};
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
if (args.includes("--help") || args.includes("-h") || args.length === 0) {
|
|
20
|
+
console.log(`
|
|
21
|
+
Progmune Policy Engine — Deploy Gate
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
npx ts-node src/policy/cli.ts check <file.ts> [options]
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--author <email> Human who initiated generation
|
|
28
|
+
--reviewer <email> Human reviewer
|
|
29
|
+
--policy <path> Policy config file (default: .progmune-policy.json)
|
|
30
|
+
--json Output as JSON
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
npx ts-node src/policy/cli.ts check src/server.ts
|
|
34
|
+
npx ts-node src/policy/cli.ts check src/server.ts --author alice@example.com
|
|
35
|
+
npx ts-node src/policy/cli.ts check src/server.ts --json
|
|
36
|
+
`);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
const cmd = args[0];
|
|
40
|
+
const filePath = args[1];
|
|
41
|
+
function parseHumanOpt(flag) {
|
|
42
|
+
const idx = args.indexOf(flag);
|
|
43
|
+
if (idx < 0 || !args[idx + 1] || args[idx + 1].startsWith("--"))
|
|
44
|
+
return undefined;
|
|
45
|
+
const email = args[idx + 1];
|
|
46
|
+
return { id: email, name: email.split("@")[0], role: flag.slice(2) };
|
|
47
|
+
}
|
|
48
|
+
const useJson = args.includes("--json");
|
|
49
|
+
const author = parseHumanOpt("--author");
|
|
50
|
+
const reviewer = parseHumanOpt("--reviewer");
|
|
51
|
+
const policyIdx = args.indexOf("--policy");
|
|
52
|
+
const policyPath = policyIdx >= 0 ? args[policyIdx + 1] : undefined;
|
|
53
|
+
if (cmd !== "check" || !filePath) {
|
|
54
|
+
console.error("❌ Usage: npx ts-node src/policy/cli.ts check <file.ts>");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
// 1. Certify the file
|
|
58
|
+
const cert = (0, certify_1.certify)(filePath);
|
|
59
|
+
// 2. Build accountability chain
|
|
60
|
+
let acct;
|
|
61
|
+
try {
|
|
62
|
+
acct = (0, accountability_1.buildAccountabilityChain)(cert.sessionId, {
|
|
63
|
+
author,
|
|
64
|
+
reviewers: reviewer ? [reviewer] : undefined,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Accountability unavailable — policy will flag human_review violations
|
|
69
|
+
}
|
|
70
|
+
// 3. Load policy (from project config or defaults)
|
|
71
|
+
const projectDir = process.env.PROGMUNE_PROJECT_DIR || process.cwd();
|
|
72
|
+
const { rules, source } = (0, engine_1.loadPolicyConfig)(projectDir, policyPath);
|
|
73
|
+
// 4. Evaluate policy
|
|
74
|
+
const ctx = {
|
|
75
|
+
certificate: {
|
|
76
|
+
validated: cert.validated,
|
|
77
|
+
confidence: cert.confidence,
|
|
78
|
+
provenanceIntact: cert.provenanceIntact,
|
|
79
|
+
fingerprint: cert.fingerprint,
|
|
80
|
+
violations: cert.violations,
|
|
81
|
+
plsbCoverage: cert.plsbCoverage,
|
|
82
|
+
plsbRecall: cert.plsbRecall,
|
|
83
|
+
degraded: cert.degraded,
|
|
84
|
+
sessionId: cert.sessionId,
|
|
85
|
+
file: cert.file,
|
|
86
|
+
},
|
|
87
|
+
accountability: acct ? {
|
|
88
|
+
humanEvents: acct.humanEvents,
|
|
89
|
+
aiEvents: acct.aiEvents,
|
|
90
|
+
automatedEvents: acct.automatedEvents,
|
|
91
|
+
custodyGap: acct.custodyGap,
|
|
92
|
+
} : undefined,
|
|
93
|
+
};
|
|
94
|
+
const result = (0, engine_1.evaluatePolicy)(ctx, rules);
|
|
95
|
+
if (useJson) {
|
|
96
|
+
console.log(JSON.stringify({ ...result, policySource: source }, null, 2));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(formatPolicyResult(result, cert.file, source));
|
|
100
|
+
}
|
|
101
|
+
process.exit(result.passed ? 0 : 1);
|
|
102
|
+
// ── Formatter ──
|
|
103
|
+
function formatPolicyResult(result, file, policySource) {
|
|
104
|
+
const lines = [];
|
|
105
|
+
const verdictColor = result.verdict === "ALLOW" ? C.green
|
|
106
|
+
: result.verdict === "WARN" ? C.yellow : C.red;
|
|
107
|
+
const box = result.verdict === "ALLOW" ? "✅"
|
|
108
|
+
: result.verdict === "WARN" ? "⚠️ " : "❌";
|
|
109
|
+
lines.push("");
|
|
110
|
+
lines.push(`${C.bold}${C.cyan}╔════════════════════════════════════════════════════╗${C.reset}`);
|
|
111
|
+
lines.push(`${C.bold}${C.cyan}║${C.reset} ${C.bold}Policy Engine — Deploy Gate${C.reset} ${C.bold}${C.cyan}║${C.reset}`);
|
|
112
|
+
lines.push(`${C.bold}${C.cyan}╚════════════════════════════════════════════════════╝${C.reset}`);
|
|
113
|
+
lines.push("");
|
|
114
|
+
lines.push(` File: ${file}`);
|
|
115
|
+
lines.push(` Policy: ${C.dim}${policySource || "built-in defaults"}${C.reset}`);
|
|
116
|
+
lines.push(` Verdict: ${verdictColor}${C.bold}${box} ${result.verdict}${C.reset}`);
|
|
117
|
+
lines.push(` Rules: ${C.green}${result.passed_rules} passed${C.reset}, ${result.failed_rules > 0 ? C.red : ""}${result.failed_rules} failed${C.reset} / ${result.rules} total`);
|
|
118
|
+
lines.push("");
|
|
119
|
+
if (result.violations.length > 0) {
|
|
120
|
+
lines.push(` ${C.bold}Violations:${C.reset}`);
|
|
121
|
+
for (const v of result.violations) {
|
|
122
|
+
const sev = v.rule.severity === "block" ? `${C.red}BLOCK${C.reset}` : `${C.yellow}WARN${C.reset}`;
|
|
123
|
+
const ruleName = v.rule.type;
|
|
124
|
+
lines.push(` ${sev} ${ruleName.padEnd(16)} ${v.actual} → expected ${v.expected}`);
|
|
125
|
+
if (v.detail) {
|
|
126
|
+
lines.push(` ${C.dim}${v.detail.slice(0, 90)}${C.reset}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
lines.push("");
|
|
130
|
+
}
|
|
131
|
+
lines.push(` ${result.summary}`);
|
|
132
|
+
lines.push("");
|
|
133
|
+
return lines.join("\n");
|
|
134
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 11: Policy Engine
|
|
4
|
+
*
|
|
5
|
+
* Evaluates policy rules against a certified file and its
|
|
6
|
+
* supporting data (provenance chain, accountability chain, PLSB).
|
|
7
|
+
* Returns ALLOW, WARN, or BLOCK.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.loadPolicyConfig = loadPolicyConfig;
|
|
44
|
+
exports.evaluatePolicy = evaluatePolicy;
|
|
45
|
+
exports.loadEnterprisePolicyConfig = loadEnterprisePolicyConfig;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const types_1 = require("./types");
|
|
49
|
+
function confidenceToNumber(c) {
|
|
50
|
+
if (c === "high")
|
|
51
|
+
return 2;
|
|
52
|
+
if (c === "medium")
|
|
53
|
+
return 1;
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
function parsePlsbCovered(coverage) {
|
|
57
|
+
const m = coverage.match(/^(\d+)\//);
|
|
58
|
+
return m ? parseInt(m[1], 10) : 0;
|
|
59
|
+
}
|
|
60
|
+
/** Load policy from project config file, merged with defaults */
|
|
61
|
+
function loadPolicyConfig(projectPath, configPath) {
|
|
62
|
+
const cfgFile = configPath
|
|
63
|
+
? path.resolve(configPath)
|
|
64
|
+
: path.join(projectPath, ".progmune-policy.json");
|
|
65
|
+
if (!fs.existsSync(cfgFile)) {
|
|
66
|
+
return { rules: [...types_1.DEFAULT_POLICY], source: "built-in defaults" };
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const cfg = JSON.parse(fs.readFileSync(cfgFile, "utf-8"));
|
|
70
|
+
const inherit = cfg.inherit !== false; // default: inherit
|
|
71
|
+
if (!inherit) {
|
|
72
|
+
return { rules: cfg.rules || [...types_1.DEFAULT_POLICY], source: cfgFile };
|
|
73
|
+
}
|
|
74
|
+
// Merge: project rules override defaults by type
|
|
75
|
+
const merged = [...types_1.DEFAULT_POLICY];
|
|
76
|
+
for (const pr of cfg.rules || []) {
|
|
77
|
+
const idx = merged.findIndex(dr => dr.type === pr.type);
|
|
78
|
+
if (idx >= 0) {
|
|
79
|
+
// Override existing rule
|
|
80
|
+
merged[idx] = {
|
|
81
|
+
type: merged[idx].type,
|
|
82
|
+
severity: pr.severity || merged[idx].severity,
|
|
83
|
+
description: pr.description || merged[idx].description,
|
|
84
|
+
threshold: pr.threshold ?? merged[idx].threshold,
|
|
85
|
+
require: pr.require ?? merged[idx].require,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// Add new rule
|
|
90
|
+
merged.push(pr);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { rules: merged, source: cfgFile };
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
console.error(`⚠️ Failed to load policy config: ${e.message}. Using defaults.`);
|
|
97
|
+
return { rules: [...types_1.DEFAULT_POLICY], source: "built-in defaults (config error)" };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function evaluatePolicy(ctx, rules) {
|
|
101
|
+
const activeRules = rules || types_1.DEFAULT_POLICY;
|
|
102
|
+
const violations = [];
|
|
103
|
+
for (const rule of activeRules) {
|
|
104
|
+
switch (rule.type) {
|
|
105
|
+
// ── Confidence ──
|
|
106
|
+
case "confidence": {
|
|
107
|
+
const minLevel = rule.threshold ?? 1; // default: medium
|
|
108
|
+
const actual = confidenceToNumber(ctx.certificate.confidence);
|
|
109
|
+
if (actual < minLevel || ctx.certificate.degraded) {
|
|
110
|
+
violations.push({
|
|
111
|
+
rule,
|
|
112
|
+
actual: ctx.certificate.degraded ? "degraded" : ctx.certificate.confidence,
|
|
113
|
+
expected: `confidence >= ${minLevel === 2 ? "high" : "medium"}`,
|
|
114
|
+
detail: ctx.certificate.degraded
|
|
115
|
+
? "This file was generated via a fallback/degraded path — reliability is reduced."
|
|
116
|
+
: `Confidence is ${ctx.certificate.confidence}. Recommend re-generating with full validation.`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
// ── Provenance ──
|
|
122
|
+
case "provenance": {
|
|
123
|
+
if (!ctx.certificate.provenanceIntact) {
|
|
124
|
+
violations.push({
|
|
125
|
+
rule,
|
|
126
|
+
actual: "broken",
|
|
127
|
+
expected: "intact",
|
|
128
|
+
detail: `Provenance chain for session ${ctx.certificate.sessionId} is broken — the ledger fingerprint has changed since generation.`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
// ── PLSB Coverage ──
|
|
134
|
+
case "plsb_coverage": {
|
|
135
|
+
const minCovered = rule.threshold ?? 5;
|
|
136
|
+
const covered = parsePlsbCovered(ctx.certificate.plsbCoverage);
|
|
137
|
+
if (covered < minCovered) {
|
|
138
|
+
violations.push({
|
|
139
|
+
rule,
|
|
140
|
+
actual: `${covered} categories covered`,
|
|
141
|
+
expected: `>= ${minCovered} categories`,
|
|
142
|
+
detail: `PLSB covers ${ctx.certificate.plsbCoverage} categories. Add protocol rules for uncovered weakness types.`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
// ── Human Review ──
|
|
148
|
+
case "human_review": {
|
|
149
|
+
const minHumans = rule.require ?? 1;
|
|
150
|
+
const humans = ctx.accountability?.humanEvents ?? 0;
|
|
151
|
+
if (humans < minHumans) {
|
|
152
|
+
violations.push({
|
|
153
|
+
rule,
|
|
154
|
+
actual: `${humans} human(s) in chain`,
|
|
155
|
+
expected: `>= ${minHumans} human reviewer(s)`,
|
|
156
|
+
detail: ctx.accountability?.custodyGap
|
|
157
|
+
? "Custody gaps detected — actor identities could not be verified."
|
|
158
|
+
: "No human reviewer found in the accountability chain. Use --author, --reviewer flags.",
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
// ── Fingerprint ──
|
|
164
|
+
case "fingerprint": {
|
|
165
|
+
if (!ctx.certificate.fingerprint || ctx.certificate.fingerprint.includes("pending")) {
|
|
166
|
+
violations.push({
|
|
167
|
+
rule,
|
|
168
|
+
actual: "no fingerprint",
|
|
169
|
+
expected: "fingerprint registered",
|
|
170
|
+
detail: "Run 'npm run check' to register missing fingerprints.",
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
// ── Risk-Based (Protocol-agnostic) ──
|
|
176
|
+
case "risk": {
|
|
177
|
+
const minSeverity = rule.threshold ?? 2;
|
|
178
|
+
const minConfidence = rule.require ?? 70;
|
|
179
|
+
try {
|
|
180
|
+
const { assessRisk } = require("../risk-model");
|
|
181
|
+
// Extract call sequence from file (best-effort)
|
|
182
|
+
const calls = ctx.certificate.validated ? [] : ["SSL_CTX_new", "SSL_connect"]; // fallback
|
|
183
|
+
const risk = assessRisk(calls.length > 0 ? calls : ["init", "connect"]);
|
|
184
|
+
const criticalOrHigh = risk.patterns.filter((p) => {
|
|
185
|
+
const sevOrder = ["Low", "Medium", "High", "Critical"];
|
|
186
|
+
return sevOrder.indexOf(p.severity) >= minSeverity && p.confidence >= minConfidence;
|
|
187
|
+
});
|
|
188
|
+
if (criticalOrHigh.length > 0) {
|
|
189
|
+
violations.push({
|
|
190
|
+
rule,
|
|
191
|
+
actual: `${criticalOrHigh.length} risk pattern(s) ≥ severity threshold`,
|
|
192
|
+
expected: `0 patterns at this severity+confidence level`,
|
|
193
|
+
detail: criticalOrHigh.map((p) => `${p.patternName} (${p.severity}, ${p.confidence}%): ${p.detail}`).join("; "),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch { /* risk model unavailable */ }
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
// ── Knowledge Base Coverage ──
|
|
201
|
+
case "kb_coverage": {
|
|
202
|
+
const minStable = rule.threshold ?? 3;
|
|
203
|
+
let stableCount = 0;
|
|
204
|
+
try {
|
|
205
|
+
const { buildKnowledgeBase } = require("../protocol-knowledge");
|
|
206
|
+
const kb = buildKnowledgeBase();
|
|
207
|
+
stableCount = kb.units.filter((u) => u.maturity === "stable").length;
|
|
208
|
+
}
|
|
209
|
+
catch { /* KB unavailable */ }
|
|
210
|
+
if (stableCount < minStable) {
|
|
211
|
+
violations.push({
|
|
212
|
+
rule,
|
|
213
|
+
actual: `${stableCount} stable assets`,
|
|
214
|
+
expected: `>= ${minStable} stable assets`,
|
|
215
|
+
detail: `The Knowledge Base has ${stableCount} stable protocol assets. Need at least ${minStable} for production governance. Run 'npm run status' to see coverage.`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
// ── Violations ──
|
|
221
|
+
case "violations": {
|
|
222
|
+
const maxViolations = rule.threshold ?? 0;
|
|
223
|
+
if (ctx.certificate.violations > maxViolations) {
|
|
224
|
+
violations.push({
|
|
225
|
+
rule,
|
|
226
|
+
actual: `${ctx.certificate.violations} SSG violation(s)`,
|
|
227
|
+
expected: `<= ${maxViolations}`,
|
|
228
|
+
detail: `Ledger consistency check found ${ctx.certificate.violations} violation(s). Run 'progmune_repair' to fix.`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// ── Compute verdict ──
|
|
236
|
+
const blockViolations = violations.filter((v) => v.rule.severity === "block");
|
|
237
|
+
const warnViolations = violations.filter((v) => v.rule.severity === "warn");
|
|
238
|
+
let verdict;
|
|
239
|
+
if (blockViolations.length > 0) {
|
|
240
|
+
verdict = "BLOCK";
|
|
241
|
+
}
|
|
242
|
+
else if (warnViolations.length > 0) {
|
|
243
|
+
verdict = "WARN";
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
verdict = "ALLOW";
|
|
247
|
+
}
|
|
248
|
+
const passed = activeRules.length - violations.length;
|
|
249
|
+
let summary;
|
|
250
|
+
if (verdict === "ALLOW") {
|
|
251
|
+
summary = `✅ ALLOW — all ${activeRules.length} policy rules passed. Safe to deploy.`;
|
|
252
|
+
}
|
|
253
|
+
else if (verdict === "WARN") {
|
|
254
|
+
summary = `⚠️ WARN — ${passed}/${activeRules.length} rules passed, ${warnViolations.length} warning(s). Review before deploy.`;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
summary = `❌ BLOCK — ${blockViolations.length} blocking violation(s). Deployment is blocked until these are resolved.`;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
passed: verdict !== "BLOCK",
|
|
261
|
+
verdict,
|
|
262
|
+
rules: activeRules.length,
|
|
263
|
+
passed_rules: passed,
|
|
264
|
+
failed_rules: violations.length,
|
|
265
|
+
violations,
|
|
266
|
+
summary,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Load policy configuration from a project's .progmune-policy.json.
|
|
271
|
+
* Auto-detects enterprise format (has `enterprise` array with `id` fields)
|
|
272
|
+
* vs legacy format (has `rules` array with `type` fields).
|
|
273
|
+
*
|
|
274
|
+
* For legacy format: returns isEnterprise=false, rules=[]
|
|
275
|
+
* For enterprise format: returns parsed EnterpriseRule[] with policy_ref
|
|
276
|
+
*/
|
|
277
|
+
function loadEnterprisePolicyConfig(projectPath, configPath) {
|
|
278
|
+
const cfgFile = configPath
|
|
279
|
+
? path.resolve(configPath)
|
|
280
|
+
: path.join(projectPath, ".progmune-policy.json");
|
|
281
|
+
const emptyResult = {
|
|
282
|
+
policy: { rules: [...types_1.DEFAULT_POLICY] },
|
|
283
|
+
source: "built-in defaults",
|
|
284
|
+
rules: [],
|
|
285
|
+
isEnterprise: false,
|
|
286
|
+
};
|
|
287
|
+
if (!fs.existsSync(cfgFile)) {
|
|
288
|
+
return emptyResult;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const raw = JSON.parse(fs.readFileSync(cfgFile, "utf-8"));
|
|
292
|
+
// Auto-detect: enterprise format has `enterprise` array with `id` fields
|
|
293
|
+
if (raw.enterprise && Array.isArray(raw.enterprise) && raw.enterprise.length > 0) {
|
|
294
|
+
const first = raw.enterprise[0];
|
|
295
|
+
if (first.id && first.policy_ref) {
|
|
296
|
+
const policy = {
|
|
297
|
+
version: raw.version || "1.0",
|
|
298
|
+
name: raw.name,
|
|
299
|
+
description: raw.description,
|
|
300
|
+
rules: raw.rules || [...types_1.DEFAULT_POLICY],
|
|
301
|
+
inherit: raw.inherit,
|
|
302
|
+
dimensions: raw.dimensions,
|
|
303
|
+
enterprise: raw.enterprise,
|
|
304
|
+
};
|
|
305
|
+
return {
|
|
306
|
+
policy,
|
|
307
|
+
source: cfgFile,
|
|
308
|
+
rules: raw.enterprise,
|
|
309
|
+
isEnterprise: true,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Fallback: treat as legacy format
|
|
314
|
+
const policy = {
|
|
315
|
+
version: raw.version,
|
|
316
|
+
name: raw.name,
|
|
317
|
+
description: raw.description,
|
|
318
|
+
rules: raw.rules || [...types_1.DEFAULT_POLICY],
|
|
319
|
+
inherit: raw.inherit,
|
|
320
|
+
dimensions: raw.dimensions,
|
|
321
|
+
};
|
|
322
|
+
return {
|
|
323
|
+
policy,
|
|
324
|
+
source: cfgFile,
|
|
325
|
+
rules: [],
|
|
326
|
+
isEnterprise: false,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
catch (e) {
|
|
330
|
+
console.error(`⚠️ Failed to load enterprise policy config: ${e.message}. Using defaults.`);
|
|
331
|
+
return emptyResult;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 11: Policy Engine Module
|
|
4
|
+
*
|
|
5
|
+
* Public API for deployment gating and policy enforcement.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.DEFAULT_POLICY = exports.evaluatePolicy = void 0;
|
|
9
|
+
var engine_1 = require("./engine");
|
|
10
|
+
Object.defineProperty(exports, "evaluatePolicy", { enumerable: true, get: function () { return engine_1.evaluatePolicy; } });
|
|
11
|
+
var types_1 = require("./types");
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_POLICY", { enumerable: true, get: function () { return types_1.DEFAULT_POLICY; } });
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 11: Policy Engine Types
|
|
4
|
+
*
|
|
5
|
+
* Declarative rules that gate AI-generated code from deployment.
|
|
6
|
+
* Transforms governance from "report" to "enforce".
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DEFAULT_POLICY = void 0;
|
|
10
|
+
/** Default policy — can be overridden by .progmune-policy.json */
|
|
11
|
+
exports.DEFAULT_POLICY = [
|
|
12
|
+
{
|
|
13
|
+
type: "confidence",
|
|
14
|
+
severity: "block",
|
|
15
|
+
description: "Certificate confidence must be medium or higher",
|
|
16
|
+
threshold: 1, // 0=low, 1=medium, 2=high
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
type: "provenance",
|
|
20
|
+
severity: "block",
|
|
21
|
+
description: "Provenance chain must be intact",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: "plsb_coverage",
|
|
25
|
+
severity: "warn",
|
|
26
|
+
description: "PLSB must cover at least 5/13 categories",
|
|
27
|
+
threshold: 5,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: "human_review",
|
|
31
|
+
severity: "block",
|
|
32
|
+
description: "At least 1 human must be in the accountability chain",
|
|
33
|
+
require: 1,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
type: "fingerprint",
|
|
37
|
+
severity: "warn",
|
|
38
|
+
description: "Fingerprint must exist and be verified",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: "violations",
|
|
42
|
+
severity: "block",
|
|
43
|
+
description: "No SSG ledger violations allowed",
|
|
44
|
+
threshold: 0,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: "kb_coverage",
|
|
48
|
+
severity: "warn",
|
|
49
|
+
description: "Knowledge Base must have at least 3 stable protocol assets",
|
|
50
|
+
threshold: 3,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: "risk",
|
|
54
|
+
severity: "block",
|
|
55
|
+
description: "Block Critical risks with ≥90% confidence. Warn on High risks with ≥70% confidence.",
|
|
56
|
+
threshold: 2, // severity: 0=Low, 1=Medium, 2=High, 3=Critical → block if >= 2 with enough confidence
|
|
57
|
+
require: 70, // minimum confidence %
|
|
58
|
+
},
|
|
59
|
+
];
|