@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.
Files changed (152) hide show
  1. package/README.md +14 -18
  2. package/bin/verax.js +7 -0
  3. package/package.json +3 -3
  4. package/src/cli/commands/baseline.js +104 -0
  5. package/src/cli/commands/default.js +79 -25
  6. package/src/cli/commands/ga.js +243 -0
  7. package/src/cli/commands/gates.js +95 -0
  8. package/src/cli/commands/inspect.js +131 -2
  9. package/src/cli/commands/release-check.js +213 -0
  10. package/src/cli/commands/run.js +246 -35
  11. package/src/cli/commands/security-check.js +211 -0
  12. package/src/cli/commands/truth.js +114 -0
  13. package/src/cli/entry.js +304 -67
  14. package/src/cli/util/angular-component-extractor.js +179 -0
  15. package/src/cli/util/angular-navigation-detector.js +141 -0
  16. package/src/cli/util/angular-network-detector.js +161 -0
  17. package/src/cli/util/angular-state-detector.js +162 -0
  18. package/src/cli/util/ast-interactive-detector.js +546 -0
  19. package/src/cli/util/ast-network-detector.js +603 -0
  20. package/src/cli/util/ast-usestate-detector.js +602 -0
  21. package/src/cli/util/bootstrap-guard.js +86 -0
  22. package/src/cli/util/determinism-runner.js +123 -0
  23. package/src/cli/util/determinism-writer.js +129 -0
  24. package/src/cli/util/env-url.js +4 -0
  25. package/src/cli/util/expectation-extractor.js +369 -73
  26. package/src/cli/util/findings-writer.js +126 -16
  27. package/src/cli/util/learn-writer.js +3 -1
  28. package/src/cli/util/observe-writer.js +3 -1
  29. package/src/cli/util/paths.js +3 -12
  30. package/src/cli/util/project-discovery.js +3 -0
  31. package/src/cli/util/project-writer.js +3 -1
  32. package/src/cli/util/run-resolver.js +64 -0
  33. package/src/cli/util/source-requirement.js +55 -0
  34. package/src/cli/util/summary-writer.js +1 -0
  35. package/src/cli/util/svelte-navigation-detector.js +163 -0
  36. package/src/cli/util/svelte-network-detector.js +80 -0
  37. package/src/cli/util/svelte-sfc-extractor.js +147 -0
  38. package/src/cli/util/svelte-state-detector.js +243 -0
  39. package/src/cli/util/vue-navigation-detector.js +177 -0
  40. package/src/cli/util/vue-sfc-extractor.js +162 -0
  41. package/src/cli/util/vue-state-detector.js +215 -0
  42. package/src/verax/cli/finding-explainer.js +56 -3
  43. package/src/verax/core/artifacts/registry.js +154 -0
  44. package/src/verax/core/artifacts/verifier.js +980 -0
  45. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  46. package/src/verax/core/baseline/baseline.snapshot.js +231 -0
  47. package/src/verax/core/capabilities/gates.js +499 -0
  48. package/src/verax/core/capabilities/registry.js +475 -0
  49. package/src/verax/core/confidence/confidence-compute.js +137 -0
  50. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  51. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  52. package/src/verax/core/confidence/confidence-weights.js +44 -0
  53. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  54. package/src/verax/core/confidence/confidence.loader.js +79 -0
  55. package/src/verax/core/confidence/confidence.schema.js +94 -0
  56. package/src/verax/core/confidence-engine-refactor.js +484 -0
  57. package/src/verax/core/confidence-engine.js +486 -0
  58. package/src/verax/core/confidence-engine.js.backup +471 -0
  59. package/src/verax/core/contracts/index.js +29 -0
  60. package/src/verax/core/contracts/types.js +185 -0
  61. package/src/verax/core/contracts/validators.js +381 -0
  62. package/src/verax/core/decision-snapshot.js +30 -3
  63. package/src/verax/core/decisions/decision.trace.js +276 -0
  64. package/src/verax/core/determinism/contract-writer.js +89 -0
  65. package/src/verax/core/determinism/contract.js +139 -0
  66. package/src/verax/core/determinism/diff.js +364 -0
  67. package/src/verax/core/determinism/engine.js +221 -0
  68. package/src/verax/core/determinism/finding-identity.js +148 -0
  69. package/src/verax/core/determinism/normalize.js +438 -0
  70. package/src/verax/core/determinism/report-writer.js +92 -0
  71. package/src/verax/core/determinism/run-fingerprint.js +118 -0
  72. package/src/verax/core/dynamic-route-intelligence.js +528 -0
  73. package/src/verax/core/evidence/evidence-capture-service.js +307 -0
  74. package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
  75. package/src/verax/core/evidence-builder.js +487 -0
  76. package/src/verax/core/execution-mode-context.js +77 -0
  77. package/src/verax/core/execution-mode-detector.js +190 -0
  78. package/src/verax/core/failures/exit-codes.js +86 -0
  79. package/src/verax/core/failures/failure-summary.js +76 -0
  80. package/src/verax/core/failures/failure.factory.js +225 -0
  81. package/src/verax/core/failures/failure.ledger.js +132 -0
  82. package/src/verax/core/failures/failure.types.js +196 -0
  83. package/src/verax/core/failures/index.js +10 -0
  84. package/src/verax/core/ga/ga-report-writer.js +43 -0
  85. package/src/verax/core/ga/ga.artifact.js +49 -0
  86. package/src/verax/core/ga/ga.contract.js +434 -0
  87. package/src/verax/core/ga/ga.enforcer.js +86 -0
  88. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  89. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  90. package/src/verax/core/guardrails/policy.loader.js +83 -0
  91. package/src/verax/core/guardrails/policy.schema.js +110 -0
  92. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  93. package/src/verax/core/guardrails-engine.js +505 -0
  94. package/src/verax/core/observe/run-timeline.js +316 -0
  95. package/src/verax/core/perf/perf.contract.js +186 -0
  96. package/src/verax/core/perf/perf.display.js +65 -0
  97. package/src/verax/core/perf/perf.enforcer.js +91 -0
  98. package/src/verax/core/perf/perf.monitor.js +209 -0
  99. package/src/verax/core/perf/perf.report.js +198 -0
  100. package/src/verax/core/pipeline-tracker.js +238 -0
  101. package/src/verax/core/product-definition.js +127 -0
  102. package/src/verax/core/release/provenance.builder.js +271 -0
  103. package/src/verax/core/release/release-report-writer.js +40 -0
  104. package/src/verax/core/release/release.enforcer.js +159 -0
  105. package/src/verax/core/release/reproducibility.check.js +221 -0
  106. package/src/verax/core/release/sbom.builder.js +283 -0
  107. package/src/verax/core/report/cross-index.js +192 -0
  108. package/src/verax/core/report/human-summary.js +222 -0
  109. package/src/verax/core/route-intelligence.js +419 -0
  110. package/src/verax/core/security/secrets.scan.js +326 -0
  111. package/src/verax/core/security/security-report.js +50 -0
  112. package/src/verax/core/security/security.enforcer.js +124 -0
  113. package/src/verax/core/security/supplychain.defaults.json +38 -0
  114. package/src/verax/core/security/supplychain.policy.js +326 -0
  115. package/src/verax/core/security/vuln.scan.js +265 -0
  116. package/src/verax/core/truth/truth.certificate.js +250 -0
  117. package/src/verax/core/ui-feedback-intelligence.js +515 -0
  118. package/src/verax/detect/confidence-engine.js +628 -40
  119. package/src/verax/detect/confidence-helper.js +33 -0
  120. package/src/verax/detect/detection-engine.js +18 -1
  121. package/src/verax/detect/dynamic-route-findings.js +335 -0
  122. package/src/verax/detect/expectation-chain-detector.js +417 -0
  123. package/src/verax/detect/expectation-model.js +3 -1
  124. package/src/verax/detect/findings-writer.js +141 -5
  125. package/src/verax/detect/index.js +229 -5
  126. package/src/verax/detect/journey-stall-detector.js +558 -0
  127. package/src/verax/detect/route-findings.js +218 -0
  128. package/src/verax/detect/ui-feedback-findings.js +207 -0
  129. package/src/verax/detect/verdict-engine.js +57 -3
  130. package/src/verax/detect/view-switch-correlator.js +242 -0
  131. package/src/verax/index.js +413 -45
  132. package/src/verax/learn/action-contract-extractor.js +682 -64
  133. package/src/verax/learn/route-validator.js +4 -1
  134. package/src/verax/observe/index.js +88 -843
  135. package/src/verax/observe/interaction-runner.js +25 -8
  136. package/src/verax/observe/observe-context.js +205 -0
  137. package/src/verax/observe/observe-helpers.js +191 -0
  138. package/src/verax/observe/observe-runner.js +226 -0
  139. package/src/verax/observe/observers/budget-observer.js +185 -0
  140. package/src/verax/observe/observers/console-observer.js +102 -0
  141. package/src/verax/observe/observers/coverage-observer.js +107 -0
  142. package/src/verax/observe/observers/interaction-observer.js +471 -0
  143. package/src/verax/observe/observers/navigation-observer.js +132 -0
  144. package/src/verax/observe/observers/network-observer.js +87 -0
  145. package/src/verax/observe/observers/safety-observer.js +82 -0
  146. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  147. package/src/verax/observe/ui-feedback-detector.js +742 -0
  148. package/src/verax/observe/ui-signal-sensor.js +148 -2
  149. package/src/verax/scan-summary-writer.js +42 -8
  150. package/src/verax/shared/artifact-manager.js +8 -5
  151. package/src/verax/shared/css-spinner-rules.js +204 -0
  152. package/src/verax/shared/view-switch-rules.js +208 -0
