@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,234 @@
1
+ /**
2
+ * PHASE 24 — Confidence Invariants (Immutable Rules)
3
+ *
4
+ * Formal confidence invariants that MUST be enforced.
5
+ * Violations trigger automatic downgrades and are recorded.
6
+ */
7
+
8
+ /**
9
+ * Confidence invariant violation reason codes
10
+ */
11
+ export const INVARIANT_VIOLATION = {
12
+ CONFIRMED_BELOW_MIN: 'INV_CONFIRMED_BELOW_MIN',
13
+ SUSPECTED_ABOVE_MAX: 'INV_SUSPECTED_ABOVE_MAX',
14
+ SUSPECTED_BELOW_MIN: 'INV_SUSPECTED_BELOW_MIN',
15
+ INFORMATIONAL_ABOVE_MAX: 'INV_INFORMATIONAL_ABOVE_MAX',
16
+ INFORMATIONAL_BELOW_MIN: 'INV_INFORMATIONAL_BELOW_MIN',
17
+ IGNORED_NON_ZERO: 'INV_IGNORED_NON_ZERO',
18
+ UNPROVEN_EXPECTATION_ABOVE_MAX: 'INV_UNPROVEN_EXPECTATION_ABOVE_MAX',
19
+ VERIFIED_WITH_ERRORS_ABOVE_MAX: 'INV_VERIFIED_WITH_ERRORS_ABOVE_MAX',
20
+ GUARDRAILS_DOWNGRADE_OVERRIDE: 'INV_GUARDRAILS_DOWNGRADE_OVERRIDE'
21
+ };
22
+
23
+ /**
24
+ * Confidence ranges by status (immutable)
25
+ */
26
+ export const CONFIDENCE_RANGES = {
27
+ CONFIRMED: { min: 0.70, max: 1.00 },
28
+ SUSPECTED: { min: 0.30, max: 0.69 },
29
+ INFORMATIONAL: { min: 0.01, max: 0.29 },
30
+ IGNORED: { min: 0.00, max: 0.00 }
31
+ };
32
+
33
+ /**
34
+ * Special caps
35
+ */
36
+ export const CONFIDENCE_CAPS = {
37
+ UNPROVEN_EXPECTATION: 0.39,
38
+ VERIFIED_WITH_ERRORS: 0.49
39
+ };
40
+
41
+ /**
42
+ * Check if confidence violates invariants for a given status
43
+ *
44
+ * @param {number} confidence - Confidence score (0..1)
45
+ * @param {string} status - Finding status (CONFIRMED, SUSPECTED, etc.)
46
+ * @param {Object} context - Context { expectationProof, verificationStatus, guardrailsOutcome }
47
+ * @returns {Object} { violated: boolean, violations: [], correctedConfidence: number }
48
+ */
49
+ export function checkConfidenceInvariants(confidence, status, context = {}) {
50
+ const violations = [];
51
+ let correctedConfidence = confidence;
52
+
53
+ // Rule 1: CONFIRMED ⇒ confidence ∈ [0.70 – 1.00]
54
+ if (status === 'CONFIRMED') {
55
+ if (confidence < CONFIDENCE_RANGES.CONFIRMED.min) {
56
+ violations.push({
57
+ code: INVARIANT_VIOLATION.CONFIRMED_BELOW_MIN,
58
+ message: `CONFIRMED status requires confidence >= ${CONFIDENCE_RANGES.CONFIRMED.min}, got ${confidence}`,
59
+ corrected: CONFIDENCE_RANGES.CONFIRMED.min
60
+ });
61
+ correctedConfidence = CONFIDENCE_RANGES.CONFIRMED.min;
62
+ }
63
+ if (confidence > CONFIDENCE_RANGES.CONFIRMED.max) {
64
+ correctedConfidence = CONFIDENCE_RANGES.CONFIRMED.max;
65
+ }
66
+ }
67
+
68
+ // Rule 2: SUSPECTED ⇒ confidence ∈ [0.30 – 0.69]
69
+ if (status === 'SUSPECTED') {
70
+ if (confidence > CONFIDENCE_RANGES.SUSPECTED.max) {
71
+ violations.push({
72
+ code: INVARIANT_VIOLATION.SUSPECTED_ABOVE_MAX,
73
+ message: `SUSPECTED status requires confidence <= ${CONFIDENCE_RANGES.SUSPECTED.max}, got ${confidence}`,
74
+ corrected: CONFIDENCE_RANGES.SUSPECTED.max
75
+ });
76
+ correctedConfidence = CONFIDENCE_RANGES.SUSPECTED.max;
77
+ }
78
+ if (confidence < CONFIDENCE_RANGES.SUSPECTED.min) {
79
+ violations.push({
80
+ code: INVARIANT_VIOLATION.SUSPECTED_BELOW_MIN,
81
+ message: `SUSPECTED status requires confidence >= ${CONFIDENCE_RANGES.SUSPECTED.min}, got ${confidence}`,
82
+ corrected: CONFIDENCE_RANGES.SUSPECTED.min
83
+ });
84
+ correctedConfidence = CONFIDENCE_RANGES.SUSPECTED.min;
85
+ }
86
+ }
87
+
88
+ // Rule 3: INFORMATIONAL ⇒ confidence ∈ [0.01 – 0.29]
89
+ if (status === 'INFORMATIONAL') {
90
+ if (confidence > CONFIDENCE_RANGES.INFORMATIONAL.max) {
91
+ violations.push({
92
+ code: INVARIANT_VIOLATION.INFORMATIONAL_ABOVE_MAX,
93
+ message: `INFORMATIONAL status requires confidence <= ${CONFIDENCE_RANGES.INFORMATIONAL.max}, got ${confidence}`,
94
+ corrected: CONFIDENCE_RANGES.INFORMATIONAL.max
95
+ });
96
+ correctedConfidence = CONFIDENCE_RANGES.INFORMATIONAL.max;
97
+ }
98
+ if (confidence < CONFIDENCE_RANGES.INFORMATIONAL.min) {
99
+ violations.push({
100
+ code: INVARIANT_VIOLATION.INFORMATIONAL_BELOW_MIN,
101
+ message: `INFORMATIONAL status requires confidence >= ${CONFIDENCE_RANGES.INFORMATIONAL.min}, got ${confidence}`,
102
+ corrected: CONFIDENCE_RANGES.INFORMATIONAL.min
103
+ });
104
+ correctedConfidence = CONFIDENCE_RANGES.INFORMATIONAL.min;
105
+ }
106
+ }
107
+
108
+ // Rule 4: IGNORED ⇒ confidence === 0
109
+ if (status === 'IGNORED') {
110
+ if (confidence !== 0) {
111
+ violations.push({
112
+ code: INVARIANT_VIOLATION.IGNORED_NON_ZERO,
113
+ message: `IGNORED status requires confidence === 0, got ${confidence}`,
114
+ corrected: 0
115
+ });
116
+ correctedConfidence = 0;
117
+ }
118
+ }
119
+
120
+ // Rule 5: UNPROVEN_EXPECTATION ⇒ confidence ≤ 0.39
121
+ if (context.expectationProof === 'UNPROVEN_EXPECTATION') {
122
+ if (correctedConfidence > CONFIDENCE_CAPS.UNPROVEN_EXPECTATION) {
123
+ violations.push({
124
+ code: INVARIANT_VIOLATION.UNPROVEN_EXPECTATION_ABOVE_MAX,
125
+ message: `UNPROVEN_EXPECTATION requires confidence <= ${CONFIDENCE_CAPS.UNPROVEN_EXPECTATION}, got ${correctedConfidence}`,
126
+ corrected: CONFIDENCE_CAPS.UNPROVEN_EXPECTATION
127
+ });
128
+ correctedConfidence = CONFIDENCE_CAPS.UNPROVEN_EXPECTATION;
129
+ }
130
+ }
131
+
132
+ // Rule 6: VERIFIED_WITH_ERRORS ⇒ confidence capped at 0.49
133
+ if (context.verificationStatus === 'VERIFIED_WITH_ERRORS') {
134
+ if (correctedConfidence > CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS) {
135
+ violations.push({
136
+ code: INVARIANT_VIOLATION.VERIFIED_WITH_ERRORS_ABOVE_MAX,
137
+ message: `VERIFIED_WITH_ERRORS requires confidence <= ${CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS}, got ${correctedConfidence}`,
138
+ corrected: CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS
139
+ });
140
+ correctedConfidence = CONFIDENCE_CAPS.VERIFIED_WITH_ERRORS;
141
+ }
142
+ }
143
+
144
+ // Rule 7: Guardrails downgrade ALWAYS overrides raw confidence
145
+ if (context.guardrailsOutcome && context.guardrailsOutcome.downgraded) {
146
+ const guardrailsFinalDecision = context.guardrailsOutcome.finalDecision || context.guardrailsOutcome.recommendedStatus;
147
+ if (guardrailsFinalDecision && guardrailsFinalDecision !== status) {
148
+ // Guardrails changed the status, confidence must match the new status
149
+ const range = CONFIDENCE_RANGES[guardrailsFinalDecision];
150
+ if (range) {
151
+ if (correctedConfidence > range.max) {
152
+ violations.push({
153
+ code: INVARIANT_VIOLATION.GUARDRAILS_DOWNGRADE_OVERRIDE,
154
+ message: `Guardrails downgrade to ${guardrailsFinalDecision} requires confidence <= ${range.max}, got ${correctedConfidence}`,
155
+ corrected: range.max
156
+ });
157
+ correctedConfidence = range.max;
158
+ }
159
+ if (correctedConfidence < range.min && guardrailsFinalDecision !== 'IGNORED') {
160
+ violations.push({
161
+ code: INVARIANT_VIOLATION.GUARDRAILS_DOWNGRADE_OVERRIDE,
162
+ message: `Guardrails downgrade to ${guardrailsFinalDecision} requires confidence >= ${range.min}, got ${correctedConfidence}`,
163
+ corrected: range.min
164
+ });
165
+ correctedConfidence = range.min;
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ return {
172
+ violated: violations.length > 0,
173
+ violations,
174
+ correctedConfidence
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Enforce confidence invariants (mutates finding if needed)
180
+ *
181
+ * @param {Object} finding - Finding object
182
+ * @param {Object} context - Context for invariant checking
183
+ * @returns {Object} { finding: correctedFinding, violations: [] }
184
+ */
185
+ export function enforceConfidenceInvariants(finding, context = {}) {
186
+ const status = finding.severity || finding.status || 'SUSPECTED';
187
+ const confidence = finding.confidence !== undefined ? finding.confidence : 0;
188
+
189
+ const expectationProof = finding.expectation?.proof || context.expectationProof;
190
+ const verificationStatus = context.verificationStatus;
191
+ const guardrailsOutcome = finding.guardrails || context.guardrailsOutcome;
192
+
193
+ const invariantCheck = checkConfidenceInvariants(confidence, status, {
194
+ expectationProof,
195
+ verificationStatus,
196
+ guardrailsOutcome
197
+ });
198
+
199
+ if (invariantCheck.violated) {
200
+ // Apply corrections
201
+ const correctedFinding = {
202
+ ...finding,
203
+ confidence: invariantCheck.correctedConfidence,
204
+ confidenceLevel: determineConfidenceLevel(invariantCheck.correctedConfidence),
205
+ invariantViolations: invariantCheck.violations.map(v => ({
206
+ code: v.code,
207
+ message: v.message,
208
+ originalConfidence: confidence,
209
+ correctedConfidence: v.corrected
210
+ }))
211
+ };
212
+
213
+ return {
214
+ finding: correctedFinding,
215
+ violations: invariantCheck.violations
216
+ };
217
+ }
218
+
219
+ return {
220
+ finding,
221
+ violations: []
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Determine confidence level from score
227
+ */
228
+ function determineConfidenceLevel(score) {
229
+ if (score >= 0.80) return 'HIGH';
230
+ if (score >= 0.50) return 'MEDIUM';
231
+ if (score >= 0.20) return 'LOW';
232
+ return 'UNPROVEN';
233
+ }
234
+
@@ -0,0 +1,112 @@
1
+ /**
2
+ * PHASE 24 — Confidence Report Writer
3
+ *
4
+ * Writes confidence.report.json artifact per run.
5
+ */
6
+
7
+ import { writeFileSync } from 'fs';
8
+ import { resolve } from 'path';
9
+ import { ARTIFACT_REGISTRY } from '../artifacts/registry.js';
10
+
11
+ /**
12
+ * Write confidence report to disk.
13
+ *
14
+ * @param {string} runDir - Absolute run directory path
15
+ * @param {Array} findings - Array of findings with confidence data
16
+ * @param {Object} confidenceData - Map of findingIdentity -> confidence computation result
17
+ * @returns {string} Path to written report
18
+ */
19
+ export function writeConfidenceReport(runDir, findings, confidenceData = {}) {
20
+ const reportPath = resolve(runDir, ARTIFACT_REGISTRY.confidenceReport.filename);
21
+
22
+ // Build per-finding entries (deterministic ordering by findingIdentity)
23
+ const perFinding = {};
24
+ const summary = {
25
+ totalFindings: findings.length,
26
+ byConfidenceLevel: {
27
+ HIGH: 0,
28
+ MEDIUM: 0,
29
+ LOW: 0,
30
+ UNPROVEN: 0
31
+ },
32
+ byTruthStatus: {
33
+ CONFIRMED: 0,
34
+ SUSPECTED: 0,
35
+ INFORMATIONAL: 0,
36
+ IGNORED: 0
37
+ },
38
+ invariantViolationsCount: 0,
39
+ averageConfidenceBefore: 0,
40
+ averageConfidenceAfter: 0
41
+ };
42
+
43
+ let totalConfidenceBefore = 0;
44
+ let totalConfidenceAfter = 0;
45
+
46
+ for (const finding of findings) {
47
+ const findingIdentity = finding.findingId || finding.id || `finding-${findings.indexOf(finding)}`;
48
+ const confidenceResult = confidenceData[findingIdentity] || null;
49
+ const truthStatus = finding.severity || finding.status || 'SUSPECTED';
50
+
51
+ const confidenceBefore = confidenceResult?.confidenceBefore || finding.confidence || 0;
52
+ const confidenceAfter = confidenceResult?.confidenceAfter || finding.confidence || 0;
53
+ const confidenceLevel = confidenceResult?.confidenceLevel || finding.confidenceLevel || 'UNPROVEN';
54
+
55
+ totalConfidenceBefore += confidenceBefore;
56
+ totalConfidenceAfter += confidenceAfter;
57
+
58
+ // Track by confidence level
59
+ if (summary.byConfidenceLevel[confidenceLevel] !== undefined) {
60
+ summary.byConfidenceLevel[confidenceLevel]++;
61
+ }
62
+
63
+ // Track by truth status
64
+ if (summary.byTruthStatus[truthStatus] !== undefined) {
65
+ summary.byTruthStatus[truthStatus]++;
66
+ }
67
+
68
+ // Track invariant violations
69
+ const violations = confidenceResult?.invariantViolations || finding.invariantViolations || [];
70
+ if (violations.length > 0) {
71
+ summary.invariantViolationsCount += violations.length;
72
+ }
73
+
74
+ // Build per-finding entry
75
+ perFinding[findingIdentity] = {
76
+ confidenceBefore,
77
+ confidenceAfter,
78
+ confidenceLevel,
79
+ truthStatus,
80
+ appliedInvariants: confidenceResult?.appliedInvariants || [],
81
+ invariantViolations: violations.map(v => ({
82
+ code: v.code,
83
+ message: v.message,
84
+ originalConfidence: v.originalConfidence,
85
+ correctedConfidence: v.correctedConfidence || v.corrected
86
+ })),
87
+ explanation: confidenceResult?.explanation || finding.confidenceReasons || [],
88
+ expectationProof: confidenceResult?.expectationProof || finding.expectation?.proof || null,
89
+ verificationStatus: confidenceResult?.verificationStatus || null
90
+ };
91
+ }
92
+
93
+ // Compute averages
94
+ if (findings.length > 0) {
95
+ summary.averageConfidenceBefore = totalConfidenceBefore / findings.length;
96
+ summary.averageConfidenceAfter = totalConfidenceAfter / findings.length;
97
+ }
98
+
99
+ // Build report
100
+ const report = {
101
+ version: 1,
102
+ generatedAt: new Date().toISOString(),
103
+ summary,
104
+ perFinding
105
+ };
106
+
107
+ // Write to disk
108
+ writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
109
+
110
+ return reportPath;
111
+ }
112
+
@@ -0,0 +1,44 @@
1
+ /**
2
+ * PHASE 24 — Confidence Weights (Canonical)
3
+ *
4
+ * Canonical weights for evidence types.
5
+ * All capabilities MUST use these weights.
6
+ * No custom weighting allowed.
7
+ */
8
+
9
+ /**
10
+ * Canonical evidence weights (normalized, sum to 1.0)
11
+ */
12
+ export const CONFIDENCE_WEIGHTS = {
13
+ UI_EVIDENCE: 0.25,
14
+ NETWORK_EVIDENCE: 0.25,
15
+ STATE_EVIDENCE: 0.15,
16
+ ROUTE_EVIDENCE: 0.15,
17
+ CONSOLE_EVIDENCE: 0.10,
18
+ EVIDENCE_COMPLETENESS: 0.10
19
+ };
20
+
21
+ /**
22
+ * Validate that weights sum to 1.0
23
+ */
24
+ export function validateWeights(weights = CONFIDENCE_WEIGHTS) {
25
+ const sum = Object.values(weights).reduce((a, b) => a + b, 0);
26
+ if (Math.abs(sum - 1.0) > 0.001) {
27
+ throw new Error(`Confidence weights must sum to 1.0, got ${sum}`);
28
+ }
29
+ return true;
30
+ }
31
+
32
+ /**
33
+ * Get weight for evidence type
34
+ *
35
+ * @param {string} evidenceType - One of: UI_EVIDENCE, NETWORK_EVIDENCE, STATE_EVIDENCE, ROUTE_EVIDENCE, CONSOLE_EVIDENCE, EVIDENCE_COMPLETENESS
36
+ * @returns {number} Weight (0..1)
37
+ */
38
+ export function getEvidenceWeight(evidenceType) {
39
+ return CONFIDENCE_WEIGHTS[evidenceType] || 0;
40
+ }
41
+
42
+ // Validate on module load
43
+ validateWeights();
44
+
@@ -0,0 +1,65 @@
1
+ /**
2
+ * PHASE 21.4 — Confidence Policy Defaults
3
+ *
4
+ * Default confidence policy matching current hardcoded behavior.
5
+ * Truth locks are enforced and cannot be configured away.
6
+ */
7
+
8
+ /**
9
+ * Default confidence policy
10
+ *
11
+ * This policy matches the current hardcoded behavior exactly.
12
+ */
13
+ export const DEFAULT_CONFIDENCE_POLICY = {
14
+ version: '21.4.0',
15
+ source: 'default',
16
+ baseScores: {
17
+ promiseProven: 1.0,
18
+ promiseObserved: 0.7,
19
+ promiseWeak: 0.5,
20
+ promiseUnknown: 0.2,
21
+ urlChanged: 0.3,
22
+ domChanged: 0.2,
23
+ uiFeedbackConfirmed: 0.3,
24
+ consoleErrors: 0.2,
25
+ networkFailure: 0.3,
26
+ networkSuccess: 0.1,
27
+ timingAligned: 0.2,
28
+ routeMatched: 0.2,
29
+ requestMatched: 0.2,
30
+ traceLinked: 0.1,
31
+ screenshots: 0.3,
32
+ traces: 0.2,
33
+ signals: 0.2,
34
+ snippets: 0.3
35
+ },
36
+ thresholds: {
37
+ high: 0.8,
38
+ medium: 0.6,
39
+ low: 0.3
40
+ },
41
+ weights: {
42
+ promiseStrength: 0.25,
43
+ observationStrength: 0.30,
44
+ correlationQuality: 0.20,
45
+ guardrails: 0.15,
46
+ evidenceCompleteness: 0.10
47
+ },
48
+ truthLocks: {
49
+ // HARD LOCK: CONFIRMED requires evidencePackage.isComplete === true
50
+ evidenceCompleteRequired: true,
51
+
52
+ // HARD LOCK: NON_DETERMINISTIC verdict caps confidence ≤ 0.6
53
+ nonDeterministicMaxConfidence: 0.6,
54
+
55
+ // HARD LOCK: Guardrails confidence deltas are max-negative only (enforced in guardrails policy)
56
+ guardrailsMaxNegative: true,
57
+
58
+ // HARD LOCK: Cannot upgrade SUSPECTED → CONFIRMED via policy
59
+ cannotUpgradeToConfirmed: true,
60
+
61
+ // HARD LOCK: Contradiction penalty
62
+ contradictionPenalty: 0.3
63
+ }
64
+ };
65
+
@@ -0,0 +1,79 @@
1
+ /**
2
+ * PHASE 21.4 — Confidence Policy Loader
3
+ *
4
+ * Loads confidence policies from files or uses defaults.
5
+ * Validates policies and enforces truth locks.
6
+ */
7
+
8
+ import { readFileSync, existsSync } from 'fs';
9
+ import { resolve } from 'path';
10
+ import { validateConfidencePolicy } from './confidence.schema.js';
11
+ import { DEFAULT_CONFIDENCE_POLICY } from './confidence.defaults.js';
12
+
13
+ /**
14
+ * Load confidence policy
15
+ *
16
+ * @param {string|null} policyPath - Path to custom policy file (optional)
17
+ * @param {string} projectDir - Project directory
18
+ * @returns {Object} Confidence policy
19
+ * @throws {Error} If policy is invalid
20
+ */
21
+ export function loadConfidencePolicy(policyPath = null, projectDir = null) {
22
+ // If no custom policy path, use defaults
23
+ if (!policyPath) {
24
+ return DEFAULT_CONFIDENCE_POLICY;
25
+ }
26
+
27
+ // Resolve policy path
28
+ const resolvedPath = projectDir ? resolve(projectDir, policyPath) : resolve(policyPath);
29
+
30
+ // Check if file exists
31
+ if (!existsSync(resolvedPath)) {
32
+ throw new Error(`Confidence policy file not found: ${resolvedPath}`);
33
+ }
34
+
35
+ // Read and parse policy
36
+ let policy;
37
+ try {
38
+ const policyContent = readFileSync(resolvedPath, 'utf-8');
39
+ policy = JSON.parse(policyContent);
40
+ } catch (error) {
41
+ throw new Error(`Failed to load confidence policy: ${error.message}`);
42
+ }
43
+
44
+ // Validate policy
45
+ try {
46
+ validateConfidencePolicy(policy);
47
+ } catch (error) {
48
+ throw new Error(`Invalid confidence policy: ${error.message}`);
49
+ }
50
+
51
+ // HARD LOCK: Enforce truth locks from defaults (cannot be overridden)
52
+ // Defaults override any custom values
53
+ policy.truthLocks = {
54
+ ...policy.truthLocks,
55
+ ...DEFAULT_CONFIDENCE_POLICY.truthLocks // Defaults take precedence
56
+ };
57
+
58
+ // Mark as custom
59
+ policy.source = 'custom';
60
+
61
+ return policy;
62
+ }
63
+
64
+ /**
65
+ * Get policy report metadata
66
+ *
67
+ * @param {Object} policy - Confidence policy
68
+ * @returns {Object} Policy report metadata
69
+ */
70
+ export function getPolicyReport(policy) {
71
+ return {
72
+ version: policy.version,
73
+ source: policy.source,
74
+ thresholds: policy.thresholds,
75
+ weights: policy.weights,
76
+ truthLocks: Object.keys(policy.truthLocks)
77
+ };
78
+ }
79
+
@@ -0,0 +1,94 @@
1
+ /**
2
+ * PHASE 21.4 — Confidence Policy Schema
3
+ *
4
+ * Defines the structure for confidence policies.
5
+ * Truth locks are enforced and cannot be configured away.
6
+ */
7
+
8
+ /**
9
+ * Confidence Policy Schema
10
+ *
11
+ * @typedef {Object} ConfidencePolicy
12
+ * @property {string} version - Policy version
13
+ * @property {string} source - 'default' | 'custom'
14
+ * @property {Object} baseScores - Base score configuration
15
+ * @property {Object} thresholds - Threshold configuration
16
+ * @property {Object} weights - Weight configuration for pillars
17
+ * @property {Object} truthLocks - Truth locks (cannot be overridden)
18
+ */
19
+
20
+ /**
21
+ * Validate confidence policy
22
+ *
23
+ * @param {Object} policy - Policy to validate
24
+ * @throws {Error} If policy is invalid
25
+ */
26
+ export function validateConfidencePolicy(policy) {
27
+ if (!policy) {
28
+ throw new Error('Confidence policy is required');
29
+ }
30
+
31
+ if (!policy.version || typeof policy.version !== 'string') {
32
+ throw new Error('Confidence policy must have a version string');
33
+ }
34
+
35
+ // Validate base scores
36
+ if (!policy.baseScores || typeof policy.baseScores !== 'object') {
37
+ throw new Error('Confidence policy must have baseScores object');
38
+ }
39
+
40
+ // Validate thresholds
41
+ if (!policy.thresholds || typeof policy.thresholds !== 'object') {
42
+ throw new Error('Confidence policy must have thresholds object');
43
+ }
44
+
45
+ // Validate weights
46
+ if (!policy.weights || typeof policy.weights !== 'object') {
47
+ throw new Error('Confidence policy must have weights object');
48
+ }
49
+
50
+ // Validate truth locks
51
+ if (!policy.truthLocks || typeof policy.truthLocks !== 'object') {
52
+ throw new Error('Confidence policy must have truthLocks object');
53
+ }
54
+
55
+ // HARD LOCK: Truth locks cannot be overridden
56
+ const requiredTruthLocks = [
57
+ 'evidenceCompleteRequired',
58
+ 'nonDeterministicMaxConfidence',
59
+ 'guardrailsMaxNegative'
60
+ ];
61
+
62
+ for (const lock of requiredTruthLocks) {
63
+ if (!(lock in policy.truthLocks)) {
64
+ throw new Error(`Confidence policy must have truth lock: ${lock}`);
65
+ }
66
+ }
67
+
68
+ // Validate threshold values
69
+ const thresholds = policy.thresholds;
70
+ if (typeof thresholds.high !== 'number' || thresholds.high < 0 || thresholds.high > 1) {
71
+ throw new Error('Confidence policy threshold.high must be a number between 0 and 1');
72
+ }
73
+
74
+ if (typeof thresholds.medium !== 'number' || thresholds.medium < 0 || thresholds.medium > 1) {
75
+ throw new Error('Confidence policy threshold.medium must be a number between 0 and 1');
76
+ }
77
+
78
+ if (typeof thresholds.low !== 'number' || thresholds.low < 0 || thresholds.low > 1) {
79
+ throw new Error('Confidence policy threshold.low must be a number between 0 and 1');
80
+ }
81
+
82
+ // Validate weights sum to reasonable range
83
+ const weights = policy.weights;
84
+ const weightSum = (weights.promiseStrength || 0) +
85
+ (weights.observationStrength || 0) +
86
+ (weights.correlationQuality || 0) +
87
+ (weights.guardrails || 0) +
88
+ (weights.evidenceCompleteness || 0);
89
+
90
+ if (Math.abs(weightSum - 1.0) > 0.01) {
91
+ throw new Error(`Confidence policy weights must sum to approximately 1.0 (got ${weightSum})`);
92
+ }
93
+ }
94
+