@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,192 @@
1
+ /**
2
+ * PHASE 21.10 — Artifact Cross-Index
3
+ *
4
+ * Builds cross-index linking findingId to all related artifacts.
5
+ */
6
+
7
+ import { readFileSync, existsSync, writeFileSync, readdirSync } from 'fs';
8
+ import { resolve, relative } from 'path';
9
+
10
+ /**
11
+ * Build cross-index
12
+ *
13
+ * @param {string} projectDir - Project directory
14
+ * @param {string} runId - Run ID
15
+ * @returns {Object} Cross-index
16
+ */
17
+ export function buildCrossIndex(projectDir, runId) {
18
+ const runDir = resolve(projectDir, '.verax', 'runs', runId);
19
+
20
+ if (!existsSync(runDir)) {
21
+ return null;
22
+ }
23
+
24
+ const index = {};
25
+
26
+ // Load findings
27
+ const findingsPath = resolve(runDir, 'findings.json');
28
+ if (!existsSync(findingsPath)) {
29
+ return {
30
+ runId,
31
+ findings: {},
32
+ summary: { total: 0 },
33
+ generatedAt: new Date().toISOString()
34
+ };
35
+ }
36
+
37
+ const findings = JSON.parse(readFileSync(findingsPath, 'utf-8'));
38
+ const evidenceIndex = loadArtifact(runDir, 'evidence.index.json');
39
+ const decisionTrace = loadArtifact(runDir, 'decisions.trace.json');
40
+ const timeline = loadArtifact(runDir, 'run.timeline.json');
41
+ const failureLedger = loadArtifact(runDir, 'failure.ledger.json');
42
+ const performanceReport = loadArtifact(runDir, 'performance.report.json');
43
+
44
+ if (!Array.isArray(findings.findings)) {
45
+ return {
46
+ runId,
47
+ findings: {},
48
+ summary: { total: 0 },
49
+ generatedAt: new Date().toISOString()
50
+ };
51
+ }
52
+
53
+ for (const finding of findings.findings) {
54
+ const findingId = finding.findingId || finding.id || `finding-${Object.keys(index).length}`;
55
+
56
+ const entry = {
57
+ findingId,
58
+ type: finding.type || null,
59
+ status: finding.severity || finding.status || null,
60
+
61
+ // Evidence files
62
+ evidence: {
63
+ packageId: finding.evidencePackage?.id || null,
64
+ files: finding.evidencePackage?.files || [],
65
+ isComplete: finding.evidencePackage?.isComplete || false,
66
+ beforeScreenshot: finding.evidence?.before || null,
67
+ afterScreenshot: finding.evidence?.after || null
68
+ },
69
+
70
+ // Confidence reasons
71
+ confidence: {
72
+ level: finding.confidenceLevel || null,
73
+ score: finding.confidence !== undefined ? finding.confidence : null,
74
+ reasons: finding.confidenceReasons || [],
75
+ trace: decisionTrace?.findings?.find(t => t.findingId === findingId)?.confidence || null
76
+ },
77
+
78
+ // Guardrails rules
79
+ guardrails: {
80
+ applied: finding.guardrails?.appliedRules?.map(r => ({
81
+ id: r.id || r,
82
+ category: r.category || null,
83
+ action: r.action || null
84
+ })) || [],
85
+ finalDecision: finding.guardrails?.finalDecision || null,
86
+ contradictions: finding.guardrails?.contradictions || [],
87
+ trace: decisionTrace?.findings?.find(t => t.findingId === findingId)?.guardrails || null
88
+ },
89
+
90
+ // Failures (if any related)
91
+ failures: failureLedger?.failures?.filter(f =>
92
+ f.context?.findingId === findingId ||
93
+ f.message?.includes(findingId)
94
+ ).map(f => ({
95
+ code: f.code,
96
+ message: f.message,
97
+ severity: f.severity,
98
+ timestamp: f.timestamp
99
+ })) || [],
100
+
101
+ // Performance impacts (if any)
102
+ performance: performanceReport?.violations?.some(v =>
103
+ v.message?.includes(findingId)
104
+ ) ? {
105
+ impacted: true,
106
+ violations: performanceReport.violations.filter(v =>
107
+ v.message?.includes(findingId)
108
+ )
109
+ } : null,
110
+
111
+ // Timeline entries
112
+ timeline: timeline?.events?.filter(e =>
113
+ e.data?.findingId === findingId ||
114
+ (e.event === 'guardrails_applied' && e.data?.findingId === findingId) ||
115
+ (e.event === 'evidence_enforced' && e.data?.findingId === findingId)
116
+ ).map(e => ({
117
+ timestamp: e.timestamp,
118
+ phase: e.phase,
119
+ event: e.event,
120
+ data: e.data
121
+ })) || []
122
+ };
123
+
124
+ index[findingId] = entry;
125
+ }
126
+
127
+ return {
128
+ runId,
129
+ findings: index,
130
+ summary: {
131
+ total: Object.keys(index).length,
132
+ withEvidence: Object.values(index).filter(e => e.evidence.files.length > 0).length,
133
+ withGuardrails: Object.values(index).filter(e => e.guardrails.applied.length > 0).length,
134
+ withFailures: Object.values(index).filter(e => e.failures.length > 0).length,
135
+ withTimeline: Object.values(index).filter(e => e.timeline.length > 0).length
136
+ },
137
+ generatedAt: new Date().toISOString()
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Load artifact JSON
143
+ */
144
+ function loadArtifact(runDir, filename) {
145
+ const path = resolve(runDir, filename);
146
+ if (!existsSync(path)) {
147
+ return null;
148
+ }
149
+ try {
150
+ return JSON.parse(readFileSync(path, 'utf-8'));
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Write cross-index to file
158
+ *
159
+ * @param {string} projectDir - Project directory
160
+ * @param {string} runId - Run ID
161
+ * @param {Object} index - Cross-index
162
+ * @returns {string} Path to written file
163
+ */
164
+ export function writeCrossIndex(projectDir, runId, index) {
165
+ const runDir = resolve(projectDir, '.verax', 'runs', runId);
166
+ const outputPath = resolve(runDir, 'artifacts.index.json');
167
+ writeFileSync(outputPath, JSON.stringify(index, null, 2), 'utf-8');
168
+ return outputPath;
169
+ }
170
+
171
+ /**
172
+ * Load cross-index from file
173
+ *
174
+ * @param {string} projectDir - Project directory
175
+ * @param {string} runId - Run ID
176
+ * @returns {Object|null} Cross-index or null
177
+ */
178
+ export function loadCrossIndex(projectDir, runId) {
179
+ const runDir = resolve(projectDir, '.verax', 'runs', runId);
180
+ const indexPath = resolve(runDir, 'artifacts.index.json');
181
+
182
+ if (!existsSync(indexPath)) {
183
+ return null;
184
+ }
185
+
186
+ try {
187
+ return JSON.parse(readFileSync(indexPath, 'utf-8'));
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+
@@ -0,0 +1,222 @@
1
+ /**
2
+ * PHASE 21.10 — Human Summary
3
+ *
4
+ * Generates human-readable summary for Enterprise UX.
5
+ * Clear, direct, no marketing.
6
+ */
7
+
8
+ import { readFileSync, existsSync } from 'fs';
9
+ import { resolve } from 'path';
10
+
11
+ /**
12
+ * Load artifact JSON
13
+ */
14
+ function loadArtifact(runDir, filename) {
15
+ const path = resolve(runDir, filename);
16
+ if (!existsSync(path)) {
17
+ return null;
18
+ }
19
+ try {
20
+ return JSON.parse(readFileSync(path, 'utf-8'));
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Generate human summary
28
+ *
29
+ * @param {string} projectDir - Project directory
30
+ * @param {string} runId - Run ID
31
+ * @returns {Object} Human summary
32
+ */
33
+ export async function generateHumanSummary(projectDir, runId) {
34
+ const runDir = resolve(projectDir, '.verax', 'runs', runId);
35
+
36
+ if (!existsSync(runDir)) {
37
+ return null;
38
+ }
39
+
40
+ const summary = loadArtifact(runDir, 'summary.json');
41
+ const findings = loadArtifact(runDir, 'findings.json');
42
+ const determinism = loadArtifact(runDir, 'decisions.json');
43
+ const performanceReport = loadArtifact(runDir, 'performance.report.json');
44
+
45
+ // Security reports are in release/ directory (project root)
46
+ // Use projectDir parameter directly (already resolved)
47
+ const releaseDir = resolve(projectDir, 'release');
48
+ const securitySecrets = loadArtifact(releaseDir, 'security.secrets.report.json');
49
+ const securityVuln = loadArtifact(releaseDir, 'security.vuln.report.json');
50
+
51
+ const gaStatus = loadArtifact(runDir, 'ga.status.json');
52
+
53
+ if (!summary) {
54
+ return null;
55
+ }
56
+
57
+ const findingsArray = Array.isArray(findings?.findings) ? findings.findings : [];
58
+ const confirmedFindings = findingsArray.filter(f => (f.severity || f.status) === 'CONFIRMED');
59
+ const suspectedFindings = findingsArray.filter(f => (f.severity || f.status) === 'SUSPECTED');
60
+
61
+ // What VERAX is confident about
62
+ const confident = {
63
+ findings: confirmedFindings.length,
64
+ message: confirmedFindings.length > 0
65
+ ? `${confirmedFindings.length} finding(s) with complete evidence`
66
+ : 'No findings with complete evidence',
67
+ details: confirmedFindings.map(f => ({
68
+ type: f.type,
69
+ outcome: f.outcome,
70
+ confidence: f.confidenceLevel || 'UNKNOWN'
71
+ }))
72
+ };
73
+
74
+ // What VERAX is NOT confident about
75
+ const notConfident = {
76
+ findings: suspectedFindings.length,
77
+ message: suspectedFindings.length > 0
78
+ ? `${suspectedFindings.length} finding(s) with incomplete evidence (SUSPECTED)`
79
+ : 'No findings with incomplete evidence',
80
+ details: suspectedFindings.map(f => ({
81
+ type: f.type,
82
+ outcome: f.outcome,
83
+ confidence: f.confidenceLevel || 'UNKNOWN',
84
+ missingEvidence: f.evidencePackage?.isComplete === false
85
+ }))
86
+ };
87
+
88
+ // Why some things were skipped
89
+ const skips = [];
90
+ if (summary.truth?.observe?.skips) {
91
+ for (const skip of summary.truth.observe.skips) {
92
+ skips.push({
93
+ reason: skip.reason || skip.code || 'UNKNOWN',
94
+ count: skip.count || 1,
95
+ message: skip.message || `Skipped: ${skip.reason || skip.code}`
96
+ });
97
+ }
98
+ }
99
+
100
+ // Determinism verdict
101
+ let determinismVerdict = 'UNKNOWN';
102
+ if (determinism) {
103
+ try {
104
+ const { DecisionRecorder } = await import('../../../core/determinism-model.js');
105
+ const recorder = DecisionRecorder.fromExport(determinism);
106
+ const { computeDeterminismVerdict } = await import('../../../core/determinism/contract.js');
107
+ const verdict = computeDeterminismVerdict(recorder);
108
+ determinismVerdict = verdict.verdict;
109
+ } catch {
110
+ determinismVerdict = summary.determinism?.verdict || 'UNKNOWN';
111
+ }
112
+ } else if (summary.determinism) {
113
+ determinismVerdict = summary.determinism.verdict || 'UNKNOWN';
114
+ }
115
+
116
+ // Performance verdict
117
+ const performanceVerdict = performanceReport?.verdict || 'UNKNOWN';
118
+ const performanceOk = performanceReport?.ok !== false;
119
+
120
+ // Security verdict
121
+ const securityOk = !securitySecrets?.hasSecrets &&
122
+ !securityVuln?.blocking &&
123
+ (securitySecrets !== null || securityVuln !== null); // At least one report exists
124
+
125
+ // GA verdict
126
+ const gaReady = gaStatus?.gaReady === true;
127
+ const gaVerdict = gaReady ? 'GA-READY' : (gaStatus ? 'GA-BLOCKED' : 'UNKNOWN');
128
+
129
+ return {
130
+ runId,
131
+ whatWeKnow: {
132
+ confident: confident,
133
+ notConfident: notConfident,
134
+ skips: skips.length > 0 ? {
135
+ total: skips.reduce((sum, s) => sum + s.count, 0),
136
+ reasons: skips
137
+ } : null
138
+ },
139
+ verdicts: {
140
+ determinism: {
141
+ verdict: determinismVerdict,
142
+ message: determinismVerdict === 'DETERMINISTIC'
143
+ ? 'Run was reproducible (same inputs = same outputs)'
144
+ : determinismVerdict === 'NON_DETERMINISTIC'
145
+ ? 'Run was not reproducible (adaptive events detected)'
146
+ : 'Determinism not evaluated'
147
+ },
148
+ performance: {
149
+ verdict: performanceVerdict,
150
+ ok: performanceOk,
151
+ message: performanceOk
152
+ ? 'Performance within budget'
153
+ : performanceReport?.violations?.length > 0
154
+ ? `${performanceReport.violations.length} BLOCKING performance violation(s)`
155
+ : 'Performance not evaluated'
156
+ },
157
+ security: {
158
+ ok: securityOk,
159
+ message: securityOk
160
+ ? 'Security baseline passed'
161
+ : securitySecrets?.hasSecrets
162
+ ? 'Secrets detected'
163
+ : securityVuln?.blocking
164
+ ? 'Critical vulnerabilities detected'
165
+ : 'Security not evaluated'
166
+ },
167
+ ga: {
168
+ verdict: gaVerdict,
169
+ ready: gaReady,
170
+ message: gaReady
171
+ ? 'GA-READY: All gates passed'
172
+ : gaStatus
173
+ ? `GA-BLOCKED: ${gaStatus.blockers?.length || 0} blocker(s)`
174
+ : 'GA not evaluated'
175
+ }
176
+ },
177
+ generatedAt: new Date().toISOString()
178
+ };
179
+ }
180
+
181
+ /**
182
+ * Format human summary for CLI display
183
+ *
184
+ * @param {Object} summary - Human summary
185
+ * @returns {string} Formatted string
186
+ */
187
+ export function formatHumanSummary(summary) {
188
+ if (!summary) {
189
+ return 'Summary: Not available';
190
+ }
191
+
192
+ const lines = [];
193
+ lines.push('\n' + '='.repeat(80));
194
+ lines.push('HUMAN SUMMARY');
195
+ lines.push('='.repeat(80));
196
+
197
+ // What we know
198
+ lines.push('\nWhat VERAX is confident about:');
199
+ lines.push(` ${summary.whatWeKnow.confident.message}`);
200
+
201
+ lines.push('\nWhat VERAX is NOT confident about:');
202
+ lines.push(` ${summary.whatWeKnow.notConfident.message}`);
203
+
204
+ if (summary.whatWeKnow.skips) {
205
+ lines.push('\nWhy some things were skipped:');
206
+ for (const skip of summary.whatWeKnow.skips.reasons) {
207
+ lines.push(` - ${skip.message} (${skip.count}x)`);
208
+ }
209
+ }
210
+
211
+ // Verdicts
212
+ lines.push('\nVerdicts:');
213
+ lines.push(` Determinism: ${summary.verdicts.determinism.verdict} - ${summary.verdicts.determinism.message}`);
214
+ lines.push(` Performance: ${summary.verdicts.performance.verdict} - ${summary.verdicts.performance.message}`);
215
+ lines.push(` Security: ${summary.verdicts.security.ok ? 'OK' : 'BLOCKED'} - ${summary.verdicts.security.message}`);
216
+ lines.push(` GA: ${summary.verdicts.ga.verdict} - ${summary.verdicts.ga.message}`);
217
+
218
+ lines.push('='.repeat(80) + '\n');
219
+
220
+ return lines.join('\n');
221
+ }
222
+