@veraxhq/verax 0.2.1 → 0.3.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 +14 -18
- package/bin/verax.js +7 -0
- package/package.json +3 -3
- package/src/cli/commands/baseline.js +104 -0
- package/src/cli/commands/default.js +79 -25
- package/src/cli/commands/ga.js +243 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +131 -2
- package/src/cli/commands/release-check.js +213 -0
- package/src/cli/commands/run.js +246 -35
- package/src/cli/commands/security-check.js +211 -0
- package/src/cli/commands/truth.js +114 -0
- package/src/cli/entry.js +304 -67
- 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 +546 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/bootstrap-guard.js +86 -0
- package/src/cli/util/determinism-runner.js +123 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/env-url.js +4 -0
- package/src/cli/util/expectation-extractor.js +369 -73
- package/src/cli/util/findings-writer.js +126 -16
- package/src/cli/util/learn-writer.js +3 -1
- package/src/cli/util/observe-writer.js +3 -1
- package/src/cli/util/paths.js +3 -12
- package/src/cli/util/project-discovery.js +3 -0
- package/src/cli/util/project-writer.js +3 -1
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +1 -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 +147 -0
- package/src/cli/util/svelte-state-detector.js +243 -0
- package/src/cli/util/vue-navigation-detector.js +177 -0
- package/src/cli/util/vue-sfc-extractor.js +162 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- package/src/verax/cli/finding-explainer.js +56 -3
- package/src/verax/core/artifacts/registry.js +154 -0
- package/src/verax/core/artifacts/verifier.js +980 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +231 -0
- package/src/verax/core/capabilities/gates.js +499 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +137 -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 +79 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +484 -0
- package/src/verax/core/confidence-engine.js +486 -0
- package/src/verax/core/confidence-engine.js.backup +471 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +185 -0
- package/src/verax/core/contracts/validators.js +381 -0
- package/src/verax/core/decision-snapshot.js +30 -3
- package/src/verax/core/decisions/decision.trace.js +276 -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 +364 -0
- package/src/verax/core/determinism/engine.js +221 -0
- package/src/verax/core/determinism/finding-identity.js +148 -0
- package/src/verax/core/determinism/normalize.js +438 -0
- package/src/verax/core/determinism/report-writer.js +92 -0
- package/src/verax/core/determinism/run-fingerprint.js +118 -0
- package/src/verax/core/dynamic-route-intelligence.js +528 -0
- package/src/verax/core/evidence/evidence-capture-service.js +307 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +165 -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 +190 -0
- package/src/verax/core/failures/exit-codes.js +86 -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 +132 -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 +434 -0
- package/src/verax/core/ga/ga.enforcer.js +86 -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 +83 -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/observe/run-timeline.js +316 -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 +198 -0
- package/src/verax/core/pipeline-tracker.js +238 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +271 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +159 -0
- package/src/verax/core/release/reproducibility.check.js +221 -0
- package/src/verax/core/release/sbom.builder.js +283 -0
- package/src/verax/core/report/cross-index.js +192 -0
- package/src/verax/core/report/human-summary.js +222 -0
- package/src/verax/core/route-intelligence.js +419 -0
- package/src/verax/core/security/secrets.scan.js +326 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +124 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +326 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/truth/truth.certificate.js +250 -0
- package/src/verax/core/ui-feedback-intelligence.js +515 -0
- package/src/verax/detect/confidence-engine.js +628 -40
- package/src/verax/detect/confidence-helper.js +33 -0
- package/src/verax/detect/detection-engine.js +18 -1
- package/src/verax/detect/dynamic-route-findings.js +335 -0
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +3 -1
- package/src/verax/detect/findings-writer.js +141 -5
- package/src/verax/detect/index.js +229 -5
- package/src/verax/detect/journey-stall-detector.js +558 -0
- package/src/verax/detect/route-findings.js +218 -0
- package/src/verax/detect/ui-feedback-findings.js +207 -0
- package/src/verax/detect/verdict-engine.js +57 -3
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/index.js +413 -45
- package/src/verax/learn/action-contract-extractor.js +682 -64
- package/src/verax/learn/route-validator.js +4 -1
- package/src/verax/observe/index.js +88 -843
- package/src/verax/observe/interaction-runner.js +25 -8
- package/src/verax/observe/observe-context.js +205 -0
- package/src/verax/observe/observe-helpers.js +191 -0
- package/src/verax/observe/observe-runner.js +226 -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/ui-feedback-detector.js +742 -0
- package/src/verax/observe/ui-signal-sensor.js +148 -2
- package/src/verax/scan-summary-writer.js +42 -8
- package/src/verax/shared/artifact-manager.js +8 -5
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/view-switch-rules.js +208 -0
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Confidence Engine (Policy-Driven with Truth Locks)
|
|
3
|
+
*
|
|
4
|
+
* Central confidence engine that computes confidence scores using policies.
|
|
5
|
+
* Truth locks are enforced and cannot be configured away.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { computeConfidence as computeConfidenceLegacy } from '../detect/confidence-engine.js';
|
|
9
|
+
import { loadConfidencePolicy, getPolicyReport } from './confidence/confidence.loader.js';
|
|
10
|
+
|
|
11
|
+
// Re-export constants for backward compatibility
|
|
12
|
+
export const CONFIDENCE_LEVEL = {
|
|
13
|
+
HIGH: 'HIGH',
|
|
14
|
+
MEDIUM: 'MEDIUM',
|
|
15
|
+
LOW: 'LOW',
|
|
16
|
+
UNPROVEN: 'UNPROVEN',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const CONFIDENCE_REASON = {
|
|
20
|
+
// Promise Strength (A)
|
|
21
|
+
PROMISE_AST_BASED: 'PROMISE_AST_BASED',
|
|
22
|
+
PROMISE_PROVEN: 'PROMISE_PROVEN',
|
|
23
|
+
PROMISE_OBSERVED: 'PROMISE_OBSERVED',
|
|
24
|
+
PROMISE_WEAK: 'PROMISE_WEAK',
|
|
25
|
+
PROMISE_UNKNOWN: 'PROMISE_UNKNOWN',
|
|
26
|
+
|
|
27
|
+
// Observation Strength (B)
|
|
28
|
+
OBS_URL_CHANGED: 'OBS_URL_CHANGED',
|
|
29
|
+
OBS_DOM_CHANGED: 'OBS_DOM_CHANGED',
|
|
30
|
+
OBS_UI_FEEDBACK_CONFIRMED: 'OBS_UI_FEEDBACK_CONFIRMED',
|
|
31
|
+
OBS_CONSOLE_ERRORS: 'OBS_CONSOLE_ERRORS',
|
|
32
|
+
OBS_NETWORK_FAILURE: 'OBS_NETWORK_FAILURE',
|
|
33
|
+
OBS_NETWORK_SUCCESS: 'OBS_NETWORK_SUCCESS',
|
|
34
|
+
OBS_NO_SIGNALS: 'OBS_NO_SIGNALS',
|
|
35
|
+
|
|
36
|
+
// Correlation Quality (C)
|
|
37
|
+
CORR_TIMING_ALIGNED: 'CORR_TIMING_ALIGNED',
|
|
38
|
+
CORR_ROUTE_MATCHED: 'CORR_ROUTE_MATCHED',
|
|
39
|
+
CORR_REQUEST_MATCHED: 'CORR_REQUEST_MATCHED',
|
|
40
|
+
CORR_TRACE_LINKED: 'CORR_TRACE_LINKED',
|
|
41
|
+
CORR_WEAK_CORRELATION: 'CORR_WEAK_CORRELATION',
|
|
42
|
+
|
|
43
|
+
// Guardrails & Contradictions (D)
|
|
44
|
+
GUARD_ANALYTICS_FILTERED: 'GUARD_ANALYTICS_FILTERED',
|
|
45
|
+
GUARD_SHALLOW_ROUTING: 'GUARD_SHALLOW_ROUTING',
|
|
46
|
+
GUARD_NETWORK_SUCCESS_NO_UI: 'GUARD_NETWORK_SUCCESS_NO_UI',
|
|
47
|
+
GUARD_UI_FEEDBACK_PRESENT: 'GUARD_UI_FEEDBACK_PRESENT',
|
|
48
|
+
GUARD_CONTRADICTION_DETECTED: 'GUARD_CONTRADICTION_DETECTED',
|
|
49
|
+
|
|
50
|
+
// Evidence Completeness (E)
|
|
51
|
+
EVIDENCE_SCREENSHOTS: 'EVIDENCE_SCREENSHOTS',
|
|
52
|
+
EVIDENCE_TRACES: 'EVIDENCE_TRACES',
|
|
53
|
+
EVIDENCE_SIGNALS: 'EVIDENCE_SIGNALS',
|
|
54
|
+
EVIDENCE_SNIPPETS: 'EVIDENCE_SNIPPETS',
|
|
55
|
+
EVIDENCE_INCOMPLETE: 'EVIDENCE_INCOMPLETE',
|
|
56
|
+
|
|
57
|
+
// Sensor Presence
|
|
58
|
+
SENSOR_NETWORK_PRESENT: 'SENSOR_NETWORK_PRESENT',
|
|
59
|
+
SENSOR_CONSOLE_PRESENT: 'SENSOR_CONSOLE_PRESENT',
|
|
60
|
+
SENSOR_UI_PRESENT: 'SENSOR_UI_PRESENT',
|
|
61
|
+
SENSOR_UI_FEEDBACK_PRESENT: 'SENSOR_UI_FEEDBACK_PRESENT',
|
|
62
|
+
SENSOR_MISSING: 'SENSOR_MISSING',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Global policy cache
|
|
66
|
+
let cachedPolicy = null;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get confidence policy (cached)
|
|
70
|
+
*/
|
|
71
|
+
function getConfidencePolicy(policyPath = null, projectDir = null) {
|
|
72
|
+
if (!cachedPolicy) {
|
|
73
|
+
cachedPolicy = loadConfidencePolicy(policyPath, projectDir);
|
|
74
|
+
}
|
|
75
|
+
return cachedPolicy;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* PHASE 21.4: Compute unified confidence using policy
|
|
80
|
+
*
|
|
81
|
+
* @param {Object} params - Confidence computation parameters
|
|
82
|
+
* @param {string} params.findingType - Type of finding
|
|
83
|
+
* @param {Object} params.expectation - Promise/expectation
|
|
84
|
+
* @param {Object} params.sensors - Sensor data
|
|
85
|
+
* @param {Object} params.comparisons - Comparison data
|
|
86
|
+
* @param {Object} params.evidence - Evidence data (optional)
|
|
87
|
+
* @param {Object} params.options - Options { policyPath, projectDir, determinismVerdict, evidencePackage }
|
|
88
|
+
* @returns {Object} { score, level, reasons[], policyReport }
|
|
89
|
+
*/
|
|
90
|
+
export function computeUnifiedConfidence({ findingType, expectation, sensors = {}, comparisons = {}, evidence = {}, options = {} }) {
|
|
91
|
+
// Backward compatibility: options is optional
|
|
92
|
+
const policy = getConfidencePolicy(options?.policyPath, options?.projectDir);
|
|
93
|
+
const reasons = [];
|
|
94
|
+
|
|
95
|
+
// === PILLAR A: Promise Strength ===
|
|
96
|
+
const promiseStrength = assessPromiseStrength(expectation, reasons, policy);
|
|
97
|
+
|
|
98
|
+
// === PILLAR B: Observation Strength ===
|
|
99
|
+
const observationStrength = assessObservationStrength(sensors, comparisons, reasons, policy);
|
|
100
|
+
|
|
101
|
+
// === PILLAR C: Correlation Quality ===
|
|
102
|
+
const correlationQuality = assessCorrelationQuality(expectation, sensors, comparisons, evidence, reasons, policy);
|
|
103
|
+
|
|
104
|
+
// === PILLAR D: Guardrails & Contradictions ===
|
|
105
|
+
const guardrails = assessGuardrails(sensors, comparisons, findingType, reasons, policy);
|
|
106
|
+
|
|
107
|
+
// === PILLAR E: Evidence Completeness ===
|
|
108
|
+
const evidenceCompleteness = assessEvidenceCompleteness(evidence, sensors, reasons, policy);
|
|
109
|
+
|
|
110
|
+
// === COMPUTE BASE SCORE using policy weights ===
|
|
111
|
+
const baseScore = (
|
|
112
|
+
promiseStrength * policy.weights.promiseStrength +
|
|
113
|
+
observationStrength * policy.weights.observationStrength +
|
|
114
|
+
correlationQuality * policy.weights.correlationQuality +
|
|
115
|
+
guardrails * policy.weights.guardrails +
|
|
116
|
+
evidenceCompleteness * policy.weights.evidenceCompleteness
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// === APPLY CONTRADICTIONS using policy ===
|
|
120
|
+
const contradictionPenalty = guardrails < 0.5 ? policy.truthLocks.contradictionPenalty : 0;
|
|
121
|
+
let finalScore = Math.max(0, Math.min(1, baseScore - contradictionPenalty));
|
|
122
|
+
|
|
123
|
+
// === TRUTH LOCKS: Apply determinism cap ===
|
|
124
|
+
if (options?.determinismVerdict === 'NON_DETERMINISTIC') {
|
|
125
|
+
const maxConfidence = policy.truthLocks.nonDeterministicMaxConfidence;
|
|
126
|
+
if (finalScore > maxConfidence) {
|
|
127
|
+
reasons.push('TRUTH_LOCK_NON_DETERMINISTIC_CAP');
|
|
128
|
+
finalScore = Math.min(finalScore, maxConfidence);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// === TRUTH LOCKS: Evidence Law cap ===
|
|
133
|
+
const evidencePackage = options?.evidencePackage || evidence?.evidencePackage || {};
|
|
134
|
+
if (evidencePackage?.severity === 'CONFIRMED' || evidencePackage?.status === 'CONFIRMED') {
|
|
135
|
+
if (policy.truthLocks.evidenceCompleteRequired && !evidencePackage.isComplete) {
|
|
136
|
+
reasons.push('TRUTH_LOCK_EVIDENCE_INCOMPLETE');
|
|
137
|
+
// Force downgrade from CONFIRMED
|
|
138
|
+
finalScore = Math.min(finalScore, 0.6); // Cap at MEDIUM
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// === DETERMINE LEVEL using policy thresholds ===
|
|
143
|
+
const level = determineConfidenceLevel(finalScore, promiseStrength, evidenceCompleteness, policy);
|
|
144
|
+
|
|
145
|
+
const policyReport = getPolicyReport(policy);
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
score: finalScore,
|
|
149
|
+
level,
|
|
150
|
+
reasons: reasons.slice(0, 10),
|
|
151
|
+
policyReport: {
|
|
152
|
+
version: policyReport.version,
|
|
153
|
+
source: policyReport.source,
|
|
154
|
+
thresholds: policyReport.thresholds
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Assess promise strength (Pillar A) using policy
|
|
161
|
+
*/
|
|
162
|
+
function assessPromiseStrength(expectation, reasons, policy) {
|
|
163
|
+
if (!expectation) {
|
|
164
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_UNKNOWN);
|
|
165
|
+
return 0.0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const isASTBased = expectation.source?.astSource || expectation.metadata?.astSource;
|
|
169
|
+
if (isASTBased) {
|
|
170
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_AST_BASED);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const proof = expectation.proof || 'UNKNOWN';
|
|
174
|
+
if (proof === 'PROVEN_EXPECTATION' || proof === 'PROVEN') {
|
|
175
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
|
|
176
|
+
return policy.baseScores.promiseProven;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (proof === 'OBSERVED' || expectation.confidence >= 0.8) {
|
|
180
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_OBSERVED);
|
|
181
|
+
return policy.baseScores.promiseObserved;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (expectation.confidence >= 0.5) {
|
|
185
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_WEAK);
|
|
186
|
+
return policy.baseScores.promiseWeak;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_UNKNOWN);
|
|
190
|
+
return policy.baseScores.promiseUnknown;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Assess observation strength (Pillar B) using policy
|
|
195
|
+
*/
|
|
196
|
+
function assessObservationStrength(sensors, comparisons, reasons, policy) {
|
|
197
|
+
let strength = 0.0;
|
|
198
|
+
let signals = 0;
|
|
199
|
+
|
|
200
|
+
const urlChanged = sensors.navigation?.urlChanged === true || comparisons.urlChanged === true;
|
|
201
|
+
if (urlChanged) {
|
|
202
|
+
reasons.push(CONFIDENCE_REASON.OBS_URL_CHANGED);
|
|
203
|
+
strength += policy.baseScores.urlChanged;
|
|
204
|
+
signals++;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const domChanged = sensors.dom?.changed === true || comparisons.domChanged === true;
|
|
208
|
+
if (domChanged) {
|
|
209
|
+
reasons.push(CONFIDENCE_REASON.OBS_DOM_CHANGED);
|
|
210
|
+
strength += policy.baseScores.domChanged;
|
|
211
|
+
signals++;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const uiFeedback = sensors.uiFeedback || {};
|
|
215
|
+
const uiFeedbackScore = uiFeedback.overallUiFeedbackScore || 0;
|
|
216
|
+
if (uiFeedbackScore > 0.5) {
|
|
217
|
+
reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
|
|
218
|
+
strength += policy.baseScores.uiFeedbackConfirmed;
|
|
219
|
+
signals++;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const consoleErrors = sensors.console?.errors > 0 || sensors.console?.errorCount > 0;
|
|
223
|
+
if (consoleErrors) {
|
|
224
|
+
reasons.push(CONFIDENCE_REASON.OBS_CONSOLE_ERRORS);
|
|
225
|
+
strength += policy.baseScores.consoleErrors;
|
|
226
|
+
signals++;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const networkFailure = sensors.network?.failedRequests > 0 || sensors.network?.topFailedUrls?.length > 0;
|
|
230
|
+
if (networkFailure) {
|
|
231
|
+
reasons.push(CONFIDENCE_REASON.OBS_NETWORK_FAILURE);
|
|
232
|
+
strength += policy.baseScores.networkFailure;
|
|
233
|
+
signals++;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const networkSuccess = sensors.network?.successfulRequests > 0 && !networkFailure;
|
|
237
|
+
if (networkSuccess) {
|
|
238
|
+
reasons.push(CONFIDENCE_REASON.OBS_NETWORK_SUCCESS);
|
|
239
|
+
strength += policy.baseScores.networkSuccess;
|
|
240
|
+
signals++;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (signals === 0) {
|
|
244
|
+
reasons.push(CONFIDENCE_REASON.OBS_NO_SIGNALS);
|
|
245
|
+
return 0.0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return Math.min(1.0, strength);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Assess correlation quality (Pillar C) using policy
|
|
253
|
+
*/
|
|
254
|
+
function assessCorrelationQuality(expectation, sensors, comparisons, evidence, reasons, policy) {
|
|
255
|
+
let quality = 0.5;
|
|
256
|
+
|
|
257
|
+
if (evidence.timing || sensors.timing) {
|
|
258
|
+
reasons.push(CONFIDENCE_REASON.CORR_TIMING_ALIGNED);
|
|
259
|
+
quality += policy.baseScores.timingAligned;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (evidence.correlation?.routeMatched === true || evidence.routeDefinition?.path) {
|
|
263
|
+
reasons.push(CONFIDENCE_REASON.CORR_ROUTE_MATCHED);
|
|
264
|
+
quality += policy.baseScores.routeMatched;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (evidence.networkRequest?.matched === true || evidence.correlation?.requestMatched === true) {
|
|
268
|
+
reasons.push(CONFIDENCE_REASON.CORR_REQUEST_MATCHED);
|
|
269
|
+
quality += policy.baseScores.requestMatched;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (evidence.traceId || evidence.source?.file) {
|
|
273
|
+
reasons.push(CONFIDENCE_REASON.CORR_TRACE_LINKED);
|
|
274
|
+
quality += policy.baseScores.traceLinked;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (quality < 0.6) {
|
|
278
|
+
reasons.push(CONFIDENCE_REASON.CORR_WEAK_CORRELATION);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return Math.min(1.0, quality);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Assess guardrails & contradictions (Pillar D) using policy
|
|
286
|
+
*/
|
|
287
|
+
function assessGuardrails(sensors, comparisons, findingType, reasons, policy) {
|
|
288
|
+
let guardrailScore = 1.0;
|
|
289
|
+
|
|
290
|
+
const networkSensor = sensors.network || {};
|
|
291
|
+
const hasAnalytics = networkSensor.observedRequestUrls?.some(url =>
|
|
292
|
+
url && typeof url === 'string' && url.includes('/api/analytics')
|
|
293
|
+
);
|
|
294
|
+
if (hasAnalytics && !sensors.navigation?.urlChanged && !sensors.uiSignals?.diff?.changed) {
|
|
295
|
+
reasons.push(CONFIDENCE_REASON.GUARD_ANALYTICS_FILTERED);
|
|
296
|
+
guardrailScore -= 0.2;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (sensors.navigation?.shallowRouting === true && !sensors.navigation?.urlChanged) {
|
|
300
|
+
reasons.push(CONFIDENCE_REASON.GUARD_SHALLOW_ROUTING);
|
|
301
|
+
guardrailScore -= 0.3;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const networkSuccess = networkSensor.successfulRequests > 0;
|
|
305
|
+
const noUIChange = !sensors.uiSignals?.diff?.changed && !sensors.uiFeedback?.overallUiFeedbackScore;
|
|
306
|
+
if (networkSuccess && noUIChange && findingType?.includes('silent_failure')) {
|
|
307
|
+
reasons.push(CONFIDENCE_REASON.GUARD_NETWORK_SUCCESS_NO_UI);
|
|
308
|
+
guardrailScore -= 0.2;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const uiFeedbackScore = sensors.uiFeedback?.overallUiFeedbackScore || 0;
|
|
312
|
+
if (uiFeedbackScore > 0.5 && findingType?.includes('silent_failure')) {
|
|
313
|
+
reasons.push(CONFIDENCE_REASON.GUARD_UI_FEEDBACK_PRESENT);
|
|
314
|
+
guardrailScore -= 0.4;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (guardrailScore < 0.6) {
|
|
318
|
+
reasons.push(CONFIDENCE_REASON.GUARD_CONTRADICTION_DETECTED);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return Math.max(0.0, guardrailScore);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Assess evidence completeness (Pillar E) using policy
|
|
326
|
+
*/
|
|
327
|
+
function assessEvidenceCompleteness(evidence, sensors, reasons, policy) {
|
|
328
|
+
let completeness = 0.0;
|
|
329
|
+
|
|
330
|
+
if (evidence.beforeAfter?.beforeScreenshot && evidence.beforeAfter?.afterScreenshot) {
|
|
331
|
+
reasons.push(CONFIDENCE_REASON.EVIDENCE_SCREENSHOTS);
|
|
332
|
+
completeness += policy.baseScores.screenshots;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (evidence.traceId || sensors.traceId) {
|
|
336
|
+
reasons.push(CONFIDENCE_REASON.EVIDENCE_TRACES);
|
|
337
|
+
completeness += policy.baseScores.traces;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (evidence.signals && Object.keys(evidence.signals).length > 0) {
|
|
341
|
+
reasons.push(CONFIDENCE_REASON.EVIDENCE_SIGNALS);
|
|
342
|
+
completeness += policy.baseScores.signals;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (evidence.source?.astSource || evidence.navigationTrigger?.astSource) {
|
|
346
|
+
reasons.push(CONFIDENCE_REASON.EVIDENCE_SNIPPETS);
|
|
347
|
+
completeness += policy.baseScores.snippets;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (completeness < 0.5) {
|
|
351
|
+
reasons.push(CONFIDENCE_REASON.EVIDENCE_INCOMPLETE);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return completeness;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Determine confidence level using policy thresholds
|
|
359
|
+
*/
|
|
360
|
+
function determineConfidenceLevel(score, promiseStrength, evidenceCompleteness, policy) {
|
|
361
|
+
const thresholds = policy.thresholds;
|
|
362
|
+
|
|
363
|
+
if (score >= thresholds.high && promiseStrength >= 0.9 && evidenceCompleteness >= 0.7) {
|
|
364
|
+
return CONFIDENCE_LEVEL.HIGH;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (score >= thresholds.medium || (score >= 0.5 && promiseStrength >= 0.7)) {
|
|
368
|
+
return CONFIDENCE_LEVEL.MEDIUM;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (score >= thresholds.low) {
|
|
372
|
+
return CONFIDENCE_LEVEL.LOW;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return CONFIDENCE_LEVEL.UNPROVEN;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* PHASE 21.4: Compute confidence for finding (wrapper with policy support)
|
|
380
|
+
*
|
|
381
|
+
* @param {Object} params - Confidence computation parameters
|
|
382
|
+
* @param {Object} params.options - Options { policyPath, projectDir, determinismVerdict, evidencePackage }
|
|
383
|
+
* @returns {Object} { score, level, reasons[] }
|
|
384
|
+
*/
|
|
385
|
+
export function computeConfidenceForFinding(params) {
|
|
386
|
+
// Backward compatibility: options may be in params.options or params directly
|
|
387
|
+
const options = params.options || {};
|
|
388
|
+
|
|
389
|
+
// Use legacy system for base computation
|
|
390
|
+
const legacyResult = computeConfidenceLegacy(params);
|
|
391
|
+
|
|
392
|
+
// Normalize score from 0-100 to 0-1
|
|
393
|
+
let normalizedScore = (legacyResult.score || 0) / 100;
|
|
394
|
+
|
|
395
|
+
// Extract reasons from legacy explain/factors
|
|
396
|
+
const reasons = extractReasonsFromLegacy(legacyResult, params);
|
|
397
|
+
|
|
398
|
+
// Load policy for truth locks
|
|
399
|
+
const policy = getConfidencePolicy(options?.policyPath, options?.projectDir);
|
|
400
|
+
|
|
401
|
+
// === TRUTH LOCKS: Apply determinism cap ===
|
|
402
|
+
if (options?.determinismVerdict === 'NON_DETERMINISTIC') {
|
|
403
|
+
const maxConfidence = policy.truthLocks.nonDeterministicMaxConfidence;
|
|
404
|
+
if (normalizedScore > maxConfidence) {
|
|
405
|
+
reasons.push('TRUTH_LOCK_NON_DETERMINISTIC_CAP');
|
|
406
|
+
normalizedScore = Math.min(normalizedScore, maxConfidence);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// === TRUTH LOCKS: Evidence Law cap ===
|
|
411
|
+
const evidencePackage = options?.evidencePackage || params.evidence?.evidencePackage || {};
|
|
412
|
+
if (evidencePackage?.severity === 'CONFIRMED' || evidencePackage?.status === 'CONFIRMED') {
|
|
413
|
+
if (policy.truthLocks.evidenceCompleteRequired && !evidencePackage.isComplete) {
|
|
414
|
+
reasons.push('TRUTH_LOCK_EVIDENCE_INCOMPLETE');
|
|
415
|
+
normalizedScore = Math.min(normalizedScore, 0.6);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Determine level using policy thresholds
|
|
420
|
+
const level = determineConfidenceLevel(
|
|
421
|
+
normalizedScore,
|
|
422
|
+
assessPromiseStrength(params.expectation, [], policy),
|
|
423
|
+
assessEvidenceCompleteness(params.evidence || {}, params.sensors || {}, [], policy),
|
|
424
|
+
policy
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
score: normalizedScore,
|
|
429
|
+
level,
|
|
430
|
+
reasons,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Extract stable reason codes from legacy confidence result
|
|
436
|
+
*/
|
|
437
|
+
function extractReasonsFromLegacy(legacyResult, params) {
|
|
438
|
+
const reasons = [];
|
|
439
|
+
|
|
440
|
+
if (legacyResult.explain && Array.isArray(legacyResult.explain)) {
|
|
441
|
+
for (const explanation of legacyResult.explain) {
|
|
442
|
+
if (typeof explanation === 'string') {
|
|
443
|
+
if (explanation.includes('AST') || explanation.includes('proven')) {
|
|
444
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
|
|
445
|
+
}
|
|
446
|
+
if (explanation.includes('network') && explanation.includes('failed')) {
|
|
447
|
+
reasons.push(CONFIDENCE_REASON.OBS_NETWORK_FAILURE);
|
|
448
|
+
}
|
|
449
|
+
if (explanation.includes('UI feedback')) {
|
|
450
|
+
reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
|
|
451
|
+
}
|
|
452
|
+
if (explanation.includes('contradiction')) {
|
|
453
|
+
reasons.push(CONFIDENCE_REASON.GUARD_CONTRADICTION_DETECTED);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (legacyResult.factors && Array.isArray(legacyResult.factors)) {
|
|
460
|
+
for (const factor of legacyResult.factors) {
|
|
461
|
+
if (factor.key === 'promise_strength' && factor.value === 'PROVEN') {
|
|
462
|
+
reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
|
|
463
|
+
}
|
|
464
|
+
if (factor.key === 'ui_feedback_score' && parseFloat(factor.value) > 0.5) {
|
|
465
|
+
reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const sensors = params.sensors || {};
|
|
471
|
+
if (sensors.network && Object.keys(sensors.network).length > 0) {
|
|
472
|
+
reasons.push(CONFIDENCE_REASON.SENSOR_NETWORK_PRESENT);
|
|
473
|
+
}
|
|
474
|
+
if (sensors.console && Object.keys(sensors.console).length > 0) {
|
|
475
|
+
reasons.push(CONFIDENCE_REASON.SENSOR_CONSOLE_PRESENT);
|
|
476
|
+
}
|
|
477
|
+
if (sensors.uiSignals && Object.keys(sensors.uiSignals).length > 0) {
|
|
478
|
+
reasons.push(CONFIDENCE_REASON.SENSOR_UI_PRESENT);
|
|
479
|
+
}
|
|
480
|
+
if (sensors.uiFeedback && Object.keys(sensors.uiFeedback).length > 0) {
|
|
481
|
+
reasons.push(CONFIDENCE_REASON.SENSOR_UI_FEEDBACK_PRESENT);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return [...new Set(reasons)];
|
|
485
|
+
}
|
|
486
|
+
|