@veraxhq/verax 0.2.0 → 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 (217) hide show
  1. package/README.md +14 -18
  2. package/bin/verax.js +7 -0
  3. package/package.json +15 -5
  4. package/src/cli/commands/baseline.js +104 -0
  5. package/src/cli/commands/default.js +323 -111
  6. package/src/cli/commands/doctor.js +36 -4
  7. package/src/cli/commands/ga.js +243 -0
  8. package/src/cli/commands/gates.js +95 -0
  9. package/src/cli/commands/inspect.js +131 -2
  10. package/src/cli/commands/release-check.js +213 -0
  11. package/src/cli/commands/run.js +498 -103
  12. package/src/cli/commands/security-check.js +211 -0
  13. package/src/cli/commands/truth.js +114 -0
  14. package/src/cli/entry.js +305 -68
  15. package/src/cli/util/angular-component-extractor.js +179 -0
  16. package/src/cli/util/angular-navigation-detector.js +141 -0
  17. package/src/cli/util/angular-network-detector.js +161 -0
  18. package/src/cli/util/angular-state-detector.js +162 -0
  19. package/src/cli/util/ast-interactive-detector.js +546 -0
  20. package/src/cli/util/ast-network-detector.js +603 -0
  21. package/src/cli/util/ast-usestate-detector.js +602 -0
  22. package/src/cli/util/bootstrap-guard.js +86 -0
  23. package/src/cli/util/detection-engine.js +4 -3
  24. package/src/cli/util/determinism-runner.js +123 -0
  25. package/src/cli/util/determinism-writer.js +129 -0
  26. package/src/cli/util/env-url.js +4 -0
  27. package/src/cli/util/events.js +76 -0
  28. package/src/cli/util/expectation-extractor.js +380 -74
  29. package/src/cli/util/findings-writer.js +126 -15
  30. package/src/cli/util/learn-writer.js +3 -1
  31. package/src/cli/util/observation-engine.js +69 -23
  32. package/src/cli/util/observe-writer.js +3 -1
  33. package/src/cli/util/paths.js +6 -14
  34. package/src/cli/util/project-discovery.js +23 -0
  35. package/src/cli/util/project-writer.js +3 -1
  36. package/src/cli/util/redact.js +2 -2
  37. package/src/cli/util/run-resolver.js +64 -0
  38. package/src/cli/util/runtime-budget.js +147 -0
  39. package/src/cli/util/source-requirement.js +55 -0
  40. package/src/cli/util/summary-writer.js +13 -1
  41. package/src/cli/util/svelte-navigation-detector.js +163 -0
  42. package/src/cli/util/svelte-network-detector.js +80 -0
  43. package/src/cli/util/svelte-sfc-extractor.js +147 -0
  44. package/src/cli/util/svelte-state-detector.js +243 -0
  45. package/src/cli/util/vue-navigation-detector.js +177 -0
  46. package/src/cli/util/vue-sfc-extractor.js +162 -0
  47. package/src/cli/util/vue-state-detector.js +215 -0
  48. package/src/types/global.d.ts +28 -0
  49. package/src/types/ts-ast.d.ts +24 -0
  50. package/src/verax/cli/doctor.js +2 -2
  51. package/src/verax/cli/finding-explainer.js +56 -3
  52. package/src/verax/cli/init.js +1 -1
  53. package/src/verax/cli/url-safety.js +12 -2
  54. package/src/verax/cli/wizard.js +13 -2
  55. package/src/verax/core/artifacts/registry.js +154 -0
  56. package/src/verax/core/artifacts/verifier.js +980 -0
  57. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  58. package/src/verax/core/baseline/baseline.snapshot.js +231 -0
  59. package/src/verax/core/budget-engine.js +1 -1
  60. package/src/verax/core/capabilities/gates.js +499 -0
  61. package/src/verax/core/capabilities/registry.js +475 -0
  62. package/src/verax/core/confidence/confidence-compute.js +137 -0
  63. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  64. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  65. package/src/verax/core/confidence/confidence-weights.js +44 -0
  66. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  67. package/src/verax/core/confidence/confidence.loader.js +79 -0
  68. package/src/verax/core/confidence/confidence.schema.js +94 -0
  69. package/src/verax/core/confidence-engine-refactor.js +484 -0
  70. package/src/verax/core/confidence-engine.js +486 -0
  71. package/src/verax/core/confidence-engine.js.backup +471 -0
  72. package/src/verax/core/contracts/index.js +29 -0
  73. package/src/verax/core/contracts/types.js +185 -0
  74. package/src/verax/core/contracts/validators.js +381 -0
  75. package/src/verax/core/decision-snapshot.js +31 -4
  76. package/src/verax/core/decisions/decision.trace.js +276 -0
  77. package/src/verax/core/determinism/contract-writer.js +89 -0
  78. package/src/verax/core/determinism/contract.js +139 -0
  79. package/src/verax/core/determinism/diff.js +364 -0
  80. package/src/verax/core/determinism/engine.js +221 -0
  81. package/src/verax/core/determinism/finding-identity.js +148 -0
  82. package/src/verax/core/determinism/normalize.js +438 -0
  83. package/src/verax/core/determinism/report-writer.js +92 -0
  84. package/src/verax/core/determinism/run-fingerprint.js +118 -0
  85. package/src/verax/core/determinism-model.js +35 -6
  86. package/src/verax/core/dynamic-route-intelligence.js +528 -0
  87. package/src/verax/core/evidence/evidence-capture-service.js +307 -0
  88. package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
  89. package/src/verax/core/evidence-builder.js +487 -0
  90. package/src/verax/core/execution-mode-context.js +77 -0
  91. package/src/verax/core/execution-mode-detector.js +190 -0
  92. package/src/verax/core/failures/exit-codes.js +86 -0
  93. package/src/verax/core/failures/failure-summary.js +76 -0
  94. package/src/verax/core/failures/failure.factory.js +225 -0
  95. package/src/verax/core/failures/failure.ledger.js +132 -0
  96. package/src/verax/core/failures/failure.types.js +196 -0
  97. package/src/verax/core/failures/index.js +10 -0
  98. package/src/verax/core/ga/ga-report-writer.js +43 -0
  99. package/src/verax/core/ga/ga.artifact.js +49 -0
  100. package/src/verax/core/ga/ga.contract.js +434 -0
  101. package/src/verax/core/ga/ga.enforcer.js +86 -0
  102. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  103. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  104. package/src/verax/core/guardrails/policy.loader.js +83 -0
  105. package/src/verax/core/guardrails/policy.schema.js +110 -0
  106. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  107. package/src/verax/core/guardrails-engine.js +505 -0
  108. package/src/verax/core/incremental-store.js +15 -7
  109. package/src/verax/core/observe/run-timeline.js +316 -0
  110. package/src/verax/core/perf/perf.contract.js +186 -0
  111. package/src/verax/core/perf/perf.display.js +65 -0
  112. package/src/verax/core/perf/perf.enforcer.js +91 -0
  113. package/src/verax/core/perf/perf.monitor.js +209 -0
  114. package/src/verax/core/perf/perf.report.js +198 -0
  115. package/src/verax/core/pipeline-tracker.js +238 -0
  116. package/src/verax/core/product-definition.js +127 -0
  117. package/src/verax/core/release/provenance.builder.js +271 -0
  118. package/src/verax/core/release/release-report-writer.js +40 -0
  119. package/src/verax/core/release/release.enforcer.js +159 -0
  120. package/src/verax/core/release/reproducibility.check.js +221 -0
  121. package/src/verax/core/release/sbom.builder.js +283 -0
  122. package/src/verax/core/replay-validator.js +4 -4
  123. package/src/verax/core/replay.js +1 -1
  124. package/src/verax/core/report/cross-index.js +192 -0
  125. package/src/verax/core/report/human-summary.js +222 -0
  126. package/src/verax/core/route-intelligence.js +419 -0
  127. package/src/verax/core/security/secrets.scan.js +326 -0
  128. package/src/verax/core/security/security-report.js +50 -0
  129. package/src/verax/core/security/security.enforcer.js +124 -0
  130. package/src/verax/core/security/supplychain.defaults.json +38 -0
  131. package/src/verax/core/security/supplychain.policy.js +326 -0
  132. package/src/verax/core/security/vuln.scan.js +265 -0
  133. package/src/verax/core/silence-impact.js +1 -1
  134. package/src/verax/core/silence-model.js +9 -7
  135. package/src/verax/core/truth/truth.certificate.js +250 -0
  136. package/src/verax/core/ui-feedback-intelligence.js +515 -0
  137. package/src/verax/detect/comparison.js +8 -3
  138. package/src/verax/detect/confidence-engine.js +645 -57
  139. package/src/verax/detect/confidence-helper.js +33 -0
  140. package/src/verax/detect/detection-engine.js +19 -2
  141. package/src/verax/detect/dynamic-route-findings.js +335 -0
  142. package/src/verax/detect/evidence-index.js +15 -65
  143. package/src/verax/detect/expectation-chain-detector.js +417 -0
  144. package/src/verax/detect/expectation-model.js +56 -3
  145. package/src/verax/detect/explanation-helpers.js +1 -1
  146. package/src/verax/detect/finding-detector.js +2 -2
  147. package/src/verax/detect/findings-writer.js +149 -20
  148. package/src/verax/detect/flow-detector.js +4 -4
  149. package/src/verax/detect/index.js +265 -15
  150. package/src/verax/detect/interactive-findings.js +3 -4
  151. package/src/verax/detect/journey-stall-detector.js +558 -0
  152. package/src/verax/detect/route-findings.js +218 -0
  153. package/src/verax/detect/signal-mapper.js +2 -2
  154. package/src/verax/detect/skip-classifier.js +4 -4
  155. package/src/verax/detect/ui-feedback-findings.js +207 -0
  156. package/src/verax/detect/verdict-engine.js +61 -9
  157. package/src/verax/detect/view-switch-correlator.js +242 -0
  158. package/src/verax/flow/flow-engine.js +3 -2
  159. package/src/verax/flow/flow-spec.js +1 -2
  160. package/src/verax/index.js +413 -33
  161. package/src/verax/intel/effect-detector.js +1 -1
  162. package/src/verax/intel/index.js +2 -2
  163. package/src/verax/intel/route-extractor.js +3 -3
  164. package/src/verax/intel/vue-navigation-extractor.js +81 -18
  165. package/src/verax/intel/vue-router-extractor.js +4 -2
  166. package/src/verax/learn/action-contract-extractor.js +684 -66
  167. package/src/verax/learn/ast-contract-extractor.js +53 -1
  168. package/src/verax/learn/index.js +36 -2
  169. package/src/verax/learn/manifest-writer.js +28 -14
  170. package/src/verax/learn/route-extractor.js +1 -1
  171. package/src/verax/learn/route-validator.js +12 -8
  172. package/src/verax/learn/state-extractor.js +1 -1
  173. package/src/verax/learn/static-extractor-navigation.js +1 -1
  174. package/src/verax/learn/static-extractor-validation.js +2 -2
  175. package/src/verax/learn/static-extractor.js +8 -7
  176. package/src/verax/learn/ts-contract-resolver.js +14 -12
  177. package/src/verax/observe/browser.js +22 -3
  178. package/src/verax/observe/console-sensor.js +2 -2
  179. package/src/verax/observe/expectation-executor.js +2 -1
  180. package/src/verax/observe/focus-sensor.js +1 -1
  181. package/src/verax/observe/human-driver.js +29 -10
  182. package/src/verax/observe/index.js +92 -844
  183. package/src/verax/observe/interaction-discovery.js +27 -15
  184. package/src/verax/observe/interaction-runner.js +31 -14
  185. package/src/verax/observe/loading-sensor.js +6 -0
  186. package/src/verax/observe/navigation-sensor.js +1 -1
  187. package/src/verax/observe/observe-context.js +205 -0
  188. package/src/verax/observe/observe-helpers.js +191 -0
  189. package/src/verax/observe/observe-runner.js +226 -0
  190. package/src/verax/observe/observers/budget-observer.js +185 -0
  191. package/src/verax/observe/observers/console-observer.js +102 -0
  192. package/src/verax/observe/observers/coverage-observer.js +107 -0
  193. package/src/verax/observe/observers/interaction-observer.js +471 -0
  194. package/src/verax/observe/observers/navigation-observer.js +132 -0
  195. package/src/verax/observe/observers/network-observer.js +87 -0
  196. package/src/verax/observe/observers/safety-observer.js +82 -0
  197. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  198. package/src/verax/observe/settle.js +1 -0
  199. package/src/verax/observe/state-sensor.js +8 -4
  200. package/src/verax/observe/state-ui-sensor.js +7 -1
  201. package/src/verax/observe/traces-writer.js +27 -16
  202. package/src/verax/observe/ui-feedback-detector.js +742 -0
  203. package/src/verax/observe/ui-signal-sensor.js +155 -2
  204. package/src/verax/scan-summary-writer.js +46 -9
  205. package/src/verax/shared/artifact-manager.js +9 -6
  206. package/src/verax/shared/budget-profiles.js +2 -2
  207. package/src/verax/shared/caching.js +1 -1
  208. package/src/verax/shared/config-loader.js +1 -2
  209. package/src/verax/shared/css-spinner-rules.js +204 -0
  210. package/src/verax/shared/dynamic-route-utils.js +12 -6
  211. package/src/verax/shared/retry-policy.js +1 -6
  212. package/src/verax/shared/root-artifacts.js +1 -1
  213. package/src/verax/shared/view-switch-rules.js +208 -0
  214. package/src/verax/shared/zip-artifacts.js +1 -0
  215. package/src/verax/validate/context-validator.js +1 -1
  216. package/src/verax/observe/index.js.backup +0 -1
  217. package/src/verax/validate/context-validator.js.bak +0 -0