@@ -0,0 +1,471 @@
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
+
@@ -0,0 +1,29 @@
1
+ /**
2
+ * VERAX Core Contracts - Main export
3
+ *
4
+ * Single source of truth for:
5
+ * - Canonical type definitions (Finding, Evidence, Confidence, Observation, Signals)
6
+ * - All enums (CONFIDENCE_LEVEL, FINDING_STATUS, IMPACT, USER_RISK, OWNERSHIP, etc.)
7
+ * - Runtime validators that enforce contracts
8
+ * - Evidence Law enforcement (findings without evidence cannot be CONFIRMED)
9
+ */
10
+
11
+ export {
12
+ CONFIDENCE_LEVEL,
13
+ FINDING_STATUS,
14
+ FINDING_TYPE,
15
+ IMPACT,
16
+ USER_RISK,
17
+ OWNERSHIP,
18
+ EVIDENCE_TYPE,
19
+ ALL_ENUMS
20
+ } from './types.js';
21
+
22
+ export {
23
+ validateFinding,
24
+ validateEvidence,
25
+ validateConfidence,
26
+ validateSignals,
27
+ isEvidenceSubstantive,
28
+ enforceContractsOnFindings
29
+ } from './validators.js';
@@ -0,0 +1,185 @@
1
+ /**
2
+ * VERAX Core Contracts - Canonical Type Definitions
3
+ *
4
+ * This module defines the single source of truth for all core VERAX types:
5
+ * Finding, Evidence, Observation, Confidence, and associated enums.
6
+ *
7
+ * These definitions enforce strict runtime contracts and form the foundation
8
+ * for the Evidence Law: findings without sufficient evidence cannot be Confirmed.
9
+ */
10
+
11
+ /**
12
+ * Confidence Levels - measure of certainty in a finding
13
+ */
14
+ export const CONFIDENCE_LEVEL = {
15
+ HIGH: 'HIGH',
16
+ MEDIUM: 'MEDIUM',
17
+ LOW: 'LOW',
18
+ UNPROVEN: 'UNPROVEN'
19
+ };
20
+
21
+ /**
22
+ * Finding Status - the evaluation outcome
23
+ */
24
+ export const FINDING_STATUS = {
25
+ CONFIRMED: 'CONFIRMED', // Evidence law satisfied: sufficient evidence exists
26
+ SUSPECTED: 'SUSPECTED', // Needs evidence: signal observed but evidence incomplete
27
+ INFORMATIONAL: 'INFORMATIONAL', // Observation recorded, no claim of failure
28
+ DROPPED: 'DROPPED' // Violated contracts, removed from report
29
+ };
30
+
31
+ /**
32
+ * Finding Type - category of silent failure
33
+ */
34
+ export const FINDING_TYPE = {
35
+ NAVIGATION_SILENT_FAILURE: 'navigation_silent_failure',
36
+ NETWORK_SILENT_FAILURE: 'network_silent_failure',
37
+ STATE_SILENT_FAILURE: 'state_silent_failure',
38
+ OBSERVED_BREAK: 'observed_break',
39
+ SILENT_FAILURE: 'silent_failure',
40
+ FLOW_SILENT_FAILURE: 'flow_silent_failure'
41
+ };
42
+
43
+ /**
44
+ * Impact Level - severity of the silence
45
+ */
46
+ export const IMPACT = {
47
+ HIGH: 'HIGH',
48
+ MEDIUM: 'MEDIUM',
49
+ LOW: 'LOW'
50
+ };
51
+
52
+ /**
53
+ * User Risk - how the silence affects the user
54
+ */
55
+ export const USER_RISK = {
56
+ BLOCKS: 'BLOCKS', // User action is blocked from completion
57
+ CONFUSES: 'CONFUSES', // User is confused about what happened
58
+ DEGRADES: 'DEGRADES' // User experience is degraded
59
+ };
60
+
61
+ /**
62
+ * Ownership - which layer failed
63
+ */
64
+ export const OWNERSHIP = {
65
+ FRONTEND: 'FRONTEND',
66
+ BACKEND: 'BACKEND',
67
+ INTEGRATION: 'INTEGRATION',
68
+ ACCESSIBILITY: 'ACCESSIBILITY',
69
+ PERFORMANCE: 'PERFORMANCE'
70
+ };
71
+
72
+ /**
73
+ * Evidence Type - what provides proof
74
+ */
75
+ export const EVIDENCE_TYPE = {
76
+ NETWORK_ACTIVITY: 'network_activity',
77
+ DOM_CHANGE: 'dom_change',
78
+ STATE_CHANGE: 'state_change',
79
+ URL_CHANGE: 'url_change',
80
+ SCREENSHOT: 'screenshot',
81
+ CONSOLE_OUTPUT: 'console_output',
82
+ SENSOR_DATA: 'sensor_data'
83
+ };
84
+
85
+ /**
86
+ * Canonical Finding Interface
87
+ *
88
+ * @typedef {Object} Finding
89
+ * @property {string} type - One of FINDING_TYPE
90
+ * @property {string} [status] - One of FINDING_STATUS (defaults to SUSPECTED if evidence insufficient)
91
+ * @property {Object} interaction - The user interaction that triggered analysis
92
+ * @property {Object} evidence - Proof of the gap (REQUIRED for CONFIRMED status)
93
+ * @property {Object} confidence - Certainty assessment
94
+ * @property {Object} signals - Impact classification (impact, userRisk, ownership, grouping)
95
+ * @property {string} what_happened - Factual description of what occurred
96
+ * @property {string} what_was_expected - Factual description of code promise
97
+ * @property {string} what_was_observed - Factual description of observed outcome
98
+ * @property {string} why_it_matters - Human explanation of the gap
99
+ * @property {string} [humanSummary] - Human-readable summary
100
+ * @property {string} [actionHint] - Recommended next step
101
+ * @property {Object} [promise] - Promise descriptor from source code
102
+ * @property {string} [id] - Optional unique identifier
103
+ * @property {string} [findingId] - Optional deterministic ID based on expectation
104
+ * @property {string} [expectationId] - Optional reference to matched expectation
105
+ */
106
+
107
+ /**
108
+ * Canonical Evidence Interface
109
+ *
110
+ * @typedef {Object} Evidence
111
+ * @property {string} [type] - One of EVIDENCE_TYPE
112
+ * @property {boolean} [hasDomChange] - Whether DOM structure changed
113
+ * @property {boolean} [hasUrlChange] - Whether URL changed
114
+ * @property {boolean} [hasNetworkActivity] - Whether network requests occurred
115
+ * @property {boolean} [hasStateChange] - Whether application state changed
116
+ * @property {string} [beforeUrl] - URL before interaction
117
+ * @property {string} [afterUrl] - URL after interaction
118
+ * @property {string} [before] - Before state (screenshot path or data)
119
+ * @property {string} [after] - After state (screenshot path or data)
120
+ * @property {Object} [beforeDom] - DOM structure before
121
+ * @property {Object} [afterDom] - DOM structure after
122
+ * @property {Array} [networkRequests] - Network activity captured
123
+ * @property {Array} [consoleLogs] - Console messages
124
+ * @property {Object} [sensors] - Sensor data (navigation, uiSignals, etc.)
125
+ * @property {string} [source] - Source file reference
126
+ * @property {string} [expectedTarget] - Expected target for navigation/network
127
+ * @property {boolean} [targetReached] - Whether expected target was reached
128
+ */
129
+
130
+ /**
131
+ * Canonical Confidence Interface
132
+ *
133
+ * @typedef {Object} Confidence
134
+ * @property {string} level - One of CONFIDENCE_LEVEL
135
+ * @property {number} score - 0-100 confidence percentage
136
+ * @property {Array} [factors] - List of confidence factors
137
+ * @property {string} [explanation] - Detailed explanation of confidence level
138
+ */
139
+
140
+ /**
141
+ * Canonical Observation Interface
142
+ *
143
+ * @typedef {Object} Observation
144
+ * @property {string} type - Type of observation
145
+ * @property {string} selector - Element selector
146
+ * @property {string} label - Human-readable label
147
+ * @property {Object} sensors - Sensor readings before and after
148
+ * @property {Array} [evidence] - Array of evidence items from observation
149
+ */
150
+
151
+ /**
152
+ * Canonical Signals Interface
153
+ *
154
+ * @typedef {Object} Signals
155
+ * @property {string} impact - One of IMPACT
156
+ * @property {string} userRisk - One of USER_RISK
157
+ * @property {string} ownership - One of OWNERSHIP
158
+ * @property {Object} grouping - Grouping metadata
159
+ * @property {string} [grouping.groupByRoute] - Route pattern
160
+ * @property {string} [grouping.groupByFailureType] - Type of failure
161
+ * @property {string} [grouping.groupByFeature] - Feature area
162
+ */
163
+
164
+ /**
165
+ * Verify all enum exports are available
166
+ */
167
+ export const ALL_ENUMS = {
168
+ CONFIDENCE_LEVEL,
169
+ FINDING_STATUS,
170
+ FINDING_TYPE,
171
+ IMPACT,
172
+ USER_RISK,
173
+ OWNERSHIP,
174
+ EVIDENCE_TYPE
175
+ };
176
+
177
+ export default {
178
+ CONFIDENCE_LEVEL,
179
+ FINDING_STATUS,
180
+ FINDING_TYPE,
181
+ IMPACT,
182
+ USER_RISK,
183
+ OWNERSHIP,
184
+ EVIDENCE_TYPE
185
+ };