@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,218 @@
1
+ /**
2
+ * PHASE 12 — Route Intelligence Findings Detector
3
+ *
4
+ * Detects route-related silent failures by correlating navigation promises
5
+ * with route definitions and evaluating outcomes.
6
+ */
7
+
8
+ import {
9
+ buildRouteModels,
10
+ correlateNavigationWithRoute,
11
+ evaluateRouteNavigation,
12
+ buildRouteEvidence,
13
+ isRouteChangeFalsePositive,
14
+ } from '../core/route-intelligence.js';
15
+ import { computeConfidence } from './confidence-engine.js';
16
+ import { computeConfidenceForFinding } from '../core/confidence-engine.js';
17
+ import { buildAndEnforceEvidencePackage } from '../core/evidence-builder.js';
18
+ import { applyGuardrails } from '../core/guardrails-engine.js';
19
+
20
+ /**
21
+ * PHASE 12: Detect route-related findings
22
+ *
23
+ * @param {Array} traces - Interaction traces
24
+ * @param {Object} manifest - Project manifest with routes and expectations
25
+ * @param {Array} findings - Findings array to append to
26
+ * @returns {Array} Route-related findings
27
+ */
28
+ export function detectRouteFindings(traces, manifest, findings) {
29
+ const routeFindings = [];
30
+
31
+ // Build route models from manifest routes
32
+ const routeModels = buildRouteModels(manifest.routes || []);
33
+
34
+ // Process each trace
35
+ for (const trace of traces) {
36
+ const interaction = trace.interaction || {};
37
+ const beforeUrl = trace.before?.url || trace.sensors?.navigation?.beforeUrl || '';
38
+ const afterUrl = trace.after?.url || trace.sensors?.navigation?.afterUrl || '';
39
+
40
+ // Find navigation expectations for this interaction
41
+ const navigationExpectations = findNavigationExpectations(manifest, interaction, beforeUrl);
42
+
43
+ for (const expectation of navigationExpectations) {
44
+ const navigationTarget = expectation.targetPath || expectation.expectedTarget || '';
45
+
46
+ if (!navigationTarget) continue;
47
+
48
+ // Correlate navigation promise with route
49
+ const correlation = correlateNavigationWithRoute(navigationTarget, routeModels);
50
+
51
+ // Check for false positives
52
+ if (isRouteChangeFalsePositive(trace, correlation)) {
53
+ continue;
54
+ }
55
+
56
+ // Evaluate route navigation outcome
57
+ const evaluation = evaluateRouteNavigation(correlation, trace, beforeUrl, afterUrl);
58
+
59
+ // Generate finding if needed
60
+ if (evaluation.outcome === 'SILENT_FAILURE' ||
61
+ evaluation.outcome === 'ROUTE_MISMATCH' ||
62
+ (evaluation.outcome === 'SUSPECTED' && evaluation.confidence >= 0.6)) {
63
+
64
+ // Build evidence
65
+ const evidence = buildRouteEvidence(correlation, expectation, evaluation, trace);
66
+
67
+ // Determine finding type
68
+ let findingType = 'route_silent_failure';
69
+ let reason = evaluation.reason || 'Route navigation promise not fulfilled';
70
+
71
+ if (evaluation.outcome === 'ROUTE_MISMATCH') {
72
+ findingType = 'route_mismatch';
73
+ reason = `Navigation occurred but target route does not match. Expected: ${correlation?.route?.path}, Actual: ${evidence.beforeAfter.afterUrl}`;
74
+ } else if (evaluation.outcome === 'SUSPECTED') {
75
+ findingType = 'route_ambiguous';
76
+ reason = 'Dynamic route cannot be deterministically validated';
77
+ }
78
+
79
+ // PHASE 15: Compute unified confidence
80
+ const unifiedConfidence = computeConfidenceForFinding({
81
+ findingType: findingType,
82
+ expectation,
83
+ sensors: trace.sensors || {},
84
+ comparisons: {
85
+ urlChanged: evidence.signals.urlChanged,
86
+ domChanged: evidence.signals.domChanged,
87
+ },
88
+ evidence,
89
+ });
90
+
91
+ // PHASE 12: Evidence Law - require sufficient evidence for CONFIRMED
92
+ const hasSufficientEvidence = evidence.beforeAfter.beforeUrl &&
93
+ evidence.beforeAfter.afterUrl &&
94
+ (evidence.signals.urlChanged ||
95
+ evidence.signals.routerStateChanged ||
96
+ evidence.signals.uiChanged ||
97
+ evidence.signals.domChanged);
98
+
99
+ const severity = hasSufficientEvidence && unifiedConfidence.score >= 0.8 ? 'CONFIRMED' : 'SUSPECTED';
100
+
101
+ const finding = {
102
+ type: findingType,
103
+ severity,
104
+ confidence: unifiedConfidence.score, // PHASE 15: Use unified confidence score (0..1)
105
+ confidenceLevel: unifiedConfidence.level, // PHASE 15: Add confidence level
106
+ confidenceReasons: unifiedConfidence.reasons, // PHASE 15: Add stable reason codes
107
+ interaction: {
108
+ type: interaction.type,
109
+ selector: interaction.selector,
110
+ label: interaction.label,
111
+ },
112
+ reason,
113
+ evidence,
114
+ source: {
115
+ file: expectation.source?.file || null,
116
+ line: expectation.source?.line || null,
117
+ column: expectation.source?.column || null,
118
+ context: expectation.source?.context || null,
119
+ astSource: expectation.source?.astSource || expectation.metadata?.astSource || null,
120
+ },
121
+ };
122
+
123
+ // PHASE 16: Build and enforce evidence package
124
+ const findingWithEvidence = buildAndEnforceEvidencePackage(finding, {
125
+ expectation,
126
+ trace,
127
+ evidence,
128
+ confidence: unifiedConfidence,
129
+ });
130
+
131
+ // PHASE 17: Apply guardrails (AFTER evidence builder)
132
+ const context = {
133
+ evidencePackage: findingWithEvidence.evidencePackage,
134
+ signals: findingWithEvidence.evidencePackage?.signals || evidence.signals || {},
135
+ confidenceReasons: unifiedConfidence.reasons || [],
136
+ promiseType: expectation?.type || null,
137
+ };
138
+ const { finding: findingWithGuardrails } = applyGuardrails(findingWithEvidence, context);
139
+
140
+ routeFindings.push(findingWithGuardrails);
141
+ }
142
+ }
143
+ }
144
+
145
+ return routeFindings;
146
+ }
147
+
148
+ /**
149
+ * Find navigation expectations matching the interaction
150
+ */
151
+ function findNavigationExpectations(manifest, interaction, beforeUrl) {
152
+ const expectations = [];
153
+
154
+ // Check static expectations
155
+ if (manifest.staticExpectations) {
156
+ const beforePath = extractPathFromUrl(beforeUrl);
157
+ if (beforePath) {
158
+ const normalizedBefore = beforePath.replace(/\/$/, '') || '/';
159
+
160
+ for (const expectation of manifest.staticExpectations) {
161
+ if (expectation.type !== 'navigation' && expectation.type !== 'spa_navigation') {
162
+ continue;
163
+ }
164
+
165
+ const normalizedFrom = (expectation.fromPath || '').replace(/\/$/, '') || '/';
166
+ if (normalizedFrom === normalizedBefore) {
167
+ // Check selector match
168
+ const selectorHint = expectation.selectorHint || '';
169
+ const interactionSelector = interaction.selector || '';
170
+
171
+ if (!selectorHint || !interactionSelector ||
172
+ selectorHint === interactionSelector ||
173
+ selectorHint.includes(interactionSelector) ||
174
+ interactionSelector.includes(selectorHint)) {
175
+ expectations.push(expectation);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ // Check expectations from intel (AST-based)
183
+ if (manifest.expectations) {
184
+ for (const expectation of manifest.expectations) {
185
+ if (expectation.type === 'navigation' || expectation.type === 'spa_navigation') {
186
+ // Match by selector or label
187
+ const selectorHint = expectation.selectorHint || '';
188
+ const interactionSelector = interaction.selector || '';
189
+ const interactionLabel = (interaction.label || '').toLowerCase();
190
+ const expectationLabel = (expectation.promise?.value || '').toLowerCase();
191
+
192
+ if (selectorHint === interactionSelector ||
193
+ (expectationLabel && interactionLabel && expectationLabel.includes(interactionLabel))) {
194
+ expectations.push(expectation);
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ return expectations;
201
+ }
202
+
203
+ /**
204
+ * Extract path from URL
205
+ */
206
+ function extractPathFromUrl(url) {
207
+ if (!url || typeof url !== 'string') return '';
208
+
209
+ try {
210
+ const urlObj = new URL(url);
211
+ return urlObj.pathname;
212
+ } catch {
213
+ // Relative URL
214
+ const pathMatch = url.match(/^([^?#]+)/);
215
+ return pathMatch ? pathMatch[1] : url;
216
+ }
217
+ }
218
+
@@ -0,0 +1,207 @@
1
+ /**
2
+ * PHASE 13 — UI Feedback Findings Detector
3
+ *
4
+ * Detects UI feedback-related silent failures by correlating promises
5
+ * with feedback signals and evaluating outcomes.
6
+ */
7
+
8
+ import {
9
+ detectUIFeedbackSignals,
10
+ scoreUIFeedback,
11
+ correlatePromiseWithFeedback,
12
+ buildUIFeedbackEvidence,
13
+ FEEDBACK_SCORE,
14
+ } from '../core/ui-feedback-intelligence.js';
15
+ import { computeConfidence } from './confidence-engine.js';
16
+ import { computeConfidenceForFinding } from '../core/confidence-engine.js';
17
+ import { buildAndEnforceEvidencePackage } from '../core/evidence-builder.js';
18
+ import { applyGuardrails } from '../core/guardrails-engine.js';
19
+
20
+ /**
21
+ * PHASE 13: Detect UI feedback-related findings
22
+ *
23
+ * @param {Array} traces - Interaction traces
24
+ * @param {Object} manifest - Project manifest with expectations
25
+ * @param {Array} findings - Findings array to append to
26
+ * @returns {Array} UI feedback-related findings
27
+ */
28
+ export function detectUIFeedbackFindings(traces, manifest, findings) {
29
+ const feedbackFindings = [];
30
+
31
+ // Process each trace
32
+ for (const trace of traces) {
33
+ const interaction = trace.interaction || {};
34
+
35
+ // Find expectations for this interaction
36
+ const expectations = findExpectationsForInteraction(manifest, interaction, trace);
37
+
38
+ for (const expectation of expectations) {
39
+ // Detect UI feedback signals
40
+ const signals = detectUIFeedbackSignals(trace);
41
+
42
+ // Score feedback presence/absence
43
+ const feedbackScore = scoreUIFeedback(signals, expectation, trace);
44
+
45
+ // Correlate promise with feedback
46
+ const correlation = correlatePromiseWithFeedback(expectation, feedbackScore, trace);
47
+
48
+ // Generate finding if correlation indicates silent failure
49
+ if (correlation.outcome === 'CONFIRMED' || correlation.outcome === 'SUSPECTED') {
50
+ // Build evidence
51
+ const evidence = buildUIFeedbackEvidence(feedbackScore, correlation, trace, expectation);
52
+
53
+ // PHASE 13: Evidence Law - require sufficient evidence for CONFIRMED
54
+ const hasSufficientEvidence = evidence.beforeAfter.beforeScreenshot &&
55
+ evidence.beforeAfter.afterScreenshot &&
56
+ (evidence.feedback.signals.length > 0 ||
57
+ evidence.feedback.score === FEEDBACK_SCORE.MISSING);
58
+
59
+ // PHASE 15: Compute unified confidence
60
+ const unifiedConfidence = computeConfidenceForFinding({
61
+ findingType: findingType,
62
+ expectation,
63
+ sensors: trace.sensors || {},
64
+ comparisons: {},
65
+ evidence,
66
+ });
67
+
68
+ // Legacy confidence for backward compatibility
69
+ const confidence = computeConfidence({
70
+ findingType: 'ui_feedback_silent_failure',
71
+ expectation,
72
+ sensors: trace.sensors || {},
73
+ comparisons: {},
74
+ attemptMeta: {},
75
+ });
76
+
77
+ // Determine severity based on evidence
78
+ const severity = hasSufficientEvidence && correlation.outcome === 'CONFIRMED' && unifiedConfidence.score >= 0.8
79
+ ? 'CONFIRMED'
80
+ : 'SUSPECTED';
81
+
82
+ // Determine finding type
83
+ let findingType = 'ui_feedback_silent_failure';
84
+ if (expectation.type === 'network_action' || expectation.type === 'network') {
85
+ findingType = 'network_feedback_missing';
86
+ } else if (expectation.type === 'navigation' || expectation.type === 'spa_navigation') {
87
+ findingType = 'navigation_feedback_missing';
88
+ } else if (expectation.type === 'validation' || expectation.type === 'form_submission') {
89
+ findingType = 'validation_feedback_missing';
90
+ } else if (expectation.type === 'state_action' || expectation.type === 'state') {
91
+ findingType = 'state_feedback_missing';
92
+ }
93
+
94
+ const finding = {
95
+ type: findingType,
96
+ severity,
97
+ confidence: unifiedConfidence.score, // PHASE 15: Use unified confidence score (0..1)
98
+ confidenceLevel: unifiedConfidence.level, // PHASE 15: Add confidence level
99
+ confidenceReasons: unifiedConfidence.reasons, // PHASE 15: Add stable reason codes
100
+ interaction: {
101
+ type: interaction.type,
102
+ selector: interaction.selector,
103
+ label: interaction.label,
104
+ },
105
+ reason: correlation.reason || feedbackScore.explanation,
106
+ evidence,
107
+ source: {
108
+ file: expectation.source?.file || null,
109
+ line: expectation.source?.line || null,
110
+ column: expectation.source?.column || null,
111
+ context: expectation.source?.context || null,
112
+ astSource: expectation.source?.astSource || null,
113
+ },
114
+ };
115
+
116
+ // PHASE 16: Build and enforce evidence package
117
+ const findingWithEvidence = buildAndEnforceEvidencePackage(finding, {
118
+ expectation,
119
+ trace,
120
+ evidence,
121
+ confidence: unifiedConfidence,
122
+ });
123
+
124
+ // PHASE 17: Apply guardrails (AFTER evidence builder)
125
+ const context = {
126
+ evidencePackage: findingWithEvidence.evidencePackage,
127
+ signals: findingWithEvidence.evidencePackage?.signals || evidence.signals || {},
128
+ confidenceReasons: unifiedConfidence.reasons || [],
129
+ promiseType: expectation?.type || null,
130
+ };
131
+ const { finding: findingWithGuardrails } = applyGuardrails(findingWithEvidence, context);
132
+
133
+ feedbackFindings.push(findingWithGuardrails);
134
+ }
135
+ }
136
+ }
137
+
138
+ return feedbackFindings;
139
+ }
140
+
141
+ /**
142
+ * Find expectations matching the interaction
143
+ */
144
+ function findExpectationsForInteraction(manifest, interaction, trace) {
145
+ const expectations = [];
146
+
147
+ // Check static expectations
148
+ if (manifest.staticExpectations) {
149
+ const beforeUrl = trace.before?.url || trace.sensors?.navigation?.beforeUrl || '';
150
+ const beforePath = extractPathFromUrl(beforeUrl);
151
+
152
+ if (beforePath) {
153
+ const normalizedBefore = beforePath.replace(/\/$/, '') || '/';
154
+
155
+ for (const expectation of manifest.staticExpectations) {
156
+ const normalizedFrom = (expectation.fromPath || '').replace(/\/$/, '') || '/';
157
+ if (normalizedFrom === normalizedBefore) {
158
+ // Check selector match
159
+ const selectorHint = expectation.selectorHint || '';
160
+ const interactionSelector = interaction.selector || '';
161
+
162
+ if (!selectorHint || !interactionSelector ||
163
+ selectorHint === interactionSelector ||
164
+ selectorHint.includes(interactionSelector) ||
165
+ interactionSelector.includes(selectorHint)) {
166
+ expectations.push(expectation);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ // Check expectations from intel (AST-based)
174
+ if (manifest.expectations) {
175
+ for (const expectation of manifest.expectations) {
176
+ // Match by selector or label
177
+ const selectorHint = expectation.selectorHint || '';
178
+ const interactionSelector = interaction.selector || '';
179
+ const interactionLabel = (interaction.label || '').toLowerCase();
180
+ const expectationLabel = (expectation.promise?.value || '').toLowerCase();
181
+
182
+ if (selectorHint === interactionSelector ||
183
+ (expectationLabel && interactionLabel && expectationLabel.includes(interactionLabel))) {
184
+ expectations.push(expectation);
185
+ }
186
+ }
187
+ }
188
+
189
+ return expectations;
190
+ }
191
+
192
+ /**
193
+ * Extract path from URL
194
+ */
195
+ function extractPathFromUrl(url) {
196
+ if (!url || typeof url !== 'string') return '';
197
+
198
+ try {
199
+ const urlObj = new URL(url);
200
+ return urlObj.pathname;
201
+ } catch {
202
+ // Relative URL
203
+ const pathMatch = url.match(/^([^?#]+)/);
204
+ return pathMatch ? pathMatch[1] : url;
205
+ }
206
+ }
207
+
@@ -55,19 +55,20 @@ export function computeObservationSummary(findings, observeTruth, learnTruth, co
55
55
  );
56
56
  const skippedCount = coverage.skippedInteractions || 0;
57
57
 
58
- // Count findings by confidence (for transparency, not judgment)
58
+ // PHASE 15: Count findings by unified confidence level
59
59
  const findingsByConfidence = {
60
60
  HIGH: 0,
61
61
  MEDIUM: 0,
62
62
  LOW: 0,
63
- UNKNOWN: 0
63
+ UNPROVEN: 0 // PHASE 15: Changed from UNKNOWN to UNPROVEN
64
64
  };
65
65
  const findingsByType = {};
66
66
  const findingsByOutcome = {}; // PHASE 2: Added outcome tracking
67
67
  const findingsByPromise = {}; // PHASE 3: Added promise tracking
68
68
 
69
69
  for (const finding of (findings || [])) {
70
- const confidence = finding.confidence?.level || 'UNKNOWN';
70
+ // PHASE 15: Use unified confidence level
71
+ const confidence = finding.confidenceLevel || finding.confidence?.level || 'UNPROVEN';
71
72
  const type = finding.type || 'unknown';
72
73
  const outcome = finding.outcome || CANONICAL_OUTCOMES.SILENT_FAILURE; // Default for legacy findings
73
74
  const promiseType = finding.promise?.type || 'UNKNOWN_PROMISE'; // PHASE 3
@@ -78,6 +79,39 @@ export function computeObservationSummary(findings, observeTruth, learnTruth, co
78
79
  findingsByType[type] = (findingsByType[type] || 0) + 1;
79
80
  findingsByOutcome[outcome] = (findingsByOutcome[outcome] || 0) + 1; // PHASE 2
80
81
  findingsByPromise[promiseType] = (findingsByPromise[promiseType] || 0) + 1; // PHASE 3
82
+
83
+ // PHASE 16: Track evidence completeness
84
+ evidenceCompleteness.totalFindings++;
85
+ if (finding.evidencePackage) {
86
+ if (finding.evidencePackage.isComplete) {
87
+ evidenceCompleteness.completeEvidence++;
88
+ } else {
89
+ evidenceCompleteness.incompleteEvidence++;
90
+ }
91
+ }
92
+ if (finding.evidenceCompleteness?.downgraded) {
93
+ evidenceCompleteness.downgradedCount++;
94
+ }
95
+
96
+ // PHASE 17: Track guardrails
97
+ if (finding.guardrails) {
98
+ guardrailsSummary.totalFindingsProcessed++;
99
+ if (finding.guardrails.appliedRules) {
100
+ guardrailsSummary.appliedRulesCount += finding.guardrails.appliedRules.length;
101
+ }
102
+ if (finding.guardrails.contradictions) {
103
+ guardrailsSummary.contradictionsCount += finding.guardrails.contradictions.length;
104
+ }
105
+ if (finding.guardrails.finalDecision === 'SUSPECTED' && finding.severity === 'CONFIRMED') {
106
+ guardrailsSummary.downgradedCount++;
107
+ }
108
+ if (finding.guardrails.finalDecision === 'INFORMATIONAL') {
109
+ guardrailsSummary.informationalCount++;
110
+ }
111
+ if (finding.guardrails.recommendedStatus !== finding.severity && finding.severity === 'CONFIRMED') {
112
+ guardrailsSummary.preventedConfirmedCount++;
113
+ }
114
+ }
81
115
  }
82
116
 
83
117
  // Calculate ratios (factual, not judgmental)
@@ -94,6 +128,24 @@ export function computeObservationSummary(findings, observeTruth, learnTruth, co
94
128
  unprovenResults: unprovenTraces.length
95
129
  };
96
130
 
131
+ // PHASE 16: Track evidence completeness summary
132
+ const evidenceCompleteness = {
133
+ totalFindings: 0,
134
+ completeEvidence: 0,
135
+ incompleteEvidence: 0,
136
+ downgradedCount: 0,
137
+ };
138
+
139
+ // PHASE 17: Track guardrails summary
140
+ const guardrailsSummary = {
141
+ totalFindingsProcessed: 0,
142
+ preventedConfirmedCount: 0,
143
+ downgradedCount: 0,
144
+ informationalCount: 0,
145
+ appliedRulesCount: 0,
146
+ contradictionsCount: 0,
147
+ };
148
+
97
149
  // Build gap details
98
150
  const gapDetails = [];
99
151
  if (isBudgetExceeded) {
@@ -150,6 +202,8 @@ export function computeObservationSummary(findings, observeTruth, learnTruth, co
150
202
  discrepanciesByPromise: findingsByPromise, // PHASE 3: Promise types
151
203
  findings: findings || []
152
204
  },
205
+ evidenceCompleteness: evidenceCompleteness, // PHASE 16: Evidence completeness summary
206
+ guardrailsSummary: guardrailsSummary, // PHASE 17: Guardrails summary
153
207
  coverage: {
154
208
  pagesEvaluated,
155
209
  pagesDiscovered,