@veraxhq/verax 0.3.0 → 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 +28 -20
- package/bin/verax.js +11 -18
- package/package.json +28 -7
- package/src/cli/commands/baseline.js +1 -2
- package/src/cli/commands/default.js +72 -81
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +3 -0
- package/src/cli/commands/gates.js +1 -1
- package/src/cli/commands/inspect.js +6 -133
- package/src/cli/commands/release-check.js +2 -0
- package/src/cli/commands/run.js +74 -246
- package/src/cli/commands/security-check.js +2 -1
- package/src/cli/commands/truth.js +0 -1
- package/src/cli/entry.js +82 -309
- package/src/cli/util/angular-component-extractor.js +2 -2
- package/src/cli/util/angular-navigation-detector.js +2 -2
- package/src/cli/util/ast-interactive-detector.js +4 -6
- package/src/cli/util/ast-network-detector.js +3 -3
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +3 -3
- package/src/cli/util/atomic-write.js +12 -1
- 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 +2 -1
- package/src/cli/util/determinism-writer.js +1 -1
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/env-url.js +0 -4
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +217 -367
- package/src/cli/util/findings-writer.js +19 -126
- 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 -2
- 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 -2
- package/src/cli/util/paths.js +12 -3
- package/src/cli/util/project-discovery.js +284 -3
- package/src/cli/util/project-writer.js +2 -2
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/summary-writer.js +2 -1
- package/src/cli/util/svelte-navigation-detector.js +3 -3
- package/src/cli/util/svelte-sfc-extractor.js +0 -1
- package/src/cli/util/svelte-state-detector.js +1 -2
- 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 +4 -3
- package/src/cli/util/vue-sfc-extractor.js +1 -2
- package/src/cli/util/vue-state-detector.js +1 -1
- 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/finding-explainer.js +3 -56
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +0 -15
- package/src/verax/core/artifacts/verifier.js +18 -8
- package/src/verax/core/baseline/baseline.snapshot.js +2 -0
- package/src/verax/core/capabilities/gates.js +7 -1
- package/src/verax/core/confidence/confidence-compute.js +14 -7
- package/src/verax/core/confidence/confidence.loader.js +1 -0
- package/src/verax/core/confidence-engine-refactor.js +8 -3
- package/src/verax/core/confidence-engine.js +162 -23
- package/src/verax/core/contracts/types.js +1 -0
- package/src/verax/core/contracts/validators.js +79 -4
- package/src/verax/core/decision-snapshot.js +3 -30
- package/src/verax/core/decisions/decision.trace.js +2 -0
- package/src/verax/core/determinism/contract-writer.js +2 -2
- package/src/verax/core/determinism/contract.js +1 -1
- package/src/verax/core/determinism/diff.js +42 -1
- package/src/verax/core/determinism/engine.js +7 -6
- package/src/verax/core/determinism/finding-identity.js +3 -2
- package/src/verax/core/determinism/normalize.js +32 -4
- package/src/verax/core/determinism/report-writer.js +1 -0
- package/src/verax/core/determinism/run-fingerprint.js +7 -2
- package/src/verax/core/dynamic-route-intelligence.js +8 -7
- package/src/verax/core/evidence/evidence-capture-service.js +1 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +2 -1
- package/src/verax/core/evidence-builder.js +2 -2
- package/src/verax/core/execution-mode-context.js +1 -1
- package/src/verax/core/execution-mode-detector.js +5 -3
- package/src/verax/core/failures/exit-codes.js +39 -37
- package/src/verax/core/failures/failure-summary.js +1 -1
- package/src/verax/core/failures/failure.factory.js +3 -3
- package/src/verax/core/failures/failure.ledger.js +3 -2
- package/src/verax/core/ga/ga.artifact.js +1 -1
- package/src/verax/core/ga/ga.contract.js +3 -2
- package/src/verax/core/ga/ga.enforcer.js +1 -0
- package/src/verax/core/guardrails/policy.loader.js +1 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +1 -1
- package/src/verax/core/guardrails-engine.js +2 -2
- 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 +2 -0
- package/src/verax/core/perf/perf.report.js +2 -0
- package/src/verax/core/pipeline-tracker.js +5 -0
- package/src/verax/core/release/provenance.builder.js +73 -214
- package/src/verax/core/release/release.enforcer.js +14 -9
- package/src/verax/core/release/reproducibility.check.js +1 -0
- package/src/verax/core/release/sbom.builder.js +32 -23
- 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 +6 -3
- package/src/verax/core/report/human-summary.js +141 -1
- package/src/verax/core/route-intelligence.js +4 -3
- 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 +10 -7
- package/src/verax/core/security/security.enforcer.js +4 -0
- package/src/verax/core/security/supplychain.policy.js +9 -1
- package/src/verax/core/security/vuln.scan.js +2 -2
- package/src/verax/core/truth/truth.certificate.js +3 -1
- package/src/verax/core/ui-feedback-intelligence.js +12 -46
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +100 -660
- package/src/verax/detect/confidence-helper.js +1 -0
- package/src/verax/detect/detection-engine.js +1 -18
- package/src/verax/detect/dynamic-route-findings.js +17 -14
- package/src/verax/detect/expectation-chain-detector.js +1 -1
- package/src/verax/detect/expectation-model.js +3 -5
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +126 -166
- 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 +51 -234
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +4 -4
- 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 +7 -6
- 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 +18 -18
- package/src/verax/detect/verdict-engine.js +3 -57
- package/src/verax/detect/view-switch-correlator.js +2 -2
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +48 -412
- 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 +67 -682
- 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/route-validator.js +1 -4
- 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 +735 -84
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -530
- 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 +1 -1
- package/src/verax/observe/observe-helpers.js +2 -1
- package/src/verax/observe/observe-runner.js +28 -24
- package/src/verax/observe/observers/budget-observer.js +3 -3
- package/src/verax/observe/observers/console-observer.js +4 -4
- package/src/verax/observe/observers/coverage-observer.js +4 -4
- package/src/verax/observe/observers/interaction-observer.js +3 -3
- package/src/verax/observe/observers/navigation-observer.js +4 -4
- package/src/verax/observe/observers/network-observer.js +4 -4
- package/src/verax/observe/observers/safety-observer.js +1 -1
- package/src/verax/observe/observers/ui-feedback-observer.js +4 -4
- package/src/verax/observe/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-signal-sensor.js +2 -148
- package/src/verax/scan-summary-writer.js +10 -42
- package/src/verax/shared/artifact-manager.js +30 -13
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/core/confidence-engine.js.backup +0 -471
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PHASE 15 — Unified Confidence System
|
|
3
|
-
*
|
|
4
|
-
* Central confidence engine that computes:
|
|
5
|
-
* - confidenceScore (0..1)
|
|
6
|
-
* - confidenceLevel (HIGH/MEDIUM/LOW/UNPROVEN)
|
|
7
|
-
* - confidenceReasons (list of stable reason codes)
|
|
8
|
-
*
|
|
9
|
-
* Based on five pillars:
|
|
10
|
-
* A) Promise strength (AST-based promise, strong vs weak inference)
|
|
11
|
-
* B) Observation strength (URL change, DOM change, UI feedback confirmed, console errors, network outcomes)
|
|
12
|
-
* C) Correlation quality (timing alignment, matched request/route, trace linkage)
|
|
13
|
-
* D) Guardrails & contradictions (analytics filtered, shallow routing, network success + no UI change, etc.)
|
|
14
|
-
* E) Evidence completeness (before/after screenshots, traces, signals, snippets)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { computeConfidence as computeConfidenceLegacy } from '../detect/confidence-engine.js';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* PHASE 15: Confidence Levels
|
|
21
|
-
*/
|
|
22
|
-
export const CONFIDENCE_LEVEL = {
|
|
23
|
-
HIGH: 'HIGH',
|
|
24
|
-
MEDIUM: 'MEDIUM',
|
|
25
|
-
LOW: 'LOW',
|
|
26
|
-
UNPROVEN: 'UNPROVEN',
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* PHASE 15: Stable Reason Codes
|
|
31
|
-
*/
|
|
32
|
-
export const CONFIDENCE_REASON = {
|
|
33
|
-
// Promise Strength (A)
|
|
34
|
-
PROMISE_AST_BASED: 'PROMISE_AST_BASED',
|
|
35
|
-
PROMISE_PROVEN: 'PROMISE_PROVEN',
|
|
36
|
-
PROMISE_OBSERVED: 'PROMISE_OBSERVED',
|
|
37
|
-
PROMISE_WEAK: 'PROMISE_WEAK',
|
|
38
|
-
PROMISE_UNKNOWN: 'PROMISE_UNKNOWN',
|
|
39
|
-
|
|
40
|
-
// Observation Strength (B)
|
|
41
|
-
OBS_URL_CHANGED: 'OBS_URL_CHANGED',
|
|
42
|
-
OBS_DOM_CHANGED: 'OBS_DOM_CHANGED',
|
|
43
|
-
OBS_UI_FEEDBACK_CONFIRMED: 'OBS_UI_FEEDBACK_CONFIRMED',
|
|
44
|
-
OBS_CONSOLE_ERRORS: 'OBS_CONSOLE_ERRORS',
|
|
45
|
-
OBS_NETWORK_FAILURE: 'OBS_NETWORK_FAILURE',
|
|
46
|
-
OBS_NETWORK_SUCCESS: 'OBS_NETWORK_SUCCESS',
|
|
47
|
-
OBS_NO_SIGNALS: 'OBS_NO_SIGNALS',
|
|
48
|
-
|
|
49
|
-
// Correlation Quality (C)
|
|
50
|
-
CORR_TIMING_ALIGNED: 'CORR_TIMING_ALIGNED',
|
|
51
|
-
CORR_ROUTE_MATCHED: 'CORR_ROUTE_MATCHED',
|
|
52
|
-
CORR_REQUEST_MATCHED: 'CORR_REQUEST_MATCHED',
|
|
53
|
-
CORR_TRACE_LINKED: 'CORR_TRACE_LINKED',
|
|
54
|
-
CORR_WEAK_CORRELATION: 'CORR_WEAK_CORRELATION',
|
|
55
|
-
|
|
56
|
-
// Guardrails & Contradictions (D)
|
|
57
|
-
GUARD_ANALYTICS_FILTERED: 'GUARD_ANALYTICS_FILTERED',
|
|
58
|
-
GUARD_SHALLOW_ROUTING: 'GUARD_SHALLOW_ROUTING',
|
|
59
|
-
GUARD_NETWORK_SUCCESS_NO_UI: 'GUARD_NETWORK_SUCCESS_NO_UI',
|
|
60
|
-
GUARD_UI_FEEDBACK_PRESENT: 'GUARD_UI_FEEDBACK_PRESENT',
|
|
61
|
-
GUARD_CONTRADICTION_DETECTED: 'GUARD_CONTRADICTION_DETECTED',
|
|
62
|
-
|
|
63
|
-
// Evidence Completeness (E)
|
|
64
|
-
EVIDENCE_SCREENSHOTS: 'EVIDENCE_SCREENSHOTS',
|
|
65
|
-
EVIDENCE_TRACES: 'EVIDENCE_TRACES',
|
|
66
|
-
EVIDENCE_SIGNALS: 'EVIDENCE_SIGNALS',
|
|
67
|
-
EVIDENCE_SNIPPETS: 'EVIDENCE_SNIPPETS',
|
|
68
|
-
EVIDENCE_INCOMPLETE: 'EVIDENCE_INCOMPLETE',
|
|
69
|
-
|
|
70
|
-
// Sensor Presence
|
|
71
|
-
SENSOR_NETWORK_PRESENT: 'SENSOR_NETWORK_PRESENT',
|
|
72
|
-
SENSOR_CONSOLE_PRESENT: 'SENSOR_CONSOLE_PRESENT',
|
|
73
|
-
SENSOR_UI_PRESENT: 'SENSOR_UI_PRESENT',
|
|
74
|
-
SENSOR_UI_FEEDBACK_PRESENT: 'SENSOR_UI_FEEDBACK_PRESENT',
|
|
75
|
-
SENSOR_MISSING: 'SENSOR_MISSING',
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* PHASE 15: Compute unified confidence
|
|
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
|
-
* @returns {Object} { score, level, reasons[] }
|
|
88
|
-
*/
|
|
89
|
-
export function computeUnifiedConfidence({ findingType, expectation, sensors = {}, comparisons = {}, evidence = {} }) {
|
|
90
|
-
const reasons = [];
|
|
91
|
-
|
|
92
|
-
// === PILLAR A: Promise Strength ===
|
|
93
|
-
const promiseStrength = assessPromiseStrength(expectation, reasons);
|
|
94
|
-
|
|
95
|
-
// === PILLAR B: Observation Strength ===
|
|
96
|
-
const observationStrength = assessObservationStrength(sensors, comparisons, reasons);
|
|
97
|
-
|
|
98
|
-
// === PILLAR C: Correlation Quality ===
|
|
99
|
-
const correlationQuality = assessCorrelationQuality(expectation, sensors, comparisons, evidence, reasons);
|
|
100
|
-
|
|
101
|
-
// === PILLAR D: Guardrails & Contradictions ===
|
|
102
|
-
const guardrails = assessGuardrails(sensors, comparisons, findingType, reasons);
|
|
103
|
-
|
|
104
|
-
// === PILLAR E: Evidence Completeness ===
|
|
105
|
-
const evidenceCompleteness = assessEvidenceCompleteness(evidence, sensors, reasons);
|
|
106
|
-
|
|
107
|
-
// === COMPUTE BASE SCORE ===
|
|
108
|
-
// Weighted combination of pillars
|
|
109
|
-
const baseScore = (
|
|
110
|
-
promiseStrength * 0.25 + // 25% weight
|
|
111
|
-
observationStrength * 0.30 + // 30% weight
|
|
112
|
-
correlationQuality * 0.20 + // 20% weight
|
|
113
|
-
guardrails * 0.15 + // 15% weight
|
|
114
|
-
evidenceCompleteness * 0.10 // 10% weight
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
// === APPLY CONTRADICTIONS ===
|
|
118
|
-
const contradictionPenalty = guardrails < 0.5 ? 0.3 : 0;
|
|
119
|
-
const finalScore = Math.max(0, Math.min(1, baseScore - contradictionPenalty));
|
|
120
|
-
|
|
121
|
-
// === DETERMINE LEVEL ===
|
|
122
|
-
const level = determineConfidenceLevel(finalScore, promiseStrength, evidenceCompleteness);
|
|
123
|
-
|
|
124
|
-
return {
|
|
125
|
-
score: finalScore,
|
|
126
|
-
level,
|
|
127
|
-
reasons: reasons.slice(0, 10), // Limit to top 10 reasons
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Assess promise strength (Pillar A)
|
|
133
|
-
*/
|
|
134
|
-
function assessPromiseStrength(expectation, reasons) {
|
|
135
|
-
if (!expectation) {
|
|
136
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_UNKNOWN);
|
|
137
|
-
return 0.0;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Check if AST-based
|
|
141
|
-
const isASTBased = expectation.source?.astSource || expectation.metadata?.astSource;
|
|
142
|
-
if (isASTBased) {
|
|
143
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_AST_BASED);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Check expectation strength
|
|
147
|
-
const proof = expectation.proof || 'UNKNOWN';
|
|
148
|
-
if (proof === 'PROVEN_EXPECTATION' || proof === 'PROVEN') {
|
|
149
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
|
|
150
|
-
return 1.0;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (proof === 'OBSERVED' || expectation.confidence >= 0.8) {
|
|
154
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_OBSERVED);
|
|
155
|
-
return 0.7;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (expectation.confidence >= 0.5) {
|
|
159
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_WEAK);
|
|
160
|
-
return 0.5;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_UNKNOWN);
|
|
164
|
-
return 0.2;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Assess observation strength (Pillar B)
|
|
169
|
-
*/
|
|
170
|
-
function assessObservationStrength(sensors, comparisons, reasons) {
|
|
171
|
-
let strength = 0.0;
|
|
172
|
-
let signals = 0;
|
|
173
|
-
|
|
174
|
-
// URL change
|
|
175
|
-
const urlChanged = sensors.navigation?.urlChanged === true ||
|
|
176
|
-
comparisons.urlChanged === true;
|
|
177
|
-
if (urlChanged) {
|
|
178
|
-
reasons.push(CONFIDENCE_REASON.OBS_URL_CHANGED);
|
|
179
|
-
strength += 0.3;
|
|
180
|
-
signals++;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// DOM change
|
|
184
|
-
const domChanged = sensors.dom?.changed === true ||
|
|
185
|
-
comparisons.domChanged === true;
|
|
186
|
-
if (domChanged) {
|
|
187
|
-
reasons.push(CONFIDENCE_REASON.OBS_DOM_CHANGED);
|
|
188
|
-
strength += 0.2;
|
|
189
|
-
signals++;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// UI feedback confirmed
|
|
193
|
-
const uiFeedback = sensors.uiFeedback || {};
|
|
194
|
-
const uiFeedbackScore = uiFeedback.overallUiFeedbackScore || 0;
|
|
195
|
-
if (uiFeedbackScore > 0.5) {
|
|
196
|
-
reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
|
|
197
|
-
strength += 0.3;
|
|
198
|
-
signals++;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Console errors
|
|
202
|
-
const consoleErrors = sensors.console?.errors > 0 ||
|
|
203
|
-
sensors.console?.errorCount > 0;
|
|
204
|
-
if (consoleErrors) {
|
|
205
|
-
reasons.push(CONFIDENCE_REASON.OBS_CONSOLE_ERRORS);
|
|
206
|
-
strength += 0.2;
|
|
207
|
-
signals++;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Network failure
|
|
211
|
-
const networkFailure = sensors.network?.failedRequests > 0 ||
|
|
212
|
-
sensors.network?.topFailedUrls?.length > 0;
|
|
213
|
-
if (networkFailure) {
|
|
214
|
-
reasons.push(CONFIDENCE_REASON.OBS_NETWORK_FAILURE);
|
|
215
|
-
strength += 0.3;
|
|
216
|
-
signals++;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Network success
|
|
220
|
-
const networkSuccess = sensors.network?.successfulRequests > 0 &&
|
|
221
|
-
!networkFailure;
|
|
222
|
-
if (networkSuccess) {
|
|
223
|
-
reasons.push(CONFIDENCE_REASON.OBS_NETWORK_SUCCESS);
|
|
224
|
-
strength += 0.1;
|
|
225
|
-
signals++;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// No signals
|
|
229
|
-
if (signals === 0) {
|
|
230
|
-
reasons.push(CONFIDENCE_REASON.OBS_NO_SIGNALS);
|
|
231
|
-
return 0.0;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return Math.min(1.0, strength);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Assess correlation quality (Pillar C)
|
|
239
|
-
*/
|
|
240
|
-
function assessCorrelationQuality(expectation, sensors, comparisons, evidence, reasons) {
|
|
241
|
-
let quality = 0.5; // Base correlation
|
|
242
|
-
|
|
243
|
-
// Timing alignment (if trace timing is available)
|
|
244
|
-
if (evidence.timing || sensors.timing) {
|
|
245
|
-
reasons.push(CONFIDENCE_REASON.CORR_TIMING_ALIGNED);
|
|
246
|
-
quality += 0.2;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Route matched
|
|
250
|
-
if (evidence.correlation?.routeMatched === true ||
|
|
251
|
-
evidence.routeDefinition?.path) {
|
|
252
|
-
reasons.push(CONFIDENCE_REASON.CORR_ROUTE_MATCHED);
|
|
253
|
-
quality += 0.2;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Request matched
|
|
257
|
-
if (evidence.networkRequest?.matched === true ||
|
|
258
|
-
evidence.correlation?.requestMatched === true) {
|
|
259
|
-
reasons.push(CONFIDENCE_REASON.CORR_REQUEST_MATCHED);
|
|
260
|
-
quality += 0.2;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Trace linked
|
|
264
|
-
if (evidence.traceId || evidence.source?.file) {
|
|
265
|
-
reasons.push(CONFIDENCE_REASON.CORR_TRACE_LINKED);
|
|
266
|
-
quality += 0.1;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Weak correlation
|
|
270
|
-
if (quality < 0.6) {
|
|
271
|
-
reasons.push(CONFIDENCE_REASON.CORR_WEAK_CORRELATION);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return Math.min(1.0, quality);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Assess guardrails & contradictions (Pillar D)
|
|
279
|
-
*/
|
|
280
|
-
function assessGuardrails(sensors, comparisons, findingType, reasons) {
|
|
281
|
-
let guardrailScore = 1.0; // Start at full score
|
|
282
|
-
|
|
283
|
-
// Analytics filtered
|
|
284
|
-
const networkSensor = sensors.network || {};
|
|
285
|
-
const hasAnalytics = networkSensor.observedRequestUrls?.some(url =>
|
|
286
|
-
url && typeof url === 'string' && url.includes('/api/analytics')
|
|
287
|
-
);
|
|
288
|
-
if (hasAnalytics && !sensors.navigation?.urlChanged && !sensors.uiSignals?.diff?.changed) {
|
|
289
|
-
reasons.push(CONFIDENCE_REASON.GUARD_ANALYTICS_FILTERED);
|
|
290
|
-
guardrailScore -= 0.2;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Shallow routing
|
|
294
|
-
if (sensors.navigation?.shallowRouting === true && !sensors.navigation?.urlChanged) {
|
|
295
|
-
reasons.push(CONFIDENCE_REASON.GUARD_SHALLOW_ROUTING);
|
|
296
|
-
guardrailScore -= 0.3;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Network success but no UI change
|
|
300
|
-
const networkSuccess = networkSensor.successfulRequests > 0;
|
|
301
|
-
const noUIChange = !sensors.uiSignals?.diff?.changed &&
|
|
302
|
-
!sensors.uiFeedback?.overallUiFeedbackScore;
|
|
303
|
-
if (networkSuccess && noUIChange && findingType?.includes('silent_failure')) {
|
|
304
|
-
reasons.push(CONFIDENCE_REASON.GUARD_NETWORK_SUCCESS_NO_UI);
|
|
305
|
-
guardrailScore -= 0.2;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// UI feedback present (contradicts silent failure)
|
|
309
|
-
const uiFeedbackScore = sensors.uiFeedback?.overallUiFeedbackScore || 0;
|
|
310
|
-
if (uiFeedbackScore > 0.5 && findingType?.includes('silent_failure')) {
|
|
311
|
-
reasons.push(CONFIDENCE_REASON.GUARD_UI_FEEDBACK_PRESENT);
|
|
312
|
-
guardrailScore -= 0.4;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Contradiction detected
|
|
316
|
-
if (guardrailScore < 0.6) {
|
|
317
|
-
reasons.push(CONFIDENCE_REASON.GUARD_CONTRADICTION_DETECTED);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return Math.max(0.0, guardrailScore);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Assess evidence completeness (Pillar E)
|
|
325
|
-
*/
|
|
326
|
-
function assessEvidenceCompleteness(evidence, sensors, reasons) {
|
|
327
|
-
let completeness = 0.0;
|
|
328
|
-
|
|
329
|
-
// Screenshots
|
|
330
|
-
if (evidence.beforeAfter?.beforeScreenshot && evidence.beforeAfter?.afterScreenshot) {
|
|
331
|
-
reasons.push(CONFIDENCE_REASON.EVIDENCE_SCREENSHOTS);
|
|
332
|
-
completeness += 0.3;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Traces
|
|
336
|
-
if (evidence.traceId || sensors.traceId) {
|
|
337
|
-
reasons.push(CONFIDENCE_REASON.EVIDENCE_TRACES);
|
|
338
|
-
completeness += 0.2;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Signals
|
|
342
|
-
if (evidence.signals && Object.keys(evidence.signals).length > 0) {
|
|
343
|
-
reasons.push(CONFIDENCE_REASON.EVIDENCE_SIGNALS);
|
|
344
|
-
completeness += 0.2;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Snippets (AST source)
|
|
348
|
-
if (evidence.source?.astSource || evidence.navigationTrigger?.astSource) {
|
|
349
|
-
reasons.push(CONFIDENCE_REASON.EVIDENCE_SNIPPETS);
|
|
350
|
-
completeness += 0.3;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Incomplete
|
|
354
|
-
if (completeness < 0.5) {
|
|
355
|
-
reasons.push(CONFIDENCE_REASON.EVIDENCE_INCOMPLETE);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return completeness;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Determine confidence level
|
|
363
|
-
*/
|
|
364
|
-
function determineConfidenceLevel(score, promiseStrength, evidenceCompleteness) {
|
|
365
|
-
// HIGH: score >= 0.8 AND promise is proven AND evidence is complete
|
|
366
|
-
if (score >= 0.8 && promiseStrength >= 0.9 && evidenceCompleteness >= 0.7) {
|
|
367
|
-
return CONFIDENCE_LEVEL.HIGH;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// MEDIUM: score >= 0.6 OR (score >= 0.5 AND promise is observed)
|
|
371
|
-
if (score >= 0.6 || (score >= 0.5 && promiseStrength >= 0.7)) {
|
|
372
|
-
return CONFIDENCE_LEVEL.MEDIUM;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// LOW: score >= 0.3
|
|
376
|
-
if (score >= 0.3) {
|
|
377
|
-
return CONFIDENCE_LEVEL.LOW;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// UNPROVEN: score < 0.3
|
|
381
|
-
return CONFIDENCE_LEVEL.UNPROVEN;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* PHASE 15: Compute confidence for finding (wrapper that integrates with legacy system)
|
|
386
|
-
*
|
|
387
|
-
* @param {Object} params - Confidence computation parameters
|
|
388
|
-
* @returns {Object} { score, level, reasons[] }
|
|
389
|
-
*/
|
|
390
|
-
export function computeConfidenceForFinding(params) {
|
|
391
|
-
// Use legacy system for base computation
|
|
392
|
-
const legacyResult = computeConfidenceLegacy(params);
|
|
393
|
-
|
|
394
|
-
// Normalize score from 0-100 to 0-1
|
|
395
|
-
const normalizedScore = (legacyResult.score || 0) / 100;
|
|
396
|
-
|
|
397
|
-
// Extract reasons from legacy explain/factors
|
|
398
|
-
const reasons = extractReasonsFromLegacy(legacyResult, params);
|
|
399
|
-
|
|
400
|
-
// Determine level
|
|
401
|
-
const level = determineConfidenceLevel(
|
|
402
|
-
normalizedScore,
|
|
403
|
-
assessPromiseStrength(params.expectation, []),
|
|
404
|
-
assessEvidenceCompleteness(params.evidence || {}, params.sensors || {}, [])
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
return {
|
|
408
|
-
score: normalizedScore,
|
|
409
|
-
level,
|
|
410
|
-
reasons,
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Extract stable reason codes from legacy confidence result
|
|
416
|
-
*/
|
|
417
|
-
function extractReasonsFromLegacy(legacyResult, params) {
|
|
418
|
-
const reasons = [];
|
|
419
|
-
|
|
420
|
-
// Extract from explain array
|
|
421
|
-
if (legacyResult.explain && Array.isArray(legacyResult.explain)) {
|
|
422
|
-
for (const explanation of legacyResult.explain) {
|
|
423
|
-
if (typeof explanation === 'string') {
|
|
424
|
-
// Map explanation strings to reason codes
|
|
425
|
-
if (explanation.includes('AST') || explanation.includes('proven')) {
|
|
426
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
|
|
427
|
-
}
|
|
428
|
-
if (explanation.includes('network') && explanation.includes('failed')) {
|
|
429
|
-
reasons.push(CONFIDENCE_REASON.OBS_NETWORK_FAILURE);
|
|
430
|
-
}
|
|
431
|
-
if (explanation.includes('UI feedback')) {
|
|
432
|
-
reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
|
|
433
|
-
}
|
|
434
|
-
if (explanation.includes('contradiction')) {
|
|
435
|
-
reasons.push(CONFIDENCE_REASON.GUARD_CONTRADICTION_DETECTED);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Extract from factors
|
|
442
|
-
if (legacyResult.factors && Array.isArray(legacyResult.factors)) {
|
|
443
|
-
for (const factor of legacyResult.factors) {
|
|
444
|
-
if (factor.key === 'promise_strength' && factor.value === 'PROVEN') {
|
|
445
|
-
reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
|
|
446
|
-
}
|
|
447
|
-
if (factor.key === 'ui_feedback_score' && parseFloat(factor.value) > 0.5) {
|
|
448
|
-
reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// Add sensor presence reasons
|
|
454
|
-
const sensors = params.sensors || {};
|
|
455
|
-
if (sensors.network && Object.keys(sensors.network).length > 0) {
|
|
456
|
-
reasons.push(CONFIDENCE_REASON.SENSOR_NETWORK_PRESENT);
|
|
457
|
-
}
|
|
458
|
-
if (sensors.console && Object.keys(sensors.console).length > 0) {
|
|
459
|
-
reasons.push(CONFIDENCE_REASON.SENSOR_CONSOLE_PRESENT);
|
|
460
|
-
}
|
|
461
|
-
if (sensors.uiSignals && Object.keys(sensors.uiSignals).length > 0) {
|
|
462
|
-
reasons.push(CONFIDENCE_REASON.SENSOR_UI_PRESENT);
|
|
463
|
-
}
|
|
464
|
-
if (sensors.uiFeedback && Object.keys(sensors.uiFeedback).length > 0) {
|
|
465
|
-
reasons.push(CONFIDENCE_REASON.SENSOR_UI_FEEDBACK_PRESENT);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// Deduplicate
|
|
469
|
-
return [...new Set(reasons)];
|
|
470
|
-
}
|
|
471
|
-
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wave 7 — Config File Support
|
|
3
|
-
*
|
|
4
|
-
* Loads and validates .verax/config.json configuration file.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { readFileSync, existsSync } from 'fs';
|
|
8
|
-
import { resolve } from 'path';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Default config values
|
|
12
|
-
*/
|
|
13
|
-
const DEFAULT_CONFIG = {
|
|
14
|
-
defaultUrl: 'http://localhost:3000',
|
|
15
|
-
projectRoot: '.',
|
|
16
|
-
outDir: '.verax/runs',
|
|
17
|
-
ciDefaults: {
|
|
18
|
-
json: true,
|
|
19
|
-
zip: true,
|
|
20
|
-
explain: false
|
|
21
|
-
},
|
|
22
|
-
safety: {
|
|
23
|
-
allowlistDomains: [],
|
|
24
|
-
denyKeywords: ['delete', 'remove', 'billing', 'payment']
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Validate config structure
|
|
30
|
-
* @param {Object} config - Config object to validate
|
|
31
|
-
* @returns {Object} { valid: boolean, errors: string[] }
|
|
32
|
-
*/
|
|
33
|
-
export function validateConfig(config) {
|
|
34
|
-
const errors = [];
|
|
35
|
-
|
|
36
|
-
if (typeof config !== 'object' || config === null) {
|
|
37
|
-
errors.push('Config must be an object');
|
|
38
|
-
return { valid: false, errors };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Validate defaultUrl
|
|
42
|
-
if (config.defaultUrl !== undefined) {
|
|
43
|
-
if (typeof config.defaultUrl !== 'string' || config.defaultUrl.trim() === '') {
|
|
44
|
-
errors.push('defaultUrl must be a non-empty string');
|
|
45
|
-
} else {
|
|
46
|
-
try {
|
|
47
|
-
new URL(config.defaultUrl);
|
|
48
|
-
} catch (e) {
|
|
49
|
-
errors.push(`defaultUrl is not a valid URL: ${config.defaultUrl}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Validate projectRoot
|
|
55
|
-
if (config.projectRoot !== undefined && typeof config.projectRoot !== 'string') {
|
|
56
|
-
errors.push('projectRoot must be a string');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Validate outDir
|
|
60
|
-
if (config.outDir !== undefined && typeof config.outDir !== 'string') {
|
|
61
|
-
errors.push('outDir must be a string');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Validate ciDefaults
|
|
65
|
-
if (config.ciDefaults !== undefined) {
|
|
66
|
-
if (typeof config.ciDefaults !== 'object' || config.ciDefaults === null) {
|
|
67
|
-
errors.push('ciDefaults must be an object');
|
|
68
|
-
} else {
|
|
69
|
-
if (config.ciDefaults.json !== undefined && typeof config.ciDefaults.json !== 'boolean') {
|
|
70
|
-
errors.push('ciDefaults.json must be a boolean');
|
|
71
|
-
}
|
|
72
|
-
if (config.ciDefaults.zip !== undefined && typeof config.ciDefaults.zip !== 'boolean') {
|
|
73
|
-
errors.push('ciDefaults.zip must be a boolean');
|
|
74
|
-
}
|
|
75
|
-
if (config.ciDefaults.explain !== undefined && typeof config.ciDefaults.explain !== 'boolean') {
|
|
76
|
-
errors.push('ciDefaults.explain must be a boolean');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Validate safety
|
|
82
|
-
if (config.safety !== undefined) {
|
|
83
|
-
if (typeof config.safety !== 'object' || config.safety === null) {
|
|
84
|
-
errors.push('safety must be an object');
|
|
85
|
-
} else {
|
|
86
|
-
if (config.safety.allowlistDomains !== undefined) {
|
|
87
|
-
if (!Array.isArray(config.safety.allowlistDomains)) {
|
|
88
|
-
errors.push('safety.allowlistDomains must be an array');
|
|
89
|
-
} else {
|
|
90
|
-
for (const domain of config.safety.allowlistDomains) {
|
|
91
|
-
if (typeof domain !== 'string') {
|
|
92
|
-
errors.push('safety.allowlistDomains must contain only strings');
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (config.safety.denyKeywords !== undefined) {
|
|
99
|
-
if (!Array.isArray(config.safety.denyKeywords)) {
|
|
100
|
-
errors.push('safety.denyKeywords must be an array');
|
|
101
|
-
} else {
|
|
102
|
-
for (const keyword of config.safety.denyKeywords) {
|
|
103
|
-
if (typeof keyword !== 'string') {
|
|
104
|
-
errors.push('safety.denyKeywords must contain only strings');
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
valid: errors.length === 0,
|
|
115
|
-
errors
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Load config file from project directory
|
|
121
|
-
* @param {string} projectRoot - Project root directory
|
|
122
|
-
* @returns {Object|null} Config object or null if not found
|
|
123
|
-
* @throws {Error} If config file exists but is invalid
|
|
124
|
-
*/
|
|
125
|
-
export function loadConfig(projectRoot) {
|
|
126
|
-
const configPath = resolve(projectRoot, '.verax', 'config.json');
|
|
127
|
-
|
|
128
|
-
if (!existsSync(configPath)) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const content = readFileSync(configPath, 'utf-8');
|
|
134
|
-
const config = JSON.parse(content);
|
|
135
|
-
|
|
136
|
-
const validation = validateConfig(config);
|
|
137
|
-
if (!validation.valid) {
|
|
138
|
-
throw new Error(`Invalid config file: ${validation.errors.join(', ')}`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Merge with defaults
|
|
142
|
-
return {
|
|
143
|
-
...DEFAULT_CONFIG,
|
|
144
|
-
...config,
|
|
145
|
-
ciDefaults: {
|
|
146
|
-
...DEFAULT_CONFIG.ciDefaults,
|
|
147
|
-
...(config.ciDefaults || {})
|
|
148
|
-
},
|
|
149
|
-
safety: {
|
|
150
|
-
...DEFAULT_CONFIG.safety,
|
|
151
|
-
...(config.safety || {})
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
} catch (error) {
|
|
155
|
-
if (error instanceof SyntaxError) {
|
|
156
|
-
throw new Error(`Config file is not valid JSON: ${error.message}`);
|
|
157
|
-
}
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get default config (for init)
|
|
164
|
-
* @returns {Object} Default config object
|
|
165
|
-
*/
|
|
166
|
-
export function getDefaultConfig() {
|
|
167
|
-
return JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
168
|
-
}
|
|
169
|
-
|
|
File without changes
|