@@ -0,0 +1,484 @@
1
+ /**
2
+ * PHASE 21.4 — Confidence Engine (Policy-Driven with Truth Locks)
3
+ *
4
+ * Central confidence engine that computes confidence scores using policies.
5
+ * Truth locks are enforced and cannot be configured away.
6
+ */
7
+
8
+ import { computeConfidence as computeConfidenceLegacy } from '../detect/confidence-engine.js';
9
+ import { loadConfidencePolicy, getPolicyReport } from './confidence/confidence.loader.js';
10
+
11
+ // Re-export constants for backward compatibility
12
+ export const CONFIDENCE_LEVEL = {
13
+ HIGH: 'HIGH',
14
+ MEDIUM: 'MEDIUM',
15
+ LOW: 'LOW',
16
+ UNPROVEN: 'UNPROVEN',
17
+ };
18
+
19
+ export const CONFIDENCE_REASON = {
20
+ // Promise Strength (A)
21
+ PROMISE_AST_BASED: 'PROMISE_AST_BASED',
22
+ PROMISE_PROVEN: 'PROMISE_PROVEN',
23
+ PROMISE_OBSERVED: 'PROMISE_OBSERVED',
24
+ PROMISE_WEAK: 'PROMISE_WEAK',
25
+ PROMISE_UNKNOWN: 'PROMISE_UNKNOWN',
26
+
27
+ // Observation Strength (B)
28
+ OBS_URL_CHANGED: 'OBS_URL_CHANGED',
29
+ OBS_DOM_CHANGED: 'OBS_DOM_CHANGED',
30
+ OBS_UI_FEEDBACK_CONFIRMED: 'OBS_UI_FEEDBACK_CONFIRMED',
31
+ OBS_CONSOLE_ERRORS: 'OBS_CONSOLE_ERRORS',
32
+ OBS_NETWORK_FAILURE: 'OBS_NETWORK_FAILURE',
33
+ OBS_NETWORK_SUCCESS: 'OBS_NETWORK_SUCCESS',
34
+ OBS_NO_SIGNALS: 'OBS_NO_SIGNALS',
35
+
36
+ // Correlation Quality (C)
37
+ CORR_TIMING_ALIGNED: 'CORR_TIMING_ALIGNED',
38
+ CORR_ROUTE_MATCHED: 'CORR_ROUTE_MATCHED',
39
+ CORR_REQUEST_MATCHED: 'CORR_REQUEST_MATCHED',
40
+ CORR_TRACE_LINKED: 'CORR_TRACE_LINKED',
41
+ CORR_WEAK_CORRELATION: 'CORR_WEAK_CORRELATION',
42
+
43
+ // Guardrails & Contradictions (D)
44
+ GUARD_ANALYTICS_FILTERED: 'GUARD_ANALYTICS_FILTERED',
45
+ GUARD_SHALLOW_ROUTING: 'GUARD_SHALLOW_ROUTING',
46
+ GUARD_NETWORK_SUCCESS_NO_UI: 'GUARD_NETWORK_SUCCESS_NO_UI',
47
+ GUARD_UI_FEEDBACK_PRESENT: 'GUARD_UI_FEEDBACK_PRESENT',
48
+ GUARD_CONTRADICTION_DETECTED: 'GUARD_CONTRADICTION_DETECTED',
49
+
50
+ // Evidence Completeness (E)
51
+ EVIDENCE_SCREENSHOTS: 'EVIDENCE_SCREENSHOTS',
52
+ EVIDENCE_TRACES: 'EVIDENCE_TRACES',
53
+ EVIDENCE_SIGNALS: 'EVIDENCE_SIGNALS',
54
+ EVIDENCE_SNIPPETS: 'EVIDENCE_SNIPPETS',
55
+ EVIDENCE_INCOMPLETE: 'EVIDENCE_INCOMPLETE',
56
+
57
+ // Sensor Presence
58
+ SENSOR_NETWORK_PRESENT: 'SENSOR_NETWORK_PRESENT',
59
+ SENSOR_CONSOLE_PRESENT: 'SENSOR_CONSOLE_PRESENT',
60
+ SENSOR_UI_PRESENT: 'SENSOR_UI_PRESENT',
61
+ SENSOR_UI_FEEDBACK_PRESENT: 'SENSOR_UI_FEEDBACK_PRESENT',
62
+ SENSOR_MISSING: 'SENSOR_MISSING',
63
+ };
64
+
65
+ // Global policy cache
66
+ let cachedPolicy = null;
67
+
68
+ /**
69
+ * Get confidence policy (cached)
70
+ */
71
+ function getConfidencePolicy(policyPath = null, projectDir = null) {
72
+ if (!cachedPolicy) {
73
+ cachedPolicy = loadConfidencePolicy(policyPath, projectDir);
74
+ }
75
+ return cachedPolicy;
76
+ }
77
+
78
+ /**
79
+ * PHASE 21.4: Compute unified confidence using policy
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
+ * @param {Object} params.options - Options { policyPath, projectDir, determinismVerdict, evidencePackage }
88
+ * @returns {Object} { score, level, reasons[], policyReport }
89
+ */
90
+ export function computeUnifiedConfidence({ findingType, expectation, sensors = {}, comparisons = {}, evidence = {}, options = {} }) {
91
+ const policy = getConfidencePolicy(options.policyPath, options.projectDir);
92
+ const reasons = [];
93
+
94
+ // === PILLAR A: Promise Strength ===
95
+ const promiseStrength = assessPromiseStrength(expectation, reasons, policy);
96
+
97
+ // === PILLAR B: Observation Strength ===
98
+ const observationStrength = assessObservationStrength(sensors, comparisons, reasons, policy);
99
+
100
+ // === PILLAR C: Correlation Quality ===
101
+ const correlationQuality = assessCorrelationQuality(expectation, sensors, comparisons, evidence, reasons, policy);
102
+
103
+ // === PILLAR D: Guardrails & Contradictions ===
104
+ const guardrails = assessGuardrails(sensors, comparisons, findingType, reasons, policy);
105
+
106
+ // === PILLAR E: Evidence Completeness ===
107
+ const evidenceCompleteness = assessEvidenceCompleteness(evidence, sensors, reasons, policy);
108
+
109
+ // === COMPUTE BASE SCORE using policy weights ===
110
+ const baseScore = (
111
+ promiseStrength * policy.weights.promiseStrength +
112
+ observationStrength * policy.weights.observationStrength +
113
+ correlationQuality * policy.weights.correlationQuality +
114
+ guardrails * policy.weights.guardrails +
115
+ evidenceCompleteness * policy.weights.evidenceCompleteness
116
+ );
117
+
118
+ // === APPLY CONTRADICTIONS using policy ===
119
+ const contradictionPenalty = guardrails < 0.5 ? policy.truthLocks.contradictionPenalty : 0;
120
+ let finalScore = Math.max(0, Math.min(1, baseScore - contradictionPenalty));
121
+
122
+ // === TRUTH LOCKS: Apply determinism cap ===
123
+ if (options.determinismVerdict === 'NON_DETERMINISTIC') {
124
+ const maxConfidence = policy.truthLocks.nonDeterministicMaxConfidence;
125
+ if (finalScore > maxConfidence) {
126
+ reasons.push('TRUTH_LOCK_NON_DETERMINISTIC_CAP');
127
+ finalScore = Math.min(finalScore, maxConfidence);
128
+ }
129
+ }
130
+
131
+ // === TRUTH LOCKS: Evidence Law cap ===
132
+ const evidencePackage = options.evidencePackage || evidence.evidencePackage || {};
133
+ if (evidencePackage.severity === 'CONFIRMED' || evidencePackage.status === 'CONFIRMED') {
134
+ if (policy.truthLocks.evidenceCompleteRequired && !evidencePackage.isComplete) {
135
+ reasons.push('TRUTH_LOCK_EVIDENCE_INCOMPLETE');
136
+ // Force downgrade from CONFIRMED
137
+ finalScore = Math.min(finalScore, 0.6); // Cap at MEDIUM
138
+ }
139
+ }
140
+
141
+ // === DETERMINE LEVEL using policy thresholds ===
142
+ const level = determineConfidenceLevel(finalScore, promiseStrength, evidenceCompleteness, policy);
143
+
144
+ const policyReport = getPolicyReport(policy);
145
+
146
+ return {
147
+ score: finalScore,
148
+ level,
149
+ reasons: reasons.slice(0, 10),
150
+ policyReport: {
151
+ version: policyReport.version,
152
+ source: policyReport.source,
153
+ thresholds: policyReport.thresholds
154
+ }
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Assess promise strength (Pillar A) using policy
160
+ */
161
+ function assessPromiseStrength(expectation, reasons, policy) {
162
+ if (!expectation) {
163
+ reasons.push(CONFIDENCE_REASON.PROMISE_UNKNOWN);
164
+ return 0.0;
165
+ }
166
+
167
+ const isASTBased = expectation.source?.astSource || expectation.metadata?.astSource;
168
+ if (isASTBased) {
169
+ reasons.push(CONFIDENCE_REASON.PROMISE_AST_BASED);
170
+ }
171
+
172
+ const proof = expectation.proof || 'UNKNOWN';
173
+ if (proof === 'PROVEN_EXPECTATION' || proof === 'PROVEN') {
174
+ reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
175
+ return policy.baseScores.promiseProven;
176
+ }
177
+
178
+ if (proof === 'OBSERVED' || expectation.confidence >= 0.8) {
179
+ reasons.push(CONFIDENCE_REASON.PROMISE_OBSERVED);
180
+ return policy.baseScores.promiseObserved;
181
+ }
182
+
183
+ if (expectation.confidence >= 0.5) {
184
+ reasons.push(CONFIDENCE_REASON.PROMISE_WEAK);
185
+ return policy.baseScores.promiseWeak;
186
+ }
187
+
188
+ reasons.push(CONFIDENCE_REASON.PROMISE_UNKNOWN);
189
+ return policy.baseScores.promiseUnknown;
190
+ }
191
+
192
+ /**
193
+ * Assess observation strength (Pillar B) using policy
194
+ */
195
+ function assessObservationStrength(sensors, comparisons, reasons, policy) {
196
+ let strength = 0.0;
197
+ let signals = 0;
198
+
199
+ const urlChanged = sensors.navigation?.urlChanged === true || comparisons.urlChanged === true;
200
+ if (urlChanged) {
201
+ reasons.push(CONFIDENCE_REASON.OBS_URL_CHANGED);
202
+ strength += policy.baseScores.urlChanged;
203
+ signals++;
204
+ }
205
+
206
+ const domChanged = sensors.dom?.changed === true || comparisons.domChanged === true;
207
+ if (domChanged) {
208
+ reasons.push(CONFIDENCE_REASON.OBS_DOM_CHANGED);
209
+ strength += policy.baseScores.domChanged;
210
+ signals++;
211
+ }
212
+
213
+ const uiFeedback = sensors.uiFeedback || {};
214
+ const uiFeedbackScore = uiFeedback.overallUiFeedbackScore || 0;
215
+ if (uiFeedbackScore > 0.5) {
216
+ reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
217
+ strength += policy.baseScores.uiFeedbackConfirmed;
218
+ signals++;
219
+ }
220
+
221
+ const consoleErrors = sensors.console?.errors > 0 || sensors.console?.errorCount > 0;
222
+ if (consoleErrors) {
223
+ reasons.push(CONFIDENCE_REASON.OBS_CONSOLE_ERRORS);
224
+ strength += policy.baseScores.consoleErrors;
225
+ signals++;
226
+ }
227
+
228
+ const networkFailure = sensors.network?.failedRequests > 0 || sensors.network?.topFailedUrls?.length > 0;
229
+ if (networkFailure) {
230
+ reasons.push(CONFIDENCE_REASON.OBS_NETWORK_FAILURE);
231
+ strength += policy.baseScores.networkFailure;
232
+ signals++;
233
+ }
234
+
235
+ const networkSuccess = sensors.network?.successfulRequests > 0 && !networkFailure;
236
+ if (networkSuccess) {
237
+ reasons.push(CONFIDENCE_REASON.OBS_NETWORK_SUCCESS);
238
+ strength += policy.baseScores.networkSuccess;
239
+ signals++;
240
+ }
241
+
242
+ if (signals === 0) {
243
+ reasons.push(CONFIDENCE_REASON.OBS_NO_SIGNALS);
244
+ return 0.0;
245
+ }
246
+
247
+ return Math.min(1.0, strength);
248
+ }
249
+
250
+ /**
251
+ * Assess correlation quality (Pillar C) using policy
252
+ */
253
+ function assessCorrelationQuality(expectation, sensors, comparisons, evidence, reasons, policy) {
254
+ let quality = 0.5;
255
+
256
+ if (evidence.timing || sensors.timing) {
257
+ reasons.push(CONFIDENCE_REASON.CORR_TIMING_ALIGNED);
258
+ quality += policy.baseScores.timingAligned;
259
+ }
260
+
261
+ if (evidence.correlation?.routeMatched === true || evidence.routeDefinition?.path) {
262
+ reasons.push(CONFIDENCE_REASON.CORR_ROUTE_MATCHED);
263
+ quality += policy.baseScores.routeMatched;
264
+ }
265
+
266
+ if (evidence.networkRequest?.matched === true || evidence.correlation?.requestMatched === true) {
267
+ reasons.push(CONFIDENCE_REASON.CORR_REQUEST_MATCHED);
268
+ quality += policy.baseScores.requestMatched;
269
+ }
270
+
271
+ if (evidence.traceId || evidence.source?.file) {
272
+ reasons.push(CONFIDENCE_REASON.CORR_TRACE_LINKED);
273
+ quality += policy.baseScores.traceLinked;
274
+ }
275
+
276
+ if (quality < 0.6) {
277
+ reasons.push(CONFIDENCE_REASON.CORR_WEAK_CORRELATION);
278
+ }
279
+
280
+ return Math.min(1.0, quality);
281
+ }
282
+
283
+ /**
284
+ * Assess guardrails & contradictions (Pillar D) using policy
285
+ */
286
+ function assessGuardrails(sensors, comparisons, findingType, reasons, policy) {
287
+ let guardrailScore = 1.0;
288
+
289
+ const networkSensor = sensors.network || {};
290
+ const hasAnalytics = networkSensor.observedRequestUrls?.some(url =>
291
+ url && typeof url === 'string' && url.includes('/api/analytics')
292
+ );
293
+ if (hasAnalytics && !sensors.navigation?.urlChanged && !sensors.uiSignals?.diff?.changed) {
294
+ reasons.push(CONFIDENCE_REASON.GUARD_ANALYTICS_FILTERED);
295
+ guardrailScore -= 0.2;
296
+ }
297
+
298
+ if (sensors.navigation?.shallowRouting === true && !sensors.navigation?.urlChanged) {
299
+ reasons.push(CONFIDENCE_REASON.GUARD_SHALLOW_ROUTING);
300
+ guardrailScore -= 0.3;
301
+ }
302
+
303
+ const networkSuccess = networkSensor.successfulRequests > 0;
304
+ const noUIChange = !sensors.uiSignals?.diff?.changed && !sensors.uiFeedback?.overallUiFeedbackScore;
305
+ if (networkSuccess && noUIChange && findingType?.includes('silent_failure')) {
306
+ reasons.push(CONFIDENCE_REASON.GUARD_NETWORK_SUCCESS_NO_UI);
307
+ guardrailScore -= 0.2;
308
+ }
309
+
310
+ const uiFeedbackScore = sensors.uiFeedback?.overallUiFeedbackScore || 0;
311
+ if (uiFeedbackScore > 0.5 && findingType?.includes('silent_failure')) {
312
+ reasons.push(CONFIDENCE_REASON.GUARD_UI_FEEDBACK_PRESENT);
313
+ guardrailScore -= 0.4;
314
+ }
315
+
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) using policy
325
+ */
326
+ function assessEvidenceCompleteness(evidence, sensors, reasons, policy) {
327
+ let completeness = 0.0;
328
+
329
+ if (evidence.beforeAfter?.beforeScreenshot && evidence.beforeAfter?.afterScreenshot) {
330
+ reasons.push(CONFIDENCE_REASON.EVIDENCE_SCREENSHOTS);
331
+ completeness += policy.baseScores.screenshots;
332
+ }
333
+
334
+ if (evidence.traceId || sensors.traceId) {
335
+ reasons.push(CONFIDENCE_REASON.EVIDENCE_TRACES);
336
+ completeness += policy.baseScores.traces;
337
+ }
338
+
339
+ if (evidence.signals && Object.keys(evidence.signals).length > 0) {
340
+ reasons.push(CONFIDENCE_REASON.EVIDENCE_SIGNALS);
341
+ completeness += policy.baseScores.signals;
342
+ }
343
+
344
+ if (evidence.source?.astSource || evidence.navigationTrigger?.astSource) {
345
+ reasons.push(CONFIDENCE_REASON.EVIDENCE_SNIPPETS);
346
+ completeness += policy.baseScores.snippets;
347
+ }
348
+
349
+ if (completeness < 0.5) {
350
+ reasons.push(CONFIDENCE_REASON.EVIDENCE_INCOMPLETE);
351
+ }
352
+
353
+ return completeness;
354
+ }
355
+
356
+ /**
357
+ * Determine confidence level using policy thresholds
358
+ */
359
+ function determineConfidenceLevel(score, promiseStrength, evidenceCompleteness, policy) {
360
+ const thresholds = policy.thresholds;
361
+
362
+ if (score >= thresholds.high && promiseStrength >= 0.9 && evidenceCompleteness >= 0.7) {
363
+ return CONFIDENCE_LEVEL.HIGH;
364
+ }
365
+
366
+ if (score >= thresholds.medium || (score >= 0.5 && promiseStrength >= 0.7)) {
367
+ return CONFIDENCE_LEVEL.MEDIUM;
368
+ }
369
+
370
+ if (score >= thresholds.low) {
371
+ return CONFIDENCE_LEVEL.LOW;
372
+ }
373
+
374
+ return CONFIDENCE_LEVEL.UNPROVEN;
375
+ }
376
+
377
+ /**
378
+ * PHASE 21.4: Compute confidence for finding (wrapper with policy support)
379
+ *
380
+ * @param {Object} params - Confidence computation parameters
381
+ * @param {Object} params.options - Options { policyPath, projectDir, determinismVerdict, evidencePackage }
382
+ * @returns {Object} { score, level, reasons[] }
383
+ */
384
+ export function computeConfidenceForFinding(params) {
385
+ const options = params.options || {};
386
+
387
+ // Use legacy system for base computation
388
+ const legacyResult = computeConfidenceLegacy(params);
389
+
390
+ // Normalize score from 0-100 to 0-1
391
+ let normalizedScore = (legacyResult.score || 0) / 100;
392
+
393
+ // Extract reasons from legacy explain/factors
394
+ const reasons = extractReasonsFromLegacy(legacyResult, params);
395
+
396
+ // Load policy for truth locks
397
+ const policy = getConfidencePolicy(options.policyPath, options.projectDir);
398
+
399
+ // === TRUTH LOCKS: Apply determinism cap ===
400
+ if (options.determinismVerdict === 'NON_DETERMINISTIC') {
401
+ const maxConfidence = policy.truthLocks.nonDeterministicMaxConfidence;
402
+ if (normalizedScore > maxConfidence) {
403
+ reasons.push('TRUTH_LOCK_NON_DETERMINISTIC_CAP');
404
+ normalizedScore = Math.min(normalizedScore, maxConfidence);
405
+ }
406
+ }
407
+
408
+ // === TRUTH LOCKS: Evidence Law cap ===
409
+ const evidencePackage = options.evidencePackage || params.evidence?.evidencePackage || {};
410
+ if (evidencePackage.severity === 'CONFIRMED' || evidencePackage.status === 'CONFIRMED') {
411
+ if (policy.truthLocks.evidenceCompleteRequired && !evidencePackage.isComplete) {
412
+ reasons.push('TRUTH_LOCK_EVIDENCE_INCOMPLETE');
413
+ normalizedScore = Math.min(normalizedScore, 0.6);
414
+ }
415
+ }
416
+
417
+ // Determine level using policy thresholds
418
+ const level = determineConfidenceLevel(
419
+ normalizedScore,
420
+ assessPromiseStrength(params.expectation, [], policy),
421
+ assessEvidenceCompleteness(params.evidence || {}, params.sensors || {}, [], policy),
422
+ policy
423
+ );
424
+
425
+ return {
426
+ score: normalizedScore,
427
+ level,
428
+ reasons,
429
+ };
430
+ }
431
+
432
+ /**
433
+ * Extract stable reason codes from legacy confidence result
434
+ */
435
+ function extractReasonsFromLegacy(legacyResult, params) {
436
+ const reasons = [];
437
+
438
+ if (legacyResult.explain && Array.isArray(legacyResult.explain)) {
439
+ for (const explanation of legacyResult.explain) {
440
+ if (typeof explanation === 'string') {
441
+ if (explanation.includes('AST') || explanation.includes('proven')) {
442
+ reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
443
+ }
444
+ if (explanation.includes('network') && explanation.includes('failed')) {
445
+ reasons.push(CONFIDENCE_REASON.OBS_NETWORK_FAILURE);
446
+ }
447
+ if (explanation.includes('UI feedback')) {
448
+ reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
449
+ }
450
+ if (explanation.includes('contradiction')) {
451
+ reasons.push(CONFIDENCE_REASON.GUARD_CONTRADICTION_DETECTED);
452
+ }
453
+ }
454
+ }
455
+ }
456
+
457
+ if (legacyResult.factors && Array.isArray(legacyResult.factors)) {
458
+ for (const factor of legacyResult.factors) {
459
+ if (factor.key === 'promise_strength' && factor.value === 'PROVEN') {
460
+ reasons.push(CONFIDENCE_REASON.PROMISE_PROVEN);
461
+ }
462
+ if (factor.key === 'ui_feedback_score' && parseFloat(factor.value) > 0.5) {
463
+ reasons.push(CONFIDENCE_REASON.OBS_UI_FEEDBACK_CONFIRMED);
464
+ }
465
+ }
466
+ }
467
+
468
+ const sensors = params.sensors || {};
469
+ if (sensors.network && Object.keys(sensors.network).length > 0) {
470
+ reasons.push(CONFIDENCE_REASON.SENSOR_NETWORK_PRESENT);
471
+ }
472
+ if (sensors.console && Object.keys(sensors.console).length > 0) {
473
+ reasons.push(CONFIDENCE_REASON.SENSOR_CONSOLE_PRESENT);
474
+ }
475
+ if (sensors.uiSignals && Object.keys(sensors.uiSignals).length > 0) {
476
+ reasons.push(CONFIDENCE_REASON.SENSOR_UI_PRESENT);
477
+ }
478
+ if (sensors.uiFeedback && Object.keys(sensors.uiFeedback).length > 0) {
479
+ reasons.push(CONFIDENCE_REASON.SENSOR_UI_FEEDBACK_PRESENT);
480
+ }
481
+
482
+ return [...new Set(reasons)];
483
+ }
484
+