@veraxhq/verax 0.2.1 → 0.4.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 +10 -6
- package/bin/verax.js +11 -11
- package/package.json +29 -8
- package/src/cli/commands/baseline.js +103 -0
- package/src/cli/commands/default.js +51 -6
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +246 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +4 -2
- package/src/cli/commands/release-check.js +215 -0
- package/src/cli/commands/run.js +45 -6
- package/src/cli/commands/security-check.js +212 -0
- package/src/cli/commands/truth.js +113 -0
- package/src/cli/entry.js +30 -20
- package/src/cli/util/angular-component-extractor.js +179 -0
- package/src/cli/util/angular-navigation-detector.js +141 -0
- package/src/cli/util/angular-network-detector.js +161 -0
- package/src/cli/util/angular-state-detector.js +162 -0
- package/src/cli/util/ast-interactive-detector.js +544 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/atomic-write.js +12 -1
- package/src/cli/util/bootstrap-guard.js +86 -0
- package/src/cli/util/console-reporter.js +72 -0
- package/src/cli/util/detection-engine.js +105 -41
- package/src/cli/util/determinism-runner.js +124 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +151 -5
- package/src/cli/util/findings-writer.js +3 -0
- package/src/cli/util/framework-detector.js +572 -0
- package/src/cli/util/idgen.js +1 -1
- package/src/cli/util/interaction-planner.js +529 -0
- package/src/cli/util/learn-writer.js +2 -0
- package/src/cli/util/ledger-writer.js +110 -0
- package/src/cli/util/monorepo-resolver.js +162 -0
- package/src/cli/util/observation-engine.js +127 -278
- package/src/cli/util/observe-writer.js +2 -0
- package/src/cli/util/project-discovery.js +284 -0
- package/src/cli/util/project-writer.js +2 -0
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +2 -0
- package/src/cli/util/svelte-navigation-detector.js +163 -0
- package/src/cli/util/svelte-network-detector.js +80 -0
- package/src/cli/util/svelte-sfc-extractor.js +146 -0
- package/src/cli/util/svelte-state-detector.js +242 -0
- package/src/cli/util/trust-activation-integration.js +496 -0
- package/src/cli/util/trust-activation-wrapper.js +85 -0
- package/src/cli/util/trust-integration-hooks.js +164 -0
- package/src/cli/util/types.js +153 -0
- package/src/cli/util/url-validation.js +40 -0
- package/src/cli/util/vue-navigation-detector.js +178 -0
- package/src/cli/util/vue-sfc-extractor.js +161 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- package/src/types/fs-augment.d.ts +23 -0
- package/src/types/global.d.ts +137 -0
- package/src/types/internal-types.d.ts +35 -0
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +139 -0
- package/src/verax/core/artifacts/verifier.js +990 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +233 -0
- package/src/verax/core/capabilities/gates.js +505 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +144 -0
- package/src/verax/core/confidence/confidence-invariants.js +234 -0
- package/src/verax/core/confidence/confidence-report-writer.js +112 -0
- package/src/verax/core/confidence/confidence-weights.js +44 -0
- package/src/verax/core/confidence/confidence.defaults.js +65 -0
- package/src/verax/core/confidence/confidence.loader.js +80 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +489 -0
- package/src/verax/core/confidence-engine.js +625 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +186 -0
- package/src/verax/core/contracts/validators.js +456 -0
- package/src/verax/core/decisions/decision.trace.js +278 -0
- package/src/verax/core/determinism/contract-writer.js +89 -0
- package/src/verax/core/determinism/contract.js +139 -0
- package/src/verax/core/determinism/diff.js +405 -0
- package/src/verax/core/determinism/engine.js +222 -0
- package/src/verax/core/determinism/finding-identity.js +149 -0
- package/src/verax/core/determinism/normalize.js +466 -0
- package/src/verax/core/determinism/report-writer.js +93 -0
- package/src/verax/core/determinism/run-fingerprint.js +123 -0
- package/src/verax/core/dynamic-route-intelligence.js +529 -0
- package/src/verax/core/evidence/evidence-capture-service.js +308 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +166 -0
- package/src/verax/core/evidence-builder.js +487 -0
- package/src/verax/core/execution-mode-context.js +77 -0
- package/src/verax/core/execution-mode-detector.js +192 -0
- package/src/verax/core/failures/exit-codes.js +88 -0
- package/src/verax/core/failures/failure-summary.js +76 -0
- package/src/verax/core/failures/failure.factory.js +225 -0
- package/src/verax/core/failures/failure.ledger.js +133 -0
- package/src/verax/core/failures/failure.types.js +196 -0
- package/src/verax/core/failures/index.js +10 -0
- package/src/verax/core/ga/ga-report-writer.js +43 -0
- package/src/verax/core/ga/ga.artifact.js +49 -0
- package/src/verax/core/ga/ga.contract.js +435 -0
- package/src/verax/core/ga/ga.enforcer.js +87 -0
- package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
- package/src/verax/core/guardrails/policy.defaults.js +210 -0
- package/src/verax/core/guardrails/policy.loader.js +84 -0
- package/src/verax/core/guardrails/policy.schema.js +110 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
- package/src/verax/core/guardrails-engine.js +505 -0
- package/src/verax/core/incremental-store.js +1 -0
- package/src/verax/core/integrity/budget.js +138 -0
- package/src/verax/core/integrity/determinism.js +342 -0
- package/src/verax/core/integrity/integrity.js +208 -0
- package/src/verax/core/integrity/poisoning.js +108 -0
- package/src/verax/core/integrity/transaction.js +140 -0
- package/src/verax/core/observe/run-timeline.js +318 -0
- package/src/verax/core/perf/perf.contract.js +186 -0
- package/src/verax/core/perf/perf.display.js +65 -0
- package/src/verax/core/perf/perf.enforcer.js +91 -0
- package/src/verax/core/perf/perf.monitor.js +209 -0
- package/src/verax/core/perf/perf.report.js +200 -0
- package/src/verax/core/pipeline-tracker.js +243 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +130 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +164 -0
- package/src/verax/core/release/reproducibility.check.js +222 -0
- package/src/verax/core/release/sbom.builder.js +292 -0
- package/src/verax/core/replay-validator.js +2 -0
- package/src/verax/core/replay.js +4 -0
- package/src/verax/core/report/cross-index.js +195 -0
- package/src/verax/core/report/human-summary.js +362 -0
- package/src/verax/core/route-intelligence.js +420 -0
- package/src/verax/core/run-id.js +6 -3
- package/src/verax/core/run-manifest.js +4 -3
- package/src/verax/core/security/secrets.scan.js +329 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +128 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +334 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/truth/truth.certificate.js +252 -0
- package/src/verax/core/ui-feedback-intelligence.js +481 -0
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +62 -34
- package/src/verax/detect/confidence-helper.js +34 -0
- package/src/verax/detect/dynamic-route-findings.js +338 -0
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +2 -2
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +131 -35
- package/src/verax/detect/flow-detector.js +2 -2
- package/src/verax/detect/form-silent-failure.js +98 -0
- package/src/verax/detect/index.js +46 -5
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +558 -0
- package/src/verax/detect/navigation-silent-failure.js +82 -0
- package/src/verax/detect/problem-aggregator.js +361 -0
- package/src/verax/detect/route-findings.js +219 -0
- package/src/verax/detect/summary-writer.js +477 -0
- package/src/verax/detect/test-failure-cause-inference.js +314 -0
- package/src/verax/detect/ui-feedback-findings.js +207 -0
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +4 -0
- package/src/verax/intel/ts-program.js +1 -0
- package/src/verax/intel/vue-navigation-extractor.js +3 -0
- package/src/verax/learn/action-contract-extractor.js +3 -0
- package/src/verax/learn/ast-contract-extractor.js +1 -1
- package/src/verax/learn/flow-extractor.js +1 -0
- package/src/verax/learn/project-detector.js +5 -0
- package/src/verax/learn/react-router-extractor.js +2 -0
- package/src/verax/learn/source-instrumenter.js +1 -0
- package/src/verax/learn/state-extractor.js +2 -1
- package/src/verax/learn/static-extractor.js +1 -0
- package/src/verax/observe/coverage-gaps.js +132 -0
- package/src/verax/observe/expectation-handler.js +126 -0
- package/src/verax/observe/incremental-skip.js +46 -0
- package/src/verax/observe/index.js +51 -155
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -513
- package/src/verax/observe/network-firewall.js +86 -0
- package/src/verax/observe/observation-builder.js +169 -0
- package/src/verax/observe/observe-context.js +205 -0
- package/src/verax/observe/observe-helpers.js +192 -0
- package/src/verax/observe/observe-runner.js +230 -0
- package/src/verax/observe/observers/budget-observer.js +185 -0
- package/src/verax/observe/observers/console-observer.js +102 -0
- package/src/verax/observe/observers/coverage-observer.js +107 -0
- package/src/verax/observe/observers/interaction-observer.js +471 -0
- package/src/verax/observe/observers/navigation-observer.js +132 -0
- package/src/verax/observe/observers/network-observer.js +87 -0
- package/src/verax/observe/observers/safety-observer.js +82 -0
- package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
- package/src/verax/observe/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-feedback-detector.js +742 -0
- package/src/verax/scan-summary-writer.js +2 -0
- package/src/verax/shared/artifact-manager.js +25 -5
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/view-switch-rules.js +208 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 24 — Confidence Invariants (Immutable Rules)
|
|
3
|
+
*
|
|
4
|
+
* Formal confidence invariants that MUST be enforced.
|
|
5
|
+
* Violations trigger automatic downgrades and are recorded.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Confidence invariant violation reason codes
|
|
10
|
+
*/
|
|
11
|
+
export const INVARIANT_VIOLATION = {
|
|
12
|
+
CONFIRMED_BELOW_MIN: 'INV_CONFIRMED_BELOW_MIN',
|
|
13
|
+
SUSPECTED_ABOVE_MAX: 'INV_SUSPECTED_ABOVE_MAX',
|
|
14
|
+
SUSPECTED_BELOW_MIN: 'INV_SUSPECTED_BELOW_MIN',
|
|
15
|
+
INFORMATIONAL_ABOVE_MAX: 'INV_INFORMATIONAL_ABOVE_MAX',
|
|
16
|
+
INFORMATIONAL_BELOW_MIN: 'INV_INFORMATIONAL_BELOW_MIN',
|
|
17
|
+
IGNORED_NON_ZERO: 'INV_IGNORED_NON_ZERO',
|
|
18
|
+
UNPROVEN_EXPECTATION_ABOVE_MAX: 'INV_UNPROVEN_EXPECTATION_ABOVE_MAX',
|
|
19
|
+
VERIFIED_WITH_ERRORS_ABOVE_MAX: 'INV_VERIFIED_WITH_ERRORS_ABOVE_MAX',
|
|
20
|
+
GUARDRAILS_DOWNGRADE_OVERRIDE: 'INV_GUARDRAILS_DOWNGRADE_OVERRIDE'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Confidence ranges by status (immutable)
|
|
25
|
+
*/
|
|
26
|
+
export const CONFIDENCE_RANGES = {
|
|
27
|
+
CONFIRMED: { min: 0.70, max: 1.00 },
|
|
28
|
+
SUSPECTED: { min: 0.30, max: 0.69 },
|
|
29
|
+
INFORMATIONAL: { min: 0.01, max: 0.29 },
|
|
30
|
+
IGNORED: { min: 0.00, max: 0.00 }
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Special caps
|
|
35
|
+
*/
|
|
36
|
+
export const CONFIDENCE_CAPS = {
|
|
37
|
+
UNPROVEN_EXPECTATION: 0.39,
|
|
38
|
+
VERIFIED_WITH_ERRORS: 0.49
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if confidence violates invariants for a given status
|
|
43
|
+
*
|
|
44
|
+
* @param {number} confidence - Confidence score (0..1)
|
|
45
|
+
* @param {string} status - Finding status (CONFIRMED, SUSPECTED, etc.)
|
|
46
|
+
* @param {Object} context - Context { expectationProof, verificationStatus, guardrailsOutcome }
|
|
47
|
+
* @returns {Object} { violated: boolean, violations: [], correctedConfidence: number }
|
|
48
|
+
*/
|
|
49
|
+
export function checkConfidenceInvariants(confidence, status, context = {}) {
|
|
50
|
+
const violations = [];
|
|
51
|
+
let correctedConfidence = confidence;
|
|
52
|
+
|
|
53
|
+
// Rule 1: CONFIRMED ⇒ confidence ∈ [0.70 – 1.00]
|
|
54
|
+
if (status === 'CONFIRMED') {
|
|
55
|
+
if (confidence < CONFIDENCE_RANGES.CONFIRMED.min) {
|
|
56
|
+
violations.push({
|
|
57
|
+
code: INVARIANT_VIOLATION.CONFIRMED_BELOW_MIN,
|
|
58
|
+
message: `CONFIRMED status requires confidence >= ${CONFIDENCE_RANGES.CONFIRMED.min}, got ${confidence}`,
|
|
59
|
+
corrected: CONFIDENCE_RANGES.CONFIRMED.min
|
|
60
|
+
});
|
|
61
|
+
correctedConfidence = CONFIDENCE_RANGES.CONFIRMED.min;
|
|
62
|
+
}
|
|
63
|
+
if (confidence > CONFIDENCE_RANGES.CONFIRMED.max) {
|
|
64
|
+
correctedConfidence = CONFIDENCE_RANGES.CONFIRMED.max;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Rule 2: SUSPECTED ⇒ confidence ∈ [0.30 – 0.69]
|
|
69
|
+
if (status === 'SUSPECTED') {
|
|
70
|
+
if (confidence > CONFIDENCE_RANGES.SUSPECTED.max) {
|
|
71
|
+
violations.push({
|
|
72
|
+
code: INVARIANT_VIOLATION.SUSPECTED_ABOVE_MAX,
|
|
73
|
+
message: `SUSPECTED status requires confidence <= ${CONFIDENCE_RANGES.SUSPECTED.max}, got ${confidence}`,
|
|
74
|
+
corrected: CONFIDENCE_RANGES.SUSPECTED.max
|
|
75
|
+
});
|
|
76
|
+
correctedConfidence = CONFIDENCE_RANGES.SUSPECTED.max;
|
|
77
|
+
}
|
|
78
|
+
if (confidence < CONFIDENCE_RANGES.SUSPECTED.min) {
|
|
79
|
+
violations.push({
|
|
80
|
+
code: INVARIANT_VIOLATION.SUSPECTED_BELOW_MIN,
|
|
81
|
+
message: `SUSPECTED status requires confidence >= ${CONFIDENCE_RANGES.SUSPECTED.min}, got ${confidence}`,
|
|
82
|
+
corrected: CONFIDENCE_RANGES.SUSPECTED.min
|
|
83
|
+
});
|
|
84
|
+
correctedConfidence = CONFIDENCE_RANGES.SUSPECTED.min;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Rule 3: INFORMATIONAL ⇒ confidence ∈ [0.01 – 0.29]
|
|
89
|
+
if (status === 'INFORMATIONAL') {
|
|
90
|
+
if (confidence > CONFIDENCE_RANGES.INFORMATIONAL.max) {
|
|
91
|
+
violations.push({
|
|
92
|
+
code: INVARIANT_VIOLATION.INFORMATIONAL_ABOVE_MAX,
|
|
93
|
+
message: `INFORMATIONAL status requires confidence <= ${CONFIDENCE_RANGES.INFORMATIONAL.max}, got ${confidence}`,
|
|
94
|
+
corrected: CONFIDENCE_RANGES.INFORMATIONAL.max
|
|
95
|
+
});
|
|
96
|
+
correctedConfidence = CONFIDENCE_RANGES.INFORMATIONAL.max;
|
|
97
|
+
}
|
|
98
|
+
if (confidence < CONFIDENCE_RANGES.INFORMATIONAL.min) {
|
|
99
|
+
violations.push({
|
|
100
|
+
code: INVARIANT_VIOLATION.INFORMATIONAL_BELOW_MIN,
|
|
101
|
+
message: `INFORMATIONAL status requires confidence >= ${CONFIDENCE_RANGES.INFORMATIONAL.min}, got ${confidence}`,
|
|
102
|
+
corrected: CONFIDENCE_RANGES.INFORMATIONAL.min
|
|
103
|
+
});
|
|
104
|
+
correctedConfidence = CONFIDENCE_RANGES.INFORMATIONAL.min;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Rule 4: IGNORED ⇒ confidence === 0
|
|
109
|
+
if (status === 'IGNORED') {
|
|
110
|
+
if (confidence !== 0) {
|
|
111
|
+
violations.push({
|
|
112
|
+
code: INVARIANT_VIOLATION.IGNORED_NON_ZERO,
|
|
113
|
+
message: `IGNORED status requires confidence === 0, got ${confidence}`,
|
|
114
|
+
corrected: 0
|
|
115
|
+
});
|
|
116
|
+
correctedConfidence = 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Rule 5: UNPROVEN_EXPECTATION ⇒ confidence ≤ 0.39
|
|
121
|
+
if (context.expectationProof === 'UNPROVEN_EXPECTATION') {
|
|
122
|
+
if (correctedConfidence > CONFIDENCE_CAPS.UNPROVEN_EXPECTATION) {
|
|
123
|
+
violations.push({
|
|
124
|
+
code: INVARIANT_VIOLATION.UNPROVEN_EXPECTATION_ABOVE_MAX,
|
|
125
|
+
message: `UNPROVEN_EXPECTATION requires confidence <= ${CONFIDENCE_CAPS.UNPROVEN_EXPECTATION}, got ${correctedConfidence}`,
|
|
126
|
+
corrected: CONFIDENCE_CAPS.UNPROVEN_EXPECTATION
|
|
127
|
+
});
|
|
128
|
+
correctedConfidence = CONFIDENCE_CAPS.UNPROVEN_EXPECTATION;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Rule 6: VERIFIED_WITH_ERRORS ⇒ confidence capped at 0.49
|
|
133
|
+
if (context.verificationStatus === 'VERIFIED_WITH_ERRORS') {
|
|
134
|
+
if (correctedConfidence > CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS) {
|
|
135
|
+
violations.push({
|
|
136
|
+
code: INVARIANT_VIOLATION.VERIFIED_WITH_ERRORS_ABOVE_MAX,
|
|
137
|
+
message: `VERIFIED_WITH_ERRORS requires confidence <= ${CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS}, got ${correctedConfidence}`,
|
|
138
|
+
corrected: CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS
|
|
139
|
+
});
|
|
140
|
+
correctedConfidence = CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Rule 7: Guardrails downgrade ALWAYS overrides raw confidence
|
|
145
|
+
if (context.guardrailsOutcome && context.guardrailsOutcome.downgraded) {
|
|
146
|
+
const guardrailsFinalDecision = context.guardrailsOutcome.finalDecision || context.guardrailsOutcome.recommendedStatus;
|
|
147
|
+
if (guardrailsFinalDecision && guardrailsFinalDecision !== status) {
|
|
148
|
+
// Guardrails changed the status, confidence must match the new status
|
|
149
|
+
const range = CONFIDENCE_RANGES[guardrailsFinalDecision];
|
|
150
|
+
if (range) {
|
|
151
|
+
if (correctedConfidence > range.max) {
|
|
152
|
+
violations.push({
|
|
153
|
+
code: INVARIANT_VIOLATION.GUARDRAILS_DOWNGRADE_OVERRIDE,
|
|
154
|
+
message: `Guardrails downgrade to ${guardrailsFinalDecision} requires confidence <= ${range.max}, got ${correctedConfidence}`,
|
|
155
|
+
corrected: range.max
|
|
156
|
+
});
|
|
157
|
+
correctedConfidence = range.max;
|
|
158
|
+
}
|
|
159
|
+
if (correctedConfidence < range.min && guardrailsFinalDecision !== 'IGNORED') {
|
|
160
|
+
violations.push({
|
|
161
|
+
code: INVARIANT_VIOLATION.GUARDRAILS_DOWNGRADE_OVERRIDE,
|
|
162
|
+
message: `Guardrails downgrade to ${guardrailsFinalDecision} requires confidence >= ${range.min}, got ${correctedConfidence}`,
|
|
163
|
+
corrected: range.min
|
|
164
|
+
});
|
|
165
|
+
correctedConfidence = range.min;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
violated: violations.length > 0,
|
|
173
|
+
violations,
|
|
174
|
+
correctedConfidence
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Enforce confidence invariants (mutates finding if needed)
|
|
180
|
+
*
|
|
181
|
+
* @param {Object} finding - Finding object
|
|
182
|
+
* @param {Object} context - Context for invariant checking
|
|
183
|
+
* @returns {Object} { finding: correctedFinding, violations: [] }
|
|
184
|
+
*/
|
|
185
|
+
export function enforceConfidenceInvariants(finding, context = {}) {
|
|
186
|
+
const status = finding.severity || finding.status || 'SUSPECTED';
|
|
187
|
+
const confidence = finding.confidence !== undefined ? finding.confidence : 0;
|
|
188
|
+
|
|
189
|
+
const expectationProof = finding.expectation?.proof || context.expectationProof;
|
|
190
|
+
const verificationStatus = context.verificationStatus;
|
|
191
|
+
const guardrailsOutcome = finding.guardrails || context.guardrailsOutcome;
|
|
192
|
+
|
|
193
|
+
const invariantCheck = checkConfidenceInvariants(confidence, status, {
|
|
194
|
+
expectationProof,
|
|
195
|
+
verificationStatus,
|
|
196
|
+
guardrailsOutcome
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
if (invariantCheck.violated) {
|
|
200
|
+
// Apply corrections
|
|
201
|
+
const correctedFinding = {
|
|
202
|
+
...finding,
|
|
203
|
+
confidence: invariantCheck.correctedConfidence,
|
|
204
|
+
confidenceLevel: determineConfidenceLevel(invariantCheck.correctedConfidence),
|
|
205
|
+
invariantViolations: invariantCheck.violations.map(v => ({
|
|
206
|
+
code: v.code,
|
|
207
|
+
message: v.message,
|
|
208
|
+
originalConfidence: confidence,
|
|
209
|
+
correctedConfidence: v.corrected
|
|
210
|
+
}))
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
finding: correctedFinding,
|
|
215
|
+
violations: invariantCheck.violations
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
finding,
|
|
221
|
+
violations: []
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Determine confidence level from score
|
|
227
|
+
*/
|
|
228
|
+
function determineConfidenceLevel(score) {
|
|
229
|
+
if (score >= 0.80) return 'HIGH';
|
|
230
|
+
if (score >= 0.50) return 'MEDIUM';
|
|
231
|
+
if (score >= 0.20) return 'LOW';
|
|
232
|
+
return 'UNPROVEN';
|
|
233
|
+
}
|
|
234
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 24 — Confidence Report Writer
|
|
3
|
+
*
|
|
4
|
+
* Writes confidence.report.json artifact per run.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { writeFileSync } from 'fs';
|
|
8
|
+
import { resolve } from 'path';
|
|
9
|
+
import { ARTIFACT_REGISTRY } from '../artifacts/registry.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Write confidence report to disk.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} runDir - Absolute run directory path
|
|
15
|
+
* @param {Array} findings - Array of findings with confidence data
|
|
16
|
+
* @param {Object} confidenceData - Map of findingIdentity -> confidence computation result
|
|
17
|
+
* @returns {string} Path to written report
|
|
18
|
+
*/
|
|
19
|
+
export function writeConfidenceReport(runDir, findings, confidenceData = {}) {
|
|
20
|
+
const reportPath = resolve(runDir, ARTIFACT_REGISTRY.confidenceReport.filename);
|
|
21
|
+
|
|
22
|
+
// Build per-finding entries (deterministic ordering by findingIdentity)
|
|
23
|
+
const perFinding = {};
|
|
24
|
+
const summary = {
|
|
25
|
+
totalFindings: findings.length,
|
|
26
|
+
byConfidenceLevel: {
|
|
27
|
+
HIGH: 0,
|
|
28
|
+
MEDIUM: 0,
|
|
29
|
+
LOW: 0,
|
|
30
|
+
UNPROVEN: 0
|
|
31
|
+
},
|
|
32
|
+
byTruthStatus: {
|
|
33
|
+
CONFIRMED: 0,
|
|
34
|
+
SUSPECTED: 0,
|
|
35
|
+
INFORMATIONAL: 0,
|
|
36
|
+
IGNORED: 0
|
|
37
|
+
},
|
|
38
|
+
invariantViolationsCount: 0,
|
|
39
|
+
averageConfidenceBefore: 0,
|
|
40
|
+
averageConfidenceAfter: 0
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
let totalConfidenceBefore = 0;
|
|
44
|
+
let totalConfidenceAfter = 0;
|
|
45
|
+
|
|
46
|
+
for (const finding of findings) {
|
|
47
|
+
const findingIdentity = finding.findingId || finding.id || `finding-${findings.indexOf(finding)}`;
|
|
48
|
+
const confidenceResult = confidenceData[findingIdentity] || null;
|
|
49
|
+
const truthStatus = finding.severity || finding.status || 'SUSPECTED';
|
|
50
|
+
|
|
51
|
+
const confidenceBefore = confidenceResult?.confidenceBefore || finding.confidence || 0;
|
|
52
|
+
const confidenceAfter = confidenceResult?.confidenceAfter || finding.confidence || 0;
|
|
53
|
+
const confidenceLevel = confidenceResult?.confidenceLevel || finding.confidenceLevel || 'UNPROVEN';
|
|
54
|
+
|
|
55
|
+
totalConfidenceBefore += confidenceBefore;
|
|
56
|
+
totalConfidenceAfter += confidenceAfter;
|
|
57
|
+
|
|
58
|
+
// Track by confidence level
|
|
59
|
+
if (summary.byConfidenceLevel[confidenceLevel] !== undefined) {
|
|
60
|
+
summary.byConfidenceLevel[confidenceLevel]++;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Track by truth status
|
|
64
|
+
if (summary.byTruthStatus[truthStatus] !== undefined) {
|
|
65
|
+
summary.byTruthStatus[truthStatus]++;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Track invariant violations
|
|
69
|
+
const violations = confidenceResult?.invariantViolations || finding.invariantViolations || [];
|
|
70
|
+
if (violations.length > 0) {
|
|
71
|
+
summary.invariantViolationsCount += violations.length;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Build per-finding entry
|
|
75
|
+
perFinding[findingIdentity] = {
|
|
76
|
+
confidenceBefore,
|
|
77
|
+
confidenceAfter,
|
|
78
|
+
confidenceLevel,
|
|
79
|
+
truthStatus,
|
|
80
|
+
appliedInvariants: confidenceResult?.appliedInvariants || [],
|
|
81
|
+
invariantViolations: violations.map(v => ({
|
|
82
|
+
code: v.code,
|
|
83
|
+
message: v.message,
|
|
84
|
+
originalConfidence: v.originalConfidence,
|
|
85
|
+
correctedConfidence: v.correctedConfidence || v.corrected
|
|
86
|
+
})),
|
|
87
|
+
explanation: confidenceResult?.explanation || finding.confidenceReasons || [],
|
|
88
|
+
expectationProof: confidenceResult?.expectationProof || finding.expectation?.proof || null,
|
|
89
|
+
verificationStatus: confidenceResult?.verificationStatus || null
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Compute averages
|
|
94
|
+
if (findings.length > 0) {
|
|
95
|
+
summary.averageConfidenceBefore = totalConfidenceBefore / findings.length;
|
|
96
|
+
summary.averageConfidenceAfter = totalConfidenceAfter / findings.length;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Build report
|
|
100
|
+
const report = {
|
|
101
|
+
version: 1,
|
|
102
|
+
generatedAt: new Date().toISOString(),
|
|
103
|
+
summary,
|
|
104
|
+
perFinding
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Write to disk
|
|
108
|
+
writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
|
|
109
|
+
|
|
110
|
+
return reportPath;
|
|
111
|
+
}
|
|
112
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 24 — Confidence Weights (Canonical)
|
|
3
|
+
*
|
|
4
|
+
* Canonical weights for evidence types.
|
|
5
|
+
* All capabilities MUST use these weights.
|
|
6
|
+
* No custom weighting allowed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Canonical evidence weights (normalized, sum to 1.0)
|
|
11
|
+
*/
|
|
12
|
+
export const CONFIDENCE_WEIGHTS = {
|
|
13
|
+
UI_EVIDENCE: 0.25,
|
|
14
|
+
NETWORK_EVIDENCE: 0.25,
|
|
15
|
+
STATE_EVIDENCE: 0.15,
|
|
16
|
+
ROUTE_EVIDENCE: 0.15,
|
|
17
|
+
CONSOLE_EVIDENCE: 0.10,
|
|
18
|
+
EVIDENCE_COMPLETENESS: 0.10
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Validate that weights sum to 1.0
|
|
23
|
+
*/
|
|
24
|
+
export function validateWeights(weights = CONFIDENCE_WEIGHTS) {
|
|
25
|
+
const sum = Object.values(weights).reduce((a, b) => a + b, 0);
|
|
26
|
+
if (Math.abs(sum - 1.0) > 0.001) {
|
|
27
|
+
throw new Error(`Confidence weights must sum to 1.0, got ${sum}`);
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get weight for evidence type
|
|
34
|
+
*
|
|
35
|
+
* @param {string} evidenceType - One of: UI_EVIDENCE, NETWORK_EVIDENCE, STATE_EVIDENCE, ROUTE_EVIDENCE, CONSOLE_EVIDENCE, EVIDENCE_COMPLETENESS
|
|
36
|
+
* @returns {number} Weight (0..1)
|
|
37
|
+
*/
|
|
38
|
+
export function getEvidenceWeight(evidenceType) {
|
|
39
|
+
return CONFIDENCE_WEIGHTS[evidenceType] || 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Validate on module load
|
|
43
|
+
validateWeights();
|
|
44
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Confidence Policy Defaults
|
|
3
|
+
*
|
|
4
|
+
* Default confidence policy matching current hardcoded behavior.
|
|
5
|
+
* Truth locks are enforced and cannot be configured away.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Default confidence policy
|
|
10
|
+
*
|
|
11
|
+
* This policy matches the current hardcoded behavior exactly.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_CONFIDENCE_POLICY = {
|
|
14
|
+
version: '21.4.0',
|
|
15
|
+
source: 'default',
|
|
16
|
+
baseScores: {
|
|
17
|
+
promiseProven: 1.0,
|
|
18
|
+
promiseObserved: 0.7,
|
|
19
|
+
promiseWeak: 0.5,
|
|
20
|
+
promiseUnknown: 0.2,
|
|
21
|
+
urlChanged: 0.3,
|
|
22
|
+
domChanged: 0.2,
|
|
23
|
+
uiFeedbackConfirmed: 0.3,
|
|
24
|
+
consoleErrors: 0.2,
|
|
25
|
+
networkFailure: 0.3,
|
|
26
|
+
networkSuccess: 0.1,
|
|
27
|
+
timingAligned: 0.2,
|
|
28
|
+
routeMatched: 0.2,
|
|
29
|
+
requestMatched: 0.2,
|
|
30
|
+
traceLinked: 0.1,
|
|
31
|
+
screenshots: 0.3,
|
|
32
|
+
traces: 0.2,
|
|
33
|
+
signals: 0.2,
|
|
34
|
+
snippets: 0.3
|
|
35
|
+
},
|
|
36
|
+
thresholds: {
|
|
37
|
+
high: 0.8,
|
|
38
|
+
medium: 0.6,
|
|
39
|
+
low: 0.3
|
|
40
|
+
},
|
|
41
|
+
weights: {
|
|
42
|
+
promiseStrength: 0.25,
|
|
43
|
+
observationStrength: 0.30,
|
|
44
|
+
correlationQuality: 0.20,
|
|
45
|
+
guardrails: 0.15,
|
|
46
|
+
evidenceCompleteness: 0.10
|
|
47
|
+
},
|
|
48
|
+
truthLocks: {
|
|
49
|
+
// HARD LOCK: CONFIRMED requires evidencePackage.isComplete === true
|
|
50
|
+
evidenceCompleteRequired: true,
|
|
51
|
+
|
|
52
|
+
// HARD LOCK: NON_DETERMINISTIC verdict caps confidence ≤ 0.6
|
|
53
|
+
nonDeterministicMaxConfidence: 0.6,
|
|
54
|
+
|
|
55
|
+
// HARD LOCK: Guardrails confidence deltas are max-negative only (enforced in guardrails policy)
|
|
56
|
+
guardrailsMaxNegative: true,
|
|
57
|
+
|
|
58
|
+
// HARD LOCK: Cannot upgrade SUSPECTED → CONFIRMED via policy
|
|
59
|
+
cannotUpgradeToConfirmed: true,
|
|
60
|
+
|
|
61
|
+
// HARD LOCK: Contradiction penalty
|
|
62
|
+
contradictionPenalty: 0.3
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Confidence Policy Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads confidence policies from files or uses defaults.
|
|
5
|
+
* Validates policies and enforces truth locks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync } from 'fs';
|
|
9
|
+
import { resolve } from 'path';
|
|
10
|
+
import { validateConfidencePolicy } from './confidence.schema.js';
|
|
11
|
+
import { DEFAULT_CONFIDENCE_POLICY } from './confidence.defaults.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Load confidence policy
|
|
15
|
+
*
|
|
16
|
+
* @param {string|null} policyPath - Path to custom policy file (optional)
|
|
17
|
+
* @param {string} projectDir - Project directory
|
|
18
|
+
* @returns {Object} Confidence policy
|
|
19
|
+
* @throws {Error} If policy is invalid
|
|
20
|
+
*/
|
|
21
|
+
export function loadConfidencePolicy(policyPath = null, projectDir = null) {
|
|
22
|
+
// If no custom policy path, use defaults
|
|
23
|
+
if (!policyPath) {
|
|
24
|
+
return DEFAULT_CONFIDENCE_POLICY;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Resolve policy path
|
|
28
|
+
const resolvedPath = projectDir ? resolve(projectDir, policyPath) : resolve(policyPath);
|
|
29
|
+
|
|
30
|
+
// Check if file exists
|
|
31
|
+
if (!existsSync(resolvedPath)) {
|
|
32
|
+
throw new Error(`Confidence policy file not found: ${resolvedPath}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Read and parse policy
|
|
36
|
+
let policy;
|
|
37
|
+
try {
|
|
38
|
+
const policyContent = readFileSync(resolvedPath, 'utf-8');
|
|
39
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
40
|
+
policy = JSON.parse(policyContent);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw new Error(`Failed to load confidence policy: ${error.message}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Validate policy
|
|
46
|
+
try {
|
|
47
|
+
validateConfidencePolicy(policy);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new Error(`Invalid confidence policy: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// HARD LOCK: Enforce truth locks from defaults (cannot be overridden)
|
|
53
|
+
// Defaults override any custom values
|
|
54
|
+
policy.truthLocks = {
|
|
55
|
+
...policy.truthLocks,
|
|
56
|
+
...DEFAULT_CONFIDENCE_POLICY.truthLocks // Defaults take precedence
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Mark as custom
|
|
60
|
+
policy.source = 'custom';
|
|
61
|
+
|
|
62
|
+
return policy;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get policy report metadata
|
|
67
|
+
*
|
|
68
|
+
* @param {Object} policy - Confidence policy
|
|
69
|
+
* @returns {Object} Policy report metadata
|
|
70
|
+
*/
|
|
71
|
+
export function getPolicyReport(policy) {
|
|
72
|
+
return {
|
|
73
|
+
version: policy.version,
|
|
74
|
+
source: policy.source,
|
|
75
|
+
thresholds: policy.thresholds,
|
|
76
|
+
weights: policy.weights,
|
|
77
|
+
truthLocks: Object.keys(policy.truthLocks)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Confidence Policy Schema
|
|
3
|
+
*
|
|
4
|
+
* Defines the structure for confidence policies.
|
|
5
|
+
* Truth locks are enforced and cannot be configured away.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Confidence Policy Schema
|
|
10
|
+
*
|
|
11
|
+
* @typedef {Object} ConfidencePolicy
|
|
12
|
+
* @property {string} version - Policy version
|
|
13
|
+
* @property {string} source - 'default' | 'custom'
|
|
14
|
+
* @property {Object} baseScores - Base score configuration
|
|
15
|
+
* @property {Object} thresholds - Threshold configuration
|
|
16
|
+
* @property {Object} weights - Weight configuration for pillars
|
|
17
|
+
* @property {Object} truthLocks - Truth locks (cannot be overridden)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validate confidence policy
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} policy - Policy to validate
|
|
24
|
+
* @throws {Error} If policy is invalid
|
|
25
|
+
*/
|
|
26
|
+
export function validateConfidencePolicy(policy) {
|
|
27
|
+
if (!policy) {
|
|
28
|
+
throw new Error('Confidence policy is required');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!policy.version || typeof policy.version !== 'string') {
|
|
32
|
+
throw new Error('Confidence policy must have a version string');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Validate base scores
|
|
36
|
+
if (!policy.baseScores || typeof policy.baseScores !== 'object') {
|
|
37
|
+
throw new Error('Confidence policy must have baseScores object');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validate thresholds
|
|
41
|
+
if (!policy.thresholds || typeof policy.thresholds !== 'object') {
|
|
42
|
+
throw new Error('Confidence policy must have thresholds object');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Validate weights
|
|
46
|
+
if (!policy.weights || typeof policy.weights !== 'object') {
|
|
47
|
+
throw new Error('Confidence policy must have weights object');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Validate truth locks
|
|
51
|
+
if (!policy.truthLocks || typeof policy.truthLocks !== 'object') {
|
|
52
|
+
throw new Error('Confidence policy must have truthLocks object');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// HARD LOCK: Truth locks cannot be overridden
|
|
56
|
+
const requiredTruthLocks = [
|
|
57
|
+
'evidenceCompleteRequired',
|
|
58
|
+
'nonDeterministicMaxConfidence',
|
|
59
|
+
'guardrailsMaxNegative'
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
for (const lock of requiredTruthLocks) {
|
|
63
|
+
if (!(lock in policy.truthLocks)) {
|
|
64
|
+
throw new Error(`Confidence policy must have truth lock: ${lock}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Validate threshold values
|
|
69
|
+
const thresholds = policy.thresholds;
|
|
70
|
+
if (typeof thresholds.high !== 'number' || thresholds.high < 0 || thresholds.high > 1) {
|
|
71
|
+
throw new Error('Confidence policy threshold.high must be a number between 0 and 1');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof thresholds.medium !== 'number' || thresholds.medium < 0 || thresholds.medium > 1) {
|
|
75
|
+
throw new Error('Confidence policy threshold.medium must be a number between 0 and 1');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof thresholds.low !== 'number' || thresholds.low < 0 || thresholds.low > 1) {
|
|
79
|
+
throw new Error('Confidence policy threshold.low must be a number between 0 and 1');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Validate weights sum to reasonable range
|
|
83
|
+
const weights = policy.weights;
|
|
84
|
+
const weightSum = (weights.promiseStrength || 0) +
|
|
85
|
+
(weights.observationStrength || 0) +
|
|
86
|
+
(weights.correlationQuality || 0) +
|
|
87
|
+
(weights.guardrails || 0) +
|
|
88
|
+
(weights.evidenceCompleteness || 0);
|
|
89
|
+
|
|
90
|
+
if (Math.abs(weightSum - 1.0) > 0.01) {
|
|
91
|
+
throw new Error(`Confidence policy weights must sum to approximately 1.0 (got ${weightSum})`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|