@veraxhq/verax 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +10 -6
  2. package/bin/verax.js +11 -11
  3. package/package.json +29 -8
  4. package/src/cli/commands/baseline.js +103 -0
  5. package/src/cli/commands/default.js +51 -6
  6. package/src/cli/commands/doctor.js +29 -0
  7. package/src/cli/commands/ga.js +246 -0
  8. package/src/cli/commands/gates.js +95 -0
  9. package/src/cli/commands/inspect.js +4 -2
  10. package/src/cli/commands/release-check.js +215 -0
  11. package/src/cli/commands/run.js +45 -6
  12. package/src/cli/commands/security-check.js +212 -0
  13. package/src/cli/commands/truth.js +113 -0
  14. package/src/cli/entry.js +30 -20
  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 +544 -0
  20. package/src/cli/util/ast-network-detector.js +603 -0
  21. package/src/cli/util/ast-promise-extractor.js +581 -0
  22. package/src/cli/util/ast-usestate-detector.js +602 -0
  23. package/src/cli/util/atomic-write.js +12 -1
  24. package/src/cli/util/bootstrap-guard.js +86 -0
  25. package/src/cli/util/console-reporter.js +72 -0
  26. package/src/cli/util/detection-engine.js +105 -41
  27. package/src/cli/util/determinism-runner.js +124 -0
  28. package/src/cli/util/determinism-writer.js +129 -0
  29. package/src/cli/util/digest-engine.js +359 -0
  30. package/src/cli/util/dom-diff.js +226 -0
  31. package/src/cli/util/evidence-engine.js +287 -0
  32. package/src/cli/util/expectation-extractor.js +151 -5
  33. package/src/cli/util/findings-writer.js +3 -0
  34. package/src/cli/util/framework-detector.js +572 -0
  35. package/src/cli/util/idgen.js +1 -1
  36. package/src/cli/util/interaction-planner.js +529 -0
  37. package/src/cli/util/learn-writer.js +2 -0
  38. package/src/cli/util/ledger-writer.js +110 -0
  39. package/src/cli/util/monorepo-resolver.js +162 -0
  40. package/src/cli/util/observation-engine.js +127 -278
  41. package/src/cli/util/observe-writer.js +2 -0
  42. package/src/cli/util/project-discovery.js +284 -0
  43. package/src/cli/util/project-writer.js +2 -0
  44. package/src/cli/util/run-id.js +23 -27
  45. package/src/cli/util/run-resolver.js +64 -0
  46. package/src/cli/util/run-result.js +778 -0
  47. package/src/cli/util/selector-resolver.js +235 -0
  48. package/src/cli/util/source-requirement.js +55 -0
  49. package/src/cli/util/summary-writer.js +2 -0
  50. package/src/cli/util/svelte-navigation-detector.js +163 -0
  51. package/src/cli/util/svelte-network-detector.js +80 -0
  52. package/src/cli/util/svelte-sfc-extractor.js +146 -0
  53. package/src/cli/util/svelte-state-detector.js +242 -0
  54. package/src/cli/util/trust-activation-integration.js +496 -0
  55. package/src/cli/util/trust-activation-wrapper.js +85 -0
  56. package/src/cli/util/trust-integration-hooks.js +164 -0
  57. package/src/cli/util/types.js +153 -0
  58. package/src/cli/util/url-validation.js +40 -0
  59. package/src/cli/util/vue-navigation-detector.js +178 -0
  60. package/src/cli/util/vue-sfc-extractor.js +161 -0
  61. package/src/cli/util/vue-state-detector.js +215 -0
  62. package/src/types/fs-augment.d.ts +23 -0
  63. package/src/types/global.d.ts +137 -0
  64. package/src/types/internal-types.d.ts +35 -0
  65. package/src/verax/cli/init.js +4 -18
  66. package/src/verax/core/action-classifier.js +4 -3
  67. package/src/verax/core/artifacts/registry.js +139 -0
  68. package/src/verax/core/artifacts/verifier.js +990 -0
  69. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  70. package/src/verax/core/baseline/baseline.snapshot.js +233 -0
  71. package/src/verax/core/capabilities/gates.js +505 -0
  72. package/src/verax/core/capabilities/registry.js +475 -0
  73. package/src/verax/core/confidence/confidence-compute.js +144 -0
  74. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  75. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  76. package/src/verax/core/confidence/confidence-weights.js +44 -0
  77. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  78. package/src/verax/core/confidence/confidence.loader.js +80 -0
  79. package/src/verax/core/confidence/confidence.schema.js +94 -0
  80. package/src/verax/core/confidence-engine-refactor.js +489 -0
  81. package/src/verax/core/confidence-engine.js +625 -0
  82. package/src/verax/core/contracts/index.js +29 -0
  83. package/src/verax/core/contracts/types.js +186 -0
  84. package/src/verax/core/contracts/validators.js +456 -0
  85. package/src/verax/core/decisions/decision.trace.js +278 -0
  86. package/src/verax/core/determinism/contract-writer.js +89 -0
  87. package/src/verax/core/determinism/contract.js +139 -0
  88. package/src/verax/core/determinism/diff.js +405 -0
  89. package/src/verax/core/determinism/engine.js +222 -0
  90. package/src/verax/core/determinism/finding-identity.js +149 -0
  91. package/src/verax/core/determinism/normalize.js +466 -0
  92. package/src/verax/core/determinism/report-writer.js +93 -0
  93. package/src/verax/core/determinism/run-fingerprint.js +123 -0
  94. package/src/verax/core/dynamic-route-intelligence.js +529 -0
  95. package/src/verax/core/evidence/evidence-capture-service.js +308 -0
  96. package/src/verax/core/evidence/evidence-intent-ledger.js +166 -0
  97. package/src/verax/core/evidence-builder.js +487 -0
  98. package/src/verax/core/execution-mode-context.js +77 -0
  99. package/src/verax/core/execution-mode-detector.js +192 -0
  100. package/src/verax/core/failures/exit-codes.js +88 -0
  101. package/src/verax/core/failures/failure-summary.js +76 -0
  102. package/src/verax/core/failures/failure.factory.js +225 -0
  103. package/src/verax/core/failures/failure.ledger.js +133 -0
  104. package/src/verax/core/failures/failure.types.js +196 -0
  105. package/src/verax/core/failures/index.js +10 -0
  106. package/src/verax/core/ga/ga-report-writer.js +43 -0
  107. package/src/verax/core/ga/ga.artifact.js +49 -0
  108. package/src/verax/core/ga/ga.contract.js +435 -0
  109. package/src/verax/core/ga/ga.enforcer.js +87 -0
  110. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  111. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  112. package/src/verax/core/guardrails/policy.loader.js +84 -0
  113. package/src/verax/core/guardrails/policy.schema.js +110 -0
  114. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  115. package/src/verax/core/guardrails-engine.js +505 -0
  116. package/src/verax/core/incremental-store.js +1 -0
  117. package/src/verax/core/integrity/budget.js +138 -0
  118. package/src/verax/core/integrity/determinism.js +342 -0
  119. package/src/verax/core/integrity/integrity.js +208 -0
  120. package/src/verax/core/integrity/poisoning.js +108 -0
  121. package/src/verax/core/integrity/transaction.js +140 -0
  122. package/src/verax/core/observe/run-timeline.js +318 -0
  123. package/src/verax/core/perf/perf.contract.js +186 -0
  124. package/src/verax/core/perf/perf.display.js +65 -0
  125. package/src/verax/core/perf/perf.enforcer.js +91 -0
  126. package/src/verax/core/perf/perf.monitor.js +209 -0
  127. package/src/verax/core/perf/perf.report.js +200 -0
  128. package/src/verax/core/pipeline-tracker.js +243 -0
  129. package/src/verax/core/product-definition.js +127 -0
  130. package/src/verax/core/release/provenance.builder.js +130 -0
  131. package/src/verax/core/release/release-report-writer.js +40 -0
  132. package/src/verax/core/release/release.enforcer.js +164 -0
  133. package/src/verax/core/release/reproducibility.check.js +222 -0
  134. package/src/verax/core/release/sbom.builder.js +292 -0
  135. package/src/verax/core/replay-validator.js +2 -0
  136. package/src/verax/core/replay.js +4 -0
  137. package/src/verax/core/report/cross-index.js +195 -0
  138. package/src/verax/core/report/human-summary.js +362 -0
  139. package/src/verax/core/route-intelligence.js +420 -0
  140. package/src/verax/core/run-id.js +6 -3
  141. package/src/verax/core/run-manifest.js +4 -3
  142. package/src/verax/core/security/secrets.scan.js +329 -0
  143. package/src/verax/core/security/security-report.js +50 -0
  144. package/src/verax/core/security/security.enforcer.js +128 -0
  145. package/src/verax/core/security/supplychain.defaults.json +38 -0
  146. package/src/verax/core/security/supplychain.policy.js +334 -0
  147. package/src/verax/core/security/vuln.scan.js +265 -0
  148. package/src/verax/core/truth/truth.certificate.js +252 -0
  149. package/src/verax/core/ui-feedback-intelligence.js +481 -0
  150. package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
  151. package/src/verax/detect/confidence-engine.js +62 -34
  152. package/src/verax/detect/confidence-helper.js +34 -0
  153. package/src/verax/detect/dynamic-route-findings.js +338 -0
  154. package/src/verax/detect/expectation-chain-detector.js +417 -0
  155. package/src/verax/detect/expectation-model.js +2 -2
  156. package/src/verax/detect/failure-cause-inference.js +293 -0
  157. package/src/verax/detect/findings-writer.js +131 -35
  158. package/src/verax/detect/flow-detector.js +2 -2
  159. package/src/verax/detect/form-silent-failure.js +98 -0
  160. package/src/verax/detect/index.js +46 -5
  161. package/src/verax/detect/invariants-enforcer.js +147 -0
  162. package/src/verax/detect/journey-stall-detector.js +558 -0
  163. package/src/verax/detect/navigation-silent-failure.js +82 -0
  164. package/src/verax/detect/problem-aggregator.js +361 -0
  165. package/src/verax/detect/route-findings.js +219 -0
  166. package/src/verax/detect/summary-writer.js +477 -0
  167. package/src/verax/detect/test-failure-cause-inference.js +314 -0
  168. package/src/verax/detect/ui-feedback-findings.js +207 -0
  169. package/src/verax/detect/view-switch-correlator.js +242 -0
  170. package/src/verax/flow/flow-engine.js +2 -1
  171. package/src/verax/flow/flow-spec.js +0 -6
  172. package/src/verax/index.js +4 -0
  173. package/src/verax/intel/ts-program.js +1 -0
  174. package/src/verax/intel/vue-navigation-extractor.js +3 -0
  175. package/src/verax/learn/action-contract-extractor.js +3 -0
  176. package/src/verax/learn/ast-contract-extractor.js +1 -1
  177. package/src/verax/learn/flow-extractor.js +1 -0
  178. package/src/verax/learn/project-detector.js +5 -0
  179. package/src/verax/learn/react-router-extractor.js +2 -0
  180. package/src/verax/learn/source-instrumenter.js +1 -0
  181. package/src/verax/learn/state-extractor.js +2 -1
  182. package/src/verax/learn/static-extractor.js +1 -0
  183. package/src/verax/observe/coverage-gaps.js +132 -0
  184. package/src/verax/observe/expectation-handler.js +126 -0
  185. package/src/verax/observe/incremental-skip.js +46 -0
  186. package/src/verax/observe/index.js +51 -155
  187. package/src/verax/observe/interaction-executor.js +192 -0
  188. package/src/verax/observe/interaction-runner.js +782 -513
  189. package/src/verax/observe/network-firewall.js +86 -0
  190. package/src/verax/observe/observation-builder.js +169 -0
  191. package/src/verax/observe/observe-context.js +205 -0
  192. package/src/verax/observe/observe-helpers.js +192 -0
  193. package/src/verax/observe/observe-runner.js +230 -0
  194. package/src/verax/observe/observers/budget-observer.js +185 -0
  195. package/src/verax/observe/observers/console-observer.js +102 -0
  196. package/src/verax/observe/observers/coverage-observer.js +107 -0
  197. package/src/verax/observe/observers/interaction-observer.js +471 -0
  198. package/src/verax/observe/observers/navigation-observer.js +132 -0
  199. package/src/verax/observe/observers/network-observer.js +87 -0
  200. package/src/verax/observe/observers/safety-observer.js +82 -0
  201. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  202. package/src/verax/observe/page-traversal.js +138 -0
  203. package/src/verax/observe/snapshot-ops.js +94 -0
  204. package/src/verax/observe/ui-feedback-detector.js +742 -0
  205. package/src/verax/scan-summary-writer.js +2 -0
  206. package/src/verax/shared/artifact-manager.js +25 -5
  207. package/src/verax/shared/caching.js +1 -0
  208. package/src/verax/shared/css-spinner-rules.js +204 -0
  209. package/src/verax/shared/expectation-tracker.js +1 -0
  210. package/src/verax/shared/view-switch-rules.js +208 -0
  211. package/src/verax/shared/zip-artifacts.js +6 -0
  212. package/src/verax/shared/config-loader.js +0 -169
  213. /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
