@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
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Problem Aggregator
3
+ *
4
+ * Groups raw findings into decision-level problems for executive review.
5
+ *
6
+ * RULES:
7
+ * - Deterministic grouping (no ML, no heuristics)
8
+ * - Every problem references underlying findings
9
+ * - Raw findings are preserved (never hidden)
10
+ * - Evidence is deduplicated across group
11
+ */
12
+
13
+ import { basename } from 'path';
14
+
15
+ /**
16
+ * Aggregate findings into decision-level problems
17
+ *
18
+ * @param {Array} findings - Raw findings from detection
19
+ * @param {Object} manifest - Project manifest
20
+ * @returns {Array} Array of ProblemGroup objects
21
+ */
22
+ export function aggregateProblems(findings, manifest) {
23
+ if (!findings || findings.length === 0) {
24
+ return [];
25
+ }
26
+
27
+ // Group findings by page/route
28
+ const byPage = groupByPage(findings);
29
+
30
+ // Within each page, group by user intent
31
+ const problems = [];
32
+
33
+ for (const [page, pageFindings] of Object.entries(byPage)) {
34
+ const intentGroups = groupByIntent(pageFindings);
35
+
36
+ for (const [intent, intentFindings] of Object.entries(intentGroups)) {
37
+ // Create a problem group
38
+ const problem = createProblemGroup(page, intent, intentFindings, manifest);
39
+ if (problem) {
40
+ problems.push(problem);
41
+ }
42
+ }
43
+ }
44
+
45
+ // Sort by impact (HIGH > MEDIUM > LOW) then confidence (HIGH > LOW)
46
+ problems.sort((a, b) => {
47
+ const impactOrder = { HIGH: 3, MEDIUM: 2, LOW: 1, UNKNOWN: 0 };
48
+ const impactDiff = impactOrder[b.impact] - impactOrder[a.impact];
49
+ if (impactDiff !== 0) return impactDiff;
50
+ return b.confidence - a.confidence;
51
+ });
52
+
53
+ return problems;
54
+ }
55
+
56
+ /**
57
+ * Group findings by page/route
58
+ */
59
+ function groupByPage(findings) {
60
+ const groups = {};
61
+
62
+ for (const finding of findings) {
63
+ const page = extractPage(finding);
64
+ if (!groups[page]) {
65
+ groups[page] = [];
66
+ }
67
+ groups[page].push(finding);
68
+ }
69
+
70
+ return groups;
71
+ }
72
+
73
+ /**
74
+ * Extract page identifier from finding
75
+ */
76
+ function extractPage(finding) {
77
+ if (!finding.source || !finding.source.file) {
78
+ return 'unknown';
79
+ }
80
+
81
+ // Extract filename without extension
82
+ const file = finding.source.file;
83
+ const filename = basename(file, '.jsx').replace(/\.js$/, '');
84
+
85
+ // Map common patterns to routes
86
+ if (filename.match(/dashboard/i)) return 'dashboard';
87
+ if (filename.match(/profile/i)) return 'profile';
88
+ if (filename.match(/settings/i)) return 'settings';
89
+ if (filename.match(/home|index/i)) return 'home';
90
+ if (filename.match(/login|auth/i)) return 'auth';
91
+
92
+ return filename.toLowerCase();
93
+ }
94
+
95
+ /**
96
+ * Group findings by user intent
97
+ */
98
+ function groupByIntent(findings) {
99
+ const groups = {};
100
+
101
+ for (const finding of findings) {
102
+ const intent = inferIntent(finding);
103
+ if (!groups[intent]) {
104
+ groups[intent] = [];
105
+ }
106
+ groups[intent].push(finding);
107
+ }
108
+
109
+ return groups;
110
+ }
111
+
112
+ /**
113
+ * Infer user intent from finding
114
+ */
115
+ function inferIntent(finding) {
116
+ const promise = finding.promise || {};
117
+ const type = finding.type;
118
+ const source = finding.source || {};
119
+ const file = source.file || '';
120
+
121
+ // Form submission
122
+ if (type === 'form' || promise.kind === 'submit') {
123
+ return 'save';
124
+ }
125
+
126
+ // Navigation
127
+ if (type === 'navigation' || promise.kind === 'navigate') {
128
+ return 'navigate';
129
+ }
130
+
131
+ // Auth actions - explicit button clicks
132
+ if (promise.kind === 'click' && promise.value && promise.value.match(/login|logout|signin|signout/i)) {
133
+ return 'auth';
134
+ }
135
+
136
+ // State changes - be more specific about what kind
137
+ if (type === 'state' || promise.kind === 'state_mutation') {
138
+ const value = promise.value || '';
139
+
140
+ // Loading/saving state - usually indicates stuck loading indicator
141
+ if (value.match(/loading|saving|submitting/i) || file.match(/dashboard/i)) {
142
+ return 'loading_feedback';
143
+ }
144
+
145
+ // Auth-related state
146
+ if (value.match(/auth|user|login/i) || file.match(/auth|profile/i)) {
147
+ // If in Profile.jsx specifically, it's conditional UI bug
148
+ if (file.match(/profile/i)) {
149
+ return 'conditional_ui';
150
+ }
151
+ return 'auth_state';
152
+ }
153
+
154
+ // Generic state update
155
+ return 'state_update';
156
+ }
157
+
158
+ // Feedback/validation
159
+ if (type === 'feedback' || promise.kind === 'validation') {
160
+ return 'validation';
161
+ }
162
+
163
+ // Button clicks
164
+ if (promise.kind === 'click') {
165
+ return 'interact';
166
+ }
167
+
168
+ return 'other';
169
+ }
170
+
171
+ /**
172
+ * Create a problem group from findings
173
+ */
174
+ function createProblemGroup(page, intent, findings, _manifest) {
175
+ if (findings.length === 0) {
176
+ return null;
177
+ }
178
+
179
+ // Generate problem ID
180
+ const id = `problem_${page}_${intent}`;
181
+
182
+ // Determine title based on intent
183
+ const title = generateTitle(page, intent, findings);
184
+
185
+ // Aggregate impact (highest wins)
186
+ const impact = aggregateImpact(findings);
187
+
188
+ // Aggregate confidence (average)
189
+ const confidence = aggregateConfidence(findings);
190
+
191
+ // Deduplicate evidence
192
+ const evidence = deduplicateEvidence(findings);
193
+
194
+ // Extract finding IDs
195
+ const findingIds = findings.map(f => f.id);
196
+
197
+ // Generate explanation
198
+ const explanation = generateExplanation(page, intent, findings);
199
+
200
+ return {
201
+ id,
202
+ title,
203
+ page,
204
+ userIntent: intent,
205
+ impact,
206
+ confidence,
207
+ findings: findingIds,
208
+ findingCount: findings.length,
209
+ evidence,
210
+ whatUserTried: explanation.whatUserTried,
211
+ whatWasExpected: explanation.whatWasExpected,
212
+ whatActuallyHappened: explanation.whatActuallyHappened,
213
+ whyItMatters: explanation.whyItMatters
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Generate human-readable title for problem
219
+ */
220
+ function generateTitle(page, intent, findings) {
221
+ const pageName = page.charAt(0).toUpperCase() + page.slice(1);
222
+
223
+ const intentMap = {
224
+ navigate: `${pageName} page doesn't load`,
225
+ save: `${pageName} form submission fails silently`,
226
+ auth: `${pageName} authentication fails silently`,
227
+ auth_state: `${pageName} authentication state doesn't update UI`,
228
+ conditional_ui: `${pageName} conditional UI doesn't update after state change`,
229
+ loading_feedback: `${pageName} loading state never resolves`,
230
+ state_update: `${pageName} state changes don't update UI`,
231
+ validation: `${pageName} validation feedback missing`,
232
+ interact: `${pageName} interactive elements don't work`,
233
+ other: `${pageName} has broken functionality`
234
+ };
235
+
236
+ return intentMap[intent] || `${pageName} has ${findings.length} silent failures`;
237
+ }
238
+
239
+ /**
240
+ * Aggregate impact across findings (highest wins)
241
+ */
242
+ function aggregateImpact(findings) {
243
+ const impactOrder = { HIGH: 3, MEDIUM: 2, LOW: 1, UNKNOWN: 0 };
244
+ let maxImpact = 'UNKNOWN';
245
+ let maxValue = 0;
246
+
247
+ for (const finding of findings) {
248
+ const impact = finding.impact || 'UNKNOWN';
249
+ const value = impactOrder[impact] || 0;
250
+ if (value > maxValue) {
251
+ maxValue = value;
252
+ maxImpact = impact;
253
+ }
254
+ }
255
+
256
+ return maxImpact;
257
+ }
258
+
259
+ /**
260
+ * Aggregate confidence across findings (average)
261
+ */
262
+ function aggregateConfidence(findings) {
263
+ if (findings.length === 0) return 0;
264
+
265
+ const sum = findings.reduce((acc, f) => acc + (f.confidence || 0.5), 0);
266
+ return Math.round((sum / findings.length) * 100) / 100;
267
+ }
268
+
269
+ /**
270
+ * Deduplicate evidence across findings
271
+ */
272
+ function deduplicateEvidence(findings) {
273
+ const evidenceMap = new Map();
274
+
275
+ for (const finding of findings) {
276
+ if (!finding.evidence) continue;
277
+
278
+ for (const ev of finding.evidence) {
279
+ const key = `${ev.type}:${ev.path || 'none'}`;
280
+ if (!evidenceMap.has(key)) {
281
+ evidenceMap.set(key, ev);
282
+ }
283
+ }
284
+ }
285
+
286
+ return Array.from(evidenceMap.values());
287
+ }
288
+
289
+ /**
290
+ * Generate explanation for problem
291
+ */
292
+ function generateExplanation(page, intent, findings) {
293
+ const pageName = page.charAt(0).toUpperCase() + page.slice(1);
294
+ const count = findings.length;
295
+
296
+ // Build explanation based on intent
297
+ const explanations = {
298
+ navigate: {
299
+ whatUserTried: `Navigate to ${pageName} page`,
300
+ whatWasExpected: 'Page content loads and displays',
301
+ whatActuallyHappened: `URL changed but page content did not render (${count} state mutations stuck)`,
302
+ whyItMatters: 'Users cannot access the intended page or see its content'
303
+ },
304
+ save: {
305
+ whatUserTried: `Submit form on ${pageName} page`,
306
+ whatWasExpected: 'Form submits and shows success feedback (message, redirect, or toast)',
307
+ whatActuallyHappened: `Form submitted but no feedback was provided to user (${count} related issues)`,
308
+ whyItMatters: 'Users don\'t know if their data was saved or if they should retry'
309
+ },
310
+ auth: {
311
+ whatUserTried: `Log in or log out using ${pageName} page buttons`,
312
+ whatWasExpected: 'Button click triggers authentication action with visual feedback',
313
+ whatActuallyHappened: `Button clicks produced no observable effect (${count} buttons don't work)`,
314
+ whyItMatters: 'Users cannot complete authentication workflows'
315
+ },
316
+ auth_state: {
317
+ whatUserTried: `Authenticate using ${pageName} page`,
318
+ whatWasExpected: 'Authentication state changes update UI accordingly',
319
+ whatActuallyHappened: `Auth state changed but UI did not reflect changes (${count} state mutations)`,
320
+ whyItMatters: 'Users cannot tell their authentication status'
321
+ },
322
+ conditional_ui: {
323
+ whatUserTried: `Interact with conditional UI on ${pageName} page`,
324
+ whatWasExpected: 'UI elements appear/disappear based on state (e.g., Login button hides after login)',
325
+ whatActuallyHappened: `State changed but conditional UI did not update (${count} stale elements)`,
326
+ whyItMatters: 'Users see UI elements that should be hidden or vice versa, causing confusion'
327
+ },
328
+ loading_feedback: {
329
+ whatUserTried: `Interact with ${pageName} page`,
330
+ whatWasExpected: 'Loading indicator appears then resolves when content is ready',
331
+ whatActuallyHappened: `Loading states were set but never cleared (${count} stuck states)`,
332
+ whyItMatters: 'Users see perpetual loading spinners or incomplete UI'
333
+ },
334
+ state_update: {
335
+ whatUserTried: `Interact with ${pageName} page elements`,
336
+ whatWasExpected: 'UI updates to reflect new state',
337
+ whatActuallyHappened: `State changed but UI did not update (${count} stale UI elements)`,
338
+ whyItMatters: 'Users see outdated information that doesn\'t match actual state'
339
+ },
340
+ validation: {
341
+ whatUserTried: `Submit invalid data on ${pageName} form`,
342
+ whatWasExpected: 'Validation errors display clearly',
343
+ whatActuallyHappened: `Validation feedback elements missing (${count} issues)`,
344
+ whyItMatters: 'Users cannot correct their mistakes or understand what went wrong'
345
+ },
346
+ interact: {
347
+ whatUserTried: `Click buttons or interact with elements on ${pageName}`,
348
+ whatWasExpected: 'Interactive elements respond with visible feedback',
349
+ whatActuallyHappened: `${count} interactive elements produced no observable effect`,
350
+ whyItMatters: 'Users cannot complete intended actions or workflows'
351
+ },
352
+ other: {
353
+ whatUserTried: `Use ${pageName} page functionality`,
354
+ whatWasExpected: 'Actions produce visible results',
355
+ whatActuallyHappened: `${count} actions failed silently with no user feedback`,
356
+ whyItMatters: 'Core functionality is broken but fails without error messages'
357
+ }
358
+ };
359
+
360
+ return explanations[intent] || explanations.other;
361
+ }
@@ -12,7 +12,6 @@ import {
12
12
  buildRouteEvidence,
13
13
  isRouteChangeFalsePositive,
14
14
  } from '../core/route-intelligence.js';
15
- import { computeConfidence } from './confidence-engine.js';
16
15
  import { computeConfidenceForFinding } from '../core/confidence-engine.js';
17
16
  import { buildAndEnforceEvidencePackage } from '../core/evidence-builder.js';
18
17
  import { applyGuardrails } from '../core/guardrails-engine.js';
@@ -22,10 +21,11 @@ import { applyGuardrails } from '../core/guardrails-engine.js';
22
21
  *
23
22
  * @param {Array} traces - Interaction traces
24
23
  * @param {Object} manifest - Project manifest with routes and expectations
25
- * @param {Array} findings - Findings array to append to
24
+ * @param {Array} _findings - Findings array to append to
25
+ * @ts-expect-error - JSDoc param documented but unused
26
26
  * @returns {Array} Route-related findings
27
27
  */
28
- export function detectRouteFindings(traces, manifest, findings) {
28
+ export function detectRouteFindings(traces, manifest, _findings) {
29
29
  const routeFindings = [];
30
30
 
31
31
  // Build route models from manifest routes
@@ -86,6 +86,7 @@ export function detectRouteFindings(traces, manifest, findings) {
86
86
  domChanged: evidence.signals.domChanged,
87
87
  },
88
88
  evidence,
89
+ options: {}
89
90
  });
90
91
 
91
92
  // PHASE 12: Evidence Law - require sufficient evidence for CONFIRMED
@@ -96,14 +97,14 @@ export function detectRouteFindings(traces, manifest, findings) {
96
97
  evidence.signals.uiChanged ||
97
98
  evidence.signals.domChanged);
98
99
 
99
- const severity = hasSufficientEvidence && unifiedConfidence.score >= 0.8 ? 'CONFIRMED' : 'SUSPECTED';
100
+ const severity = hasSufficientEvidence && (unifiedConfidence.score01 || unifiedConfidence.score || 0) >= 0.8 ? 'CONFIRMED' : 'SUSPECTED';
100
101
 
101
102
  const finding = {
102
103
  type: findingType,
103
104
  severity,
104
- confidence: unifiedConfidence.score, // PHASE 15: Use unified confidence score (0..1)
105
+ confidence: unifiedConfidence.score01 || unifiedConfidence.score || 0, // Contract v1: score01 canonical
105
106
  confidenceLevel: unifiedConfidence.level, // PHASE 15: Add confidence level
106
- confidenceReasons: unifiedConfidence.reasons, // PHASE 15: Add stable reason codes
107
+ confidenceReasons: unifiedConfidence.topReasons || unifiedConfidence.reasons || [], // Contract v1: topReasons
107
108
  interaction: {
108
109
  type: interaction.type,
109
110
  selector: interaction.selector,