@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.
Files changed (191) hide show
  1. package/README.md +28 -20
  2. package/bin/verax.js +11 -18
  3. package/package.json +28 -7
  4. package/src/cli/commands/baseline.js +1 -2
  5. package/src/cli/commands/default.js +72 -81
  6. package/src/cli/commands/doctor.js +29 -0
  7. package/src/cli/commands/ga.js +3 -0
  8. package/src/cli/commands/gates.js +1 -1
  9. package/src/cli/commands/inspect.js +6 -133
  10. package/src/cli/commands/release-check.js +2 -0
  11. package/src/cli/commands/run.js +74 -246
  12. package/src/cli/commands/security-check.js +2 -1
  13. package/src/cli/commands/truth.js +0 -1
  14. package/src/cli/entry.js +82 -309
  15. package/src/cli/util/angular-component-extractor.js +2 -2
  16. package/src/cli/util/angular-navigation-detector.js +2 -2
  17. package/src/cli/util/ast-interactive-detector.js +4 -6
  18. package/src/cli/util/ast-network-detector.js +3 -3
  19. package/src/cli/util/ast-promise-extractor.js +581 -0
  20. package/src/cli/util/ast-usestate-detector.js +3 -3
  21. package/src/cli/util/atomic-write.js +12 -1
  22. package/src/cli/util/console-reporter.js +72 -0
  23. package/src/cli/util/detection-engine.js +105 -41
  24. package/src/cli/util/determinism-runner.js +2 -1
  25. package/src/cli/util/determinism-writer.js +1 -1
  26. package/src/cli/util/digest-engine.js +359 -0
  27. package/src/cli/util/dom-diff.js +226 -0
  28. package/src/cli/util/env-url.js +0 -4
  29. package/src/cli/util/evidence-engine.js +287 -0
  30. package/src/cli/util/expectation-extractor.js +217 -367
  31. package/src/cli/util/findings-writer.js +19 -126
  32. package/src/cli/util/framework-detector.js +572 -0
  33. package/src/cli/util/idgen.js +1 -1
  34. package/src/cli/util/interaction-planner.js +529 -0
  35. package/src/cli/util/learn-writer.js +2 -2
  36. package/src/cli/util/ledger-writer.js +110 -0
  37. package/src/cli/util/monorepo-resolver.js +162 -0
  38. package/src/cli/util/observation-engine.js +127 -278
  39. package/src/cli/util/observe-writer.js +2 -2
  40. package/src/cli/util/paths.js +12 -3
  41. package/src/cli/util/project-discovery.js +284 -3
  42. package/src/cli/util/project-writer.js +2 -2
  43. package/src/cli/util/run-id.js +23 -27
  44. package/src/cli/util/run-result.js +778 -0
  45. package/src/cli/util/selector-resolver.js +235 -0
  46. package/src/cli/util/summary-writer.js +2 -1
  47. package/src/cli/util/svelte-navigation-detector.js +3 -3
  48. package/src/cli/util/svelte-sfc-extractor.js +0 -1
  49. package/src/cli/util/svelte-state-detector.js +1 -2
  50. package/src/cli/util/trust-activation-integration.js +496 -0
  51. package/src/cli/util/trust-activation-wrapper.js +85 -0
  52. package/src/cli/util/trust-integration-hooks.js +164 -0
  53. package/src/cli/util/types.js +153 -0
  54. package/src/cli/util/url-validation.js +40 -0
  55. package/src/cli/util/vue-navigation-detector.js +4 -3
  56. package/src/cli/util/vue-sfc-extractor.js +1 -2
  57. package/src/cli/util/vue-state-detector.js +1 -1
  58. package/src/types/fs-augment.d.ts +23 -0
  59. package/src/types/global.d.ts +137 -0
  60. package/src/types/internal-types.d.ts +35 -0
  61. package/src/verax/cli/finding-explainer.js +3 -56
  62. package/src/verax/cli/init.js +4 -18
  63. package/src/verax/core/action-classifier.js +4 -3
  64. package/src/verax/core/artifacts/registry.js +0 -15
  65. package/src/verax/core/artifacts/verifier.js +18 -8
  66. package/src/verax/core/baseline/baseline.snapshot.js +2 -0
  67. package/src/verax/core/capabilities/gates.js +7 -1
  68. package/src/verax/core/confidence/confidence-compute.js +14 -7
  69. package/src/verax/core/confidence/confidence.loader.js +1 -0
  70. package/src/verax/core/confidence-engine-refactor.js +8 -3
  71. package/src/verax/core/confidence-engine.js +162 -23
  72. package/src/verax/core/contracts/types.js +1 -0
  73. package/src/verax/core/contracts/validators.js +79 -4
  74. package/src/verax/core/decision-snapshot.js +3 -30
  75. package/src/verax/core/decisions/decision.trace.js +2 -0
  76. package/src/verax/core/determinism/contract-writer.js +2 -2
  77. package/src/verax/core/determinism/contract.js +1 -1
  78. package/src/verax/core/determinism/diff.js +42 -1
  79. package/src/verax/core/determinism/engine.js +7 -6
  80. package/src/verax/core/determinism/finding-identity.js +3 -2
  81. package/src/verax/core/determinism/normalize.js +32 -4
  82. package/src/verax/core/determinism/report-writer.js +1 -0
  83. package/src/verax/core/determinism/run-fingerprint.js +7 -2
  84. package/src/verax/core/dynamic-route-intelligence.js +8 -7
  85. package/src/verax/core/evidence/evidence-capture-service.js +1 -0
  86. package/src/verax/core/evidence/evidence-intent-ledger.js +2 -1
  87. package/src/verax/core/evidence-builder.js +2 -2
  88. package/src/verax/core/execution-mode-context.js +1 -1
  89. package/src/verax/core/execution-mode-detector.js +5 -3
  90. package/src/verax/core/failures/exit-codes.js +39 -37
  91. package/src/verax/core/failures/failure-summary.js +1 -1
  92. package/src/verax/core/failures/failure.factory.js +3 -3
  93. package/src/verax/core/failures/failure.ledger.js +3 -2
  94. package/src/verax/core/ga/ga.artifact.js +1 -1
  95. package/src/verax/core/ga/ga.contract.js +3 -2
  96. package/src/verax/core/ga/ga.enforcer.js +1 -0
  97. package/src/verax/core/guardrails/policy.loader.js +1 -0
  98. package/src/verax/core/guardrails/truth-reconciliation.js +1 -1
  99. package/src/verax/core/guardrails-engine.js +2 -2
  100. package/src/verax/core/incremental-store.js +1 -0
  101. package/src/verax/core/integrity/budget.js +138 -0
  102. package/src/verax/core/integrity/determinism.js +342 -0
  103. package/src/verax/core/integrity/integrity.js +208 -0
  104. package/src/verax/core/integrity/poisoning.js +108 -0
  105. package/src/verax/core/integrity/transaction.js +140 -0
  106. package/src/verax/core/observe/run-timeline.js +2 -0
  107. package/src/verax/core/perf/perf.report.js +2 -0
  108. package/src/verax/core/pipeline-tracker.js +5 -0
  109. package/src/verax/core/release/provenance.builder.js +73 -214
  110. package/src/verax/core/release/release.enforcer.js +14 -9
  111. package/src/verax/core/release/reproducibility.check.js +1 -0
  112. package/src/verax/core/release/sbom.builder.js +32 -23
  113. package/src/verax/core/replay-validator.js +2 -0
  114. package/src/verax/core/replay.js +4 -0
  115. package/src/verax/core/report/cross-index.js +6 -3
  116. package/src/verax/core/report/human-summary.js +141 -1
  117. package/src/verax/core/route-intelligence.js +4 -3
  118. package/src/verax/core/run-id.js +6 -3
  119. package/src/verax/core/run-manifest.js +4 -3
  120. package/src/verax/core/security/secrets.scan.js +10 -7
  121. package/src/verax/core/security/security.enforcer.js +4 -0
  122. package/src/verax/core/security/supplychain.policy.js +9 -1
  123. package/src/verax/core/security/vuln.scan.js +2 -2
  124. package/src/verax/core/truth/truth.certificate.js +3 -1
  125. package/src/verax/core/ui-feedback-intelligence.js +12 -46
  126. package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
  127. package/src/verax/detect/confidence-engine.js +100 -660
  128. package/src/verax/detect/confidence-helper.js +1 -0
  129. package/src/verax/detect/detection-engine.js +1 -18
  130. package/src/verax/detect/dynamic-route-findings.js +17 -14
  131. package/src/verax/detect/expectation-chain-detector.js +1 -1
  132. package/src/verax/detect/expectation-model.js +3 -5
  133. package/src/verax/detect/failure-cause-inference.js +293 -0
  134. package/src/verax/detect/findings-writer.js +126 -166
  135. package/src/verax/detect/flow-detector.js +2 -2
  136. package/src/verax/detect/form-silent-failure.js +98 -0
  137. package/src/verax/detect/index.js +51 -234
  138. package/src/verax/detect/invariants-enforcer.js +147 -0
  139. package/src/verax/detect/journey-stall-detector.js +4 -4
  140. package/src/verax/detect/navigation-silent-failure.js +82 -0
  141. package/src/verax/detect/problem-aggregator.js +361 -0
  142. package/src/verax/detect/route-findings.js +7 -6
  143. package/src/verax/detect/summary-writer.js +477 -0
  144. package/src/verax/detect/test-failure-cause-inference.js +314 -0
  145. package/src/verax/detect/ui-feedback-findings.js +18 -18
  146. package/src/verax/detect/verdict-engine.js +3 -57
  147. package/src/verax/detect/view-switch-correlator.js +2 -2
  148. package/src/verax/flow/flow-engine.js +2 -1
  149. package/src/verax/flow/flow-spec.js +0 -6
  150. package/src/verax/index.js +48 -412
  151. package/src/verax/intel/ts-program.js +1 -0
  152. package/src/verax/intel/vue-navigation-extractor.js +3 -0
  153. package/src/verax/learn/action-contract-extractor.js +67 -682
  154. package/src/verax/learn/ast-contract-extractor.js +1 -1
  155. package/src/verax/learn/flow-extractor.js +1 -0
  156. package/src/verax/learn/project-detector.js +5 -0
  157. package/src/verax/learn/react-router-extractor.js +2 -0
  158. package/src/verax/learn/route-validator.js +1 -4
  159. package/src/verax/learn/source-instrumenter.js +1 -0
  160. package/src/verax/learn/state-extractor.js +2 -1
  161. package/src/verax/learn/static-extractor.js +1 -0
  162. package/src/verax/observe/coverage-gaps.js +132 -0
  163. package/src/verax/observe/expectation-handler.js +126 -0
  164. package/src/verax/observe/incremental-skip.js +46 -0
  165. package/src/verax/observe/index.js +735 -84
  166. package/src/verax/observe/interaction-executor.js +192 -0
  167. package/src/verax/observe/interaction-runner.js +782 -530
  168. package/src/verax/observe/network-firewall.js +86 -0
  169. package/src/verax/observe/observation-builder.js +169 -0
  170. package/src/verax/observe/observe-context.js +1 -1
  171. package/src/verax/observe/observe-helpers.js +2 -1
  172. package/src/verax/observe/observe-runner.js +28 -24
  173. package/src/verax/observe/observers/budget-observer.js +3 -3
  174. package/src/verax/observe/observers/console-observer.js +4 -4
  175. package/src/verax/observe/observers/coverage-observer.js +4 -4
  176. package/src/verax/observe/observers/interaction-observer.js +3 -3
  177. package/src/verax/observe/observers/navigation-observer.js +4 -4
  178. package/src/verax/observe/observers/network-observer.js +4 -4
  179. package/src/verax/observe/observers/safety-observer.js +1 -1
  180. package/src/verax/observe/observers/ui-feedback-observer.js +4 -4
  181. package/src/verax/observe/page-traversal.js +138 -0
  182. package/src/verax/observe/snapshot-ops.js +94 -0
  183. package/src/verax/observe/ui-signal-sensor.js +2 -148
  184. package/src/verax/scan-summary-writer.js +10 -42
  185. package/src/verax/shared/artifact-manager.js +30 -13
  186. package/src/verax/shared/caching.js +1 -0
  187. package/src/verax/shared/expectation-tracker.js +1 -0
  188. package/src/verax/shared/zip-artifacts.js +6 -0
  189. package/src/verax/core/confidence-engine.js.backup +0 -471
  190. package/src/verax/shared/config-loader.js +0 -169
  191. /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
-