@@ -0,0 +1,435 @@
1
+ /**
2
+ * PHASE 21.6 — GA Readiness Contract
3
+ *
4
+ * Hard gate that determines if VERAX is Enterprise-GA ready.
5
+ * No human judgment, only code decides.
6
+ */
7
+
8
+ import { evaluateAllCapabilityGates, buildGateContext } from '../capabilities/gates.js';
9
+ import { CAPABILITY_MATURITY as _CAPABILITY_MATURITY } from '../capabilities/gates.js';
10
+ import { verifyRun } from '../artifacts/verifier.js';
11
+ import { checkSecurityStatus } from '../security/security.enforcer.js';
12
+ import { readFileSync, existsSync } from 'fs';
13
+ import { resolve } from 'path';
14
+ import { isBaselineFrozen as _isBaselineFrozen, enforceBaseline as _enforceBaseline } from '../baseline/baseline.enforcer.js';
15
+
16
+ /**
17
+ * GA Blocker Codes
18
+ */
19
+ export const GA_BLOCKER_CODE = {
20
+ NO_RUNS_FOUND: 'GA_NO_RUNS_FOUND',
21
+ CAPABILITY_GATES_FAILED: 'GA_CAPABILITY_GATES_FAILED',
22
+ FRAMEWORK_WAVES_UNSTABLE: 'GA_FRAMEWORK_WAVES_UNSTABLE',
23
+ EVIDENCE_LAW_VIOLATION: 'GA_EVIDENCE_LAW_VIOLATION',
24
+ DETERMINISM_NOT_ACCEPTED: 'GA_DETERMINISM_NOT_ACCEPTED',
25
+ BLOCKING_FAILURES: 'GA_BLOCKING_FAILURES',
26
+ DEGRADED_FAILURES: 'GA_DEGRADED_FAILURES',
27
+ INTERNAL_FAILURES: 'GA_INTERNAL_FAILURES',
28
+ CONTRACT_FAILURES: 'GA_CONTRACT_FAILURES',
29
+ POLICY_INVALID: 'GA_POLICY_INVALID',
30
+ ARTIFACT_VERIFIER_FAILED: 'GA_ARTIFACT_VERIFIER_FAILED',
31
+ SECURITY_NOT_CHECKED: 'GA_SECURITY_NOT_CHECKED',
32
+ SECURITY_BLOCKED: 'GA_SECURITY_BLOCKED',
33
+ PERFORMANCE_BLOCKED: 'GA_PERFORMANCE_BLOCKED',
34
+ BASELINE_DRIFT: 'GA_BASELINE_DRIFT'
35
+ };
36
+
37
+ /**
38
+ * GA Warning Codes
39
+ */
40
+ export const GA_WARNING_CODE = {
41
+ WARNINGS_IN_LEDGER: 'GA_WARNINGS_IN_LEDGER',
42
+ NON_DETERMINISTIC_ACCEPTED: 'GA_NON_DETERMINISTIC_ACCEPTED',
43
+ SECURITY_NOT_CHECKED: 'GA_SECURITY_NOT_CHECKED'
44
+ };
45
+
46
+ /**
47
+ * @typedef {Object} GA_BLOCKER
48
+ * @property {string} code - Blocker code
49
+ * @property {string} message - Human-readable message
50
+ * @property {Object} context - Additional context
51
+ */
52
+
53
+ /**
54
+ * @typedef {Object} GA_WARNING
55
+ * @property {string} code - Warning code
56
+ * @property {string} message - Human-readable message
57
+ * @property {Object} context - Additional context
58
+ */
59
+
60
+ /**
61
+ * @typedef {Object} GAReadinessResult
62
+ * @property {boolean} pass - Whether GA-ready
63
+ * @property {GA_BLOCKER[]} blockers - List of blockers
64
+ * @property {GA_WARNING[]} warnings - List of warnings
65
+ * @property {Object} summary - Summary of evaluation
66
+ * @property {Object} inputs - Inputs used for evaluation
67
+ */
68
+
69
+ /**
70
+ * Check if determinism acceptance policy exists and is valid
71
+ *
72
+ * @param {string} projectDir - Project directory
73
+ * @returns {Object|null} Acceptance policy or null
74
+ */
75
+ function loadDeterminismAcceptancePolicy(projectDir) {
76
+ const policyPath = resolve(projectDir, 'determinism.acceptance.json');
77
+ if (!existsSync(policyPath)) {
78
+ return null;
79
+ }
80
+
81
+ try {
82
+ const content = readFileSync(policyPath, 'utf-8');
83
+ // @ts-expect-error - readFileSync with encoding returns string
84
+ const policy = JSON.parse(content);
85
+
86
+ // Validate policy structure
87
+ if (!policy.allowedAdaptiveEvents || !Array.isArray(policy.allowedAdaptiveEvents)) {
88
+ return null;
89
+ }
90
+
91
+ if (!policy.justification || typeof policy.justification !== 'string') {
92
+ return null;
93
+ }
94
+
95
+ return policy;
96
+ } catch (error) {
97
+ return null;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Check if determinism verdict is accepted
103
+ *
104
+ * @param {string} determinismVerdict - Determinism verdict (DETERMINISTIC | NON_DETERMINISTIC)
105
+ * @param {Object|null} acceptancePolicy - Determinism acceptance policy
106
+ * @returns {boolean} Whether verdict is accepted
107
+ */
108
+ function isDeterminismAccepted(determinismVerdict, acceptancePolicy) {
109
+ if (determinismVerdict === 'DETERMINISTIC') {
110
+ return true;
111
+ }
112
+
113
+ if (determinismVerdict === 'NON_DETERMINISTIC' && acceptancePolicy) {
114
+ return true;
115
+ }
116
+
117
+ return false;
118
+ }
119
+
120
+ /**
121
+ * Check if all framework waves are STABLE
122
+ *
123
+ * @param {Object} gateResult - Capability gates result
124
+ * @returns {Object} { allStable: boolean, unstable: string[] }
125
+ */
126
+ function checkFrameworkWavesStable(gateResult) {
127
+ const unstable = [];
128
+
129
+ // Check all capabilities marked as STABLE actually pass gates
130
+ for (const [capabilityId, result] of Object.entries(gateResult.perCapability || {})) {
131
+ // This is a simplified check - in reality, we'd need to check the registry
132
+ // to see which capabilities are marked as STABLE
133
+ // For now, we check if any capability fails gates
134
+ if (!result.pass) {
135
+ unstable.push(capabilityId);
136
+ }
137
+ }
138
+
139
+ return {
140
+ allStable: unstable.length === 0,
141
+ unstable
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Evaluate GA Readiness
147
+ *
148
+ * @param {Object} context - Evaluation context
149
+ * @param {string} context.projectDir - Project directory
150
+ * @param {string} [context.runId] - Run ID (for artifact verification)
151
+ * @param {string} [context.determinismVerdict] - Determinism verdict
152
+ * @param {boolean} [context.evidenceLawViolated] - Whether Evidence Law was violated
153
+ * @param {Object} [context.failureLedger] - Failure ledger summary
154
+ * @returns {Promise<GAReadinessResult>} GA readiness result
155
+ */
156
+ export async function evaluateGAReadiness(context) {
157
+ const {
158
+ projectDir,
159
+ runId = null,
160
+ determinismVerdict = null,
161
+ evidenceLawViolated = false,
162
+ failureLedger = null
163
+ } = context;
164
+
165
+ const blockers = [];
166
+ const warnings = [];
167
+ const inputs = {
168
+ gates: null,
169
+ determinism: determinismVerdict || 'UNKNOWN',
170
+ evidenceLaw: evidenceLawViolated ? 'VIOLATED' : 'ENFORCED',
171
+ failureLedger: failureLedger || { total: 0, bySeverity: {} },
172
+ artifactVerifier: null
173
+ };
174
+
175
+ // 1. Phase 19: Capability Gates - 100% PASS required
176
+ let gateResult = null;
177
+ try {
178
+ const gateContext = await buildGateContext({ projectRoot: projectDir });
179
+ gateResult = evaluateAllCapabilityGates(gateContext);
180
+ inputs.gates = gateResult.pass ? 'PASS' : 'FAIL';
181
+
182
+ if (!gateResult.pass) {
183
+ blockers.push({
184
+ code: GA_BLOCKER_CODE.CAPABILITY_GATES_FAILED,
185
+ message: `Capability gates failed: ${gateResult.summary.fail} of ${gateResult.summary.total} capabilities failed`,
186
+ context: {
187
+ total: gateResult.summary.total,
188
+ pass: gateResult.summary.pass,
189
+ fail: gateResult.summary.fail,
190
+ failures: gateResult.summary.allFailures
191
+ }
192
+ });
193
+ }
194
+ } catch (error) {
195
+ blockers.push({
196
+ code: GA_BLOCKER_CODE.CAPABILITY_GATES_FAILED,
197
+ message: `Failed to evaluate capability gates: ${error.message}`,
198
+ context: { error: error.message }
199
+ });
200
+ }
201
+
202
+ // 2. Phase 20: Framework Waves - ALL STABLE required
203
+ if (gateResult) {
204
+ const wavesCheck = checkFrameworkWavesStable(gateResult);
205
+ inputs.frameworkWaves = wavesCheck.allStable ? 'ALL_STABLE' : 'UNSTABLE';
206
+
207
+ if (!wavesCheck.allStable) {
208
+ blockers.push({
209
+ code: GA_BLOCKER_CODE.FRAMEWORK_WAVES_UNSTABLE,
210
+ message: `Framework waves not stable: ${wavesCheck.unstable.length} capabilities unstable`,
211
+ context: {
212
+ unstable: wavesCheck.unstable
213
+ }
214
+ });
215
+ }
216
+ }
217
+
218
+ // 3. Evidence Law - No violations allowed
219
+ if (evidenceLawViolated) {
220
+ blockers.push({
221
+ code: GA_BLOCKER_CODE.EVIDENCE_LAW_VIOLATION,
222
+ message: 'Evidence Law violated: CONFIRMED findings with incomplete evidence',
223
+ context: {}
224
+ });
225
+ }
226
+
227
+ // 4. Determinism - Either DETERMINISTIC or explicitly accepted
228
+ const acceptancePolicy = loadDeterminismAcceptancePolicy(projectDir);
229
+ if (determinismVerdict) {
230
+ if (!isDeterminismAccepted(determinismVerdict, acceptancePolicy)) {
231
+ blockers.push({
232
+ code: GA_BLOCKER_CODE.DETERMINISM_NOT_ACCEPTED,
233
+ message: `NON_DETERMINISTIC execution without acceptance policy`,
234
+ context: {
235
+ verdict: determinismVerdict,
236
+ hasPolicy: !!acceptancePolicy
237
+ }
238
+ });
239
+ } else if (determinismVerdict === 'NON_DETERMINISTIC' && acceptancePolicy) {
240
+ warnings.push({
241
+ code: GA_WARNING_CODE.NON_DETERMINISTIC_ACCEPTED,
242
+ message: `NON_DETERMINISTIC execution accepted via policy: ${acceptancePolicy.justification}`,
243
+ context: {
244
+ allowedEvents: acceptancePolicy.allowedAdaptiveEvents
245
+ }
246
+ });
247
+ }
248
+ }
249
+
250
+ // 5. Failure Ledger - BLOCKING = 0, DEGRADED = 0 required
251
+ if (failureLedger) {
252
+ const blockingCount = failureLedger.bySeverity?.BLOCKING || 0;
253
+ const degradedCount = failureLedger.bySeverity?.DEGRADED || 0;
254
+ const warningCount = failureLedger.bySeverity?.WARNING || 0;
255
+
256
+ if (blockingCount > 0) {
257
+ blockers.push({
258
+ code: GA_BLOCKER_CODE.BLOCKING_FAILURES,
259
+ message: `${blockingCount} BLOCKING failure(s) in failure ledger`,
260
+ context: {
261
+ count: blockingCount
262
+ }
263
+ });
264
+ }
265
+
266
+ if (degradedCount > 0) {
267
+ blockers.push({
268
+ code: GA_BLOCKER_CODE.DEGRADED_FAILURES,
269
+ message: `${degradedCount} DEGRADED failure(s) in failure ledger`,
270
+ context: {
271
+ count: degradedCount
272
+ }
273
+ });
274
+ }
275
+
276
+ // Check for INTERNAL or CONTRACT failures
277
+ const internalCount = failureLedger.byCategory?.INTERNAL || 0;
278
+ const contractCount = failureLedger.byCategory?.CONTRACT || 0;
279
+
280
+ if (internalCount > 0) {
281
+ blockers.push({
282
+ code: GA_BLOCKER_CODE.INTERNAL_FAILURES,
283
+ message: `${internalCount} INTERNAL failure(s) in failure ledger`,
284
+ context: {
285
+ count: internalCount
286
+ }
287
+ });
288
+ }
289
+
290
+ if (contractCount > 0) {
291
+ blockers.push({
292
+ code: GA_BLOCKER_CODE.CONTRACT_FAILURES,
293
+ message: `${contractCount} CONTRACT failure(s) in failure ledger`,
294
+ context: {
295
+ count: contractCount
296
+ }
297
+ });
298
+ }
299
+
300
+ if (warningCount > 0) {
301
+ warnings.push({
302
+ code: GA_WARNING_CODE.WARNINGS_IN_LEDGER,
303
+ message: `${warningCount} WARNING failure(s) in failure ledger`,
304
+ context: {
305
+ count: warningCount
306
+ }
307
+ });
308
+ }
309
+ }
310
+
311
+ // 6. Policies - All must be valid and loaded
312
+ try {
313
+ const { loadGuardrailsPolicy } = await import('../guardrails/policy.loader.js');
314
+ const { loadConfidencePolicy } = await import('../confidence/confidence.loader.js');
315
+
316
+ try {
317
+ loadGuardrailsPolicy();
318
+ } catch (error) {
319
+ blockers.push({
320
+ code: GA_BLOCKER_CODE.POLICY_INVALID,
321
+ message: `Guardrails policy invalid: ${error.message}`,
322
+ context: { error: error.message }
323
+ });
324
+ }
325
+
326
+ try {
327
+ loadConfidencePolicy();
328
+ } catch (error) {
329
+ blockers.push({
330
+ code: GA_BLOCKER_CODE.POLICY_INVALID,
331
+ message: `Confidence policy invalid: ${error.message}`,
332
+ context: { error: error.message }
333
+ });
334
+ }
335
+ } catch (error) {
336
+ blockers.push({
337
+ code: GA_BLOCKER_CODE.POLICY_INVALID,
338
+ message: `Failed to load policies: ${error.message}`,
339
+ context: { error: error.message }
340
+ });
341
+ }
342
+
343
+ // 7. Artifact Verifier - Must pass with no blocking errors
344
+ if (runId) {
345
+ try {
346
+ const runDir = resolve(projectDir, '.verax', 'runs', runId);
347
+ const verification = verifyRun(runDir);
348
+ inputs.artifactVerifier = verification.ok ? 'PASS' : 'FAIL';
349
+
350
+ if (!verification.ok) {
351
+ blockers.push({
352
+ code: GA_BLOCKER_CODE.ARTIFACT_VERIFIER_FAILED,
353
+ message: `Artifact verifier failed: ${verification.errors.length} error(s)`,
354
+ context: {
355
+ errors: verification.errors,
356
+ warnings: verification.warnings
357
+ }
358
+ });
359
+ }
360
+ } catch (error) {
361
+ blockers.push({
362
+ code: GA_BLOCKER_CODE.ARTIFACT_VERIFIER_FAILED,
363
+ message: `Failed to verify artifacts: ${error.message}`,
364
+ context: { error: error.message }
365
+ });
366
+ }
367
+ }
368
+
369
+ // 8. Security Baseline (PHASE 21.8) - SECURITY-OK required
370
+ try {
371
+ const securityCheck = checkSecurityStatus(projectDir);
372
+ inputs.security = securityCheck.ok ? 'OK' : 'BLOCKED';
373
+
374
+ if (!securityCheck.exists) {
375
+ blockers.push({
376
+ code: GA_BLOCKER_CODE.SECURITY_NOT_CHECKED,
377
+ message: 'Security reports not found. Run "verax security:check" first.',
378
+ context: {}
379
+ });
380
+ } else if (!securityCheck.ok) {
381
+ blockers.push({
382
+ code: GA_BLOCKER_CODE.SECURITY_BLOCKED,
383
+ message: `SECURITY-BLOCKED: ${securityCheck.blockers.join('; ')}`,
384
+ context: { blockers: securityCheck.blockers }
385
+ });
386
+ }
387
+ } catch (error) {
388
+ blockers.push({
389
+ code: GA_BLOCKER_CODE.SECURITY_NOT_CHECKED,
390
+ message: `Security check failed: ${error.message}`,
391
+ context: { error: error.message }
392
+ });
393
+ }
394
+
395
+ // 9. Performance Budget (PHASE 21.9) - BLOCKING perf violations block GA
396
+ if (runId) {
397
+ try {
398
+ const { checkPerformanceStatus } = await import('../perf/perf.enforcer.js');
399
+ const perfCheck = checkPerformanceStatus(projectDir, runId);
400
+ inputs.performance = perfCheck.ok ? 'OK' : 'BLOCKED';
401
+
402
+ if (!perfCheck.exists) {
403
+ // Performance report missing is not a blocker (may be from old runs)
404
+ inputs.performance = 'MISSING';
405
+ } else if (!perfCheck.ok) {
406
+ blockers.push({
407
+ code: GA_BLOCKER_CODE.PERFORMANCE_BLOCKED,
408
+ message: `PERFORMANCE-BLOCKED: ${perfCheck.blockers.join('; ')}`,
409
+ context: { blockers: perfCheck.blockers, verdict: perfCheck.verdict }
410
+ });
411
+ }
412
+ } catch (error) {
413
+ // Performance check failure is not a blocker (may be from old runs)
414
+ inputs.performance = 'ERROR';
415
+ }
416
+ }
417
+
418
+ const pass = blockers.length === 0;
419
+
420
+ const summary = {
421
+ pass,
422
+ blockersCount: blockers.length,
423
+ warningsCount: warnings.length,
424
+ checkedAt: new Date().toISOString()
425
+ };
426
+
427
+ return {
428
+ pass,
429
+ blockers,
430
+ warnings,
431
+ summary,
432
+ inputs
433
+ };
434
+ }
435
+
@@ -0,0 +1,87 @@
1
+ /**
2
+ * PHASE 21.6 — GA Enforcer
3
+ *
4
+ * Hard enforcement that blocks shipping without GA-READY status.
5
+ * This is not advisory. This is hard enforcement.
6
+ */
7
+
8
+ import { readFileSync, existsSync } from 'fs';
9
+ import { resolve } from 'path';
10
+ import { createInternalFailure } from '../failures/failure.factory.js';
11
+ import { FAILURE_CODE } from '../failures/failure.types.js';
12
+
13
+ /**
14
+ * Check if GA status exists and is READY
15
+ *
16
+ * @param {string} projectDir - Project directory
17
+ * @param {string} runId - Run ID
18
+ * @returns {Object} { exists: boolean, ready: boolean, status: Object|null }
19
+ */
20
+ export function checkGAStatus(projectDir, runId) {
21
+ const statusPath = resolve(projectDir, '.verax', 'runs', runId, 'ga.status.json');
22
+
23
+ if (!existsSync(statusPath)) {
24
+ return {
25
+ exists: false,
26
+ ready: false,
27
+ status: null
28
+ };
29
+ }
30
+
31
+ try {
32
+ const content = readFileSync(statusPath, 'utf-8');
33
+ // @ts-expect-error - readFileSync with encoding returns string
34
+ const status = JSON.parse(content);
35
+
36
+ return {
37
+ exists: true,
38
+ ready: status.gaReady === true,
39
+ status
40
+ };
41
+ } catch (error) {
42
+ return {
43
+ exists: false,
44
+ ready: false,
45
+ status: null,
46
+ error: error.message
47
+ };
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Enforce GA readiness before release operations
53
+ *
54
+ * @param {string} projectDir - Project directory
55
+ * @param {string} runId - Run ID
56
+ * @param {string} operation - Operation name (publish, release, tag)
57
+ * @throws {Error} If GA not ready
58
+ */
59
+ export function enforceGAReadiness(projectDir, runId, operation) {
60
+ const check = checkGAStatus(projectDir, runId);
61
+
62
+ if (!check.exists) {
63
+ const failure = createInternalFailure(
64
+ FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
65
+ `Cannot ${operation}: GA status not found. Run 'verax ga' first.`,
66
+ 'ga.enforcer',
67
+ { operation, runId },
68
+ null
69
+ );
70
+ throw failure;
71
+ }
72
+
73
+ if (!check.ready) {
74
+ const blockers = check.status?.blockers || [];
75
+ const blockerMessages = blockers.map(b => b.message).join('; ');
76
+
77
+ const failure = createInternalFailure(
78
+ FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
79
+ `Cannot ${operation}: GA-BLOCKED. Blockers: ${blockerMessages}`,
80
+ 'ga.enforcer',
81
+ { operation, runId, blockers },
82
+ null
83
+ );
84
+ throw failure;
85
+ }
86
+ }
87
+
@@ -0,0 +1,109 @@
1
+ /**
2
+ * PHASE 23 — Guardrails Report Writer
3
+ *
4
+ * Writes guardrails.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 guardrails report to disk.
13
+ *
14
+ * @param {string} runDir - Absolute run directory path
15
+ * @param {Array} findings - Array of findings with guardrails data
16
+ * @param {Object} truthDecisions - Map of findingIdentity -> truthDecision
17
+ * @returns {string} Path to written report
18
+ */
19
+ export function writeGuardrailsReport(runDir, findings, truthDecisions = {}) {
20
+ const reportPath = resolve(runDir, ARTIFACT_REGISTRY.guardrailsReport.filename);
21
+
22
+ // Build per-finding entries (deterministic ordering by findingIdentity)
23
+ const perFinding = {};
24
+ const summary = {
25
+ totalFindings: findings.length,
26
+ byFinalDecision: {
27
+ CONFIRMED: 0,
28
+ SUSPECTED: 0,
29
+ INFORMATIONAL: 0,
30
+ IGNORED: 0
31
+ },
32
+ topRules: {},
33
+ contradictionCount: 0,
34
+ reconciliationCount: 0
35
+ };
36
+
37
+ for (const finding of findings) {
38
+ const findingIdentity = finding.findingId || finding.id || `finding-${findings.indexOf(finding)}`;
39
+ const guardrails = finding.guardrails || {};
40
+ const truthDecision = truthDecisions[findingIdentity] || null;
41
+
42
+ const appliedRules = guardrails.appliedRules || [];
43
+ const contradictions = guardrails.contradictions || [];
44
+ const finalDecision = truthDecision?.finalStatus || guardrails.finalDecision || finding.severity || 'SUSPECTED';
45
+
46
+ // Track top rules
47
+ for (const rule of appliedRules) {
48
+ const ruleCode = rule.code || rule.ruleId || 'unknown';
49
+ summary.topRules[ruleCode] = (summary.topRules[ruleCode] || 0) + 1;
50
+ }
51
+
52
+ // Track contradictions
53
+ if (contradictions.length > 0) {
54
+ summary.contradictionCount += contradictions.length;
55
+ }
56
+
57
+ // Track reconciliation
58
+ if (truthDecision && truthDecision.reconciliationReasons.length > 0) {
59
+ summary.reconciliationCount++;
60
+ }
61
+
62
+ // Track by final decision
63
+ if (summary.byFinalDecision[finalDecision] !== undefined) {
64
+ summary.byFinalDecision[finalDecision]++;
65
+ }
66
+
67
+ // Build per-finding entry
68
+ perFinding[findingIdentity] = {
69
+ appliedRules: appliedRules.map(r => ({
70
+ code: r.code || r.ruleId,
71
+ severity: r.severity,
72
+ category: r.category
73
+ })),
74
+ contradictions: contradictions.map(c => ({
75
+ code: c.code,
76
+ message: c.message
77
+ })),
78
+ finalDecision,
79
+ confidenceDelta: truthDecision?.confidenceDelta || guardrails.confidenceDelta || 0,
80
+ confidenceBefore: truthDecision?.confidenceBefore || finding.confidence || 0,
81
+ confidenceAfter: truthDecision?.confidenceAfter || finding.confidence || 0,
82
+ reconciliationReasons: truthDecision?.reconciliationReasons || [],
83
+ contradictionsResolved: truthDecision?.contradictionsResolved || []
84
+ };
85
+ }
86
+
87
+ // Sort top rules by count (descending)
88
+ const topRulesSorted = Object.entries(summary.topRules)
89
+ .sort((a, b) => b[1] - a[1])
90
+ .slice(0, 10)
91
+ .map(([code, count]) => ({ code, count }));
92
+
93
+ // Build report
94
+ const report = {
95
+ version: 1,
96
+ generatedAt: new Date().toISOString(),
97
+ summary: {
98
+ ...summary,
99
+ topRules: topRulesSorted
100
+ },
101
+ perFinding
102
+ };
103
+
104
+ // Write to disk
105
+ writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
106
+
107
+ return reportPath;
108
+ }
109
+