@veraxhq/verax 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +14 -18
  2. package/bin/verax.js +7 -0
  3. package/package.json +3 -3
  4. package/src/cli/commands/baseline.js +104 -0
  5. package/src/cli/commands/default.js +79 -25
  6. package/src/cli/commands/ga.js +243 -0
  7. package/src/cli/commands/gates.js +95 -0
  8. package/src/cli/commands/inspect.js +131 -2
  9. package/src/cli/commands/release-check.js +213 -0
  10. package/src/cli/commands/run.js +246 -35
  11. package/src/cli/commands/security-check.js +211 -0
  12. package/src/cli/commands/truth.js +114 -0
  13. package/src/cli/entry.js +304 -67
  14. package/src/cli/util/angular-component-extractor.js +179 -0
  15. package/src/cli/util/angular-navigation-detector.js +141 -0
  16. package/src/cli/util/angular-network-detector.js +161 -0
  17. package/src/cli/util/angular-state-detector.js +162 -0
  18. package/src/cli/util/ast-interactive-detector.js +546 -0
  19. package/src/cli/util/ast-network-detector.js +603 -0
  20. package/src/cli/util/ast-usestate-detector.js +602 -0
  21. package/src/cli/util/bootstrap-guard.js +86 -0
  22. package/src/cli/util/determinism-runner.js +123 -0
  23. package/src/cli/util/determinism-writer.js +129 -0
  24. package/src/cli/util/env-url.js +4 -0
  25. package/src/cli/util/expectation-extractor.js +369 -73
  26. package/src/cli/util/findings-writer.js +126 -16
  27. package/src/cli/util/learn-writer.js +3 -1
  28. package/src/cli/util/observe-writer.js +3 -1
  29. package/src/cli/util/paths.js +3 -12
  30. package/src/cli/util/project-discovery.js +3 -0
  31. package/src/cli/util/project-writer.js +3 -1
  32. package/src/cli/util/run-resolver.js +64 -0
  33. package/src/cli/util/source-requirement.js +55 -0
  34. package/src/cli/util/summary-writer.js +1 -0
  35. package/src/cli/util/svelte-navigation-detector.js +163 -0
  36. package/src/cli/util/svelte-network-detector.js +80 -0
  37. package/src/cli/util/svelte-sfc-extractor.js +147 -0
  38. package/src/cli/util/svelte-state-detector.js +243 -0
  39. package/src/cli/util/vue-navigation-detector.js +177 -0
  40. package/src/cli/util/vue-sfc-extractor.js +162 -0
  41. package/src/cli/util/vue-state-detector.js +215 -0
  42. package/src/verax/cli/finding-explainer.js +56 -3
  43. package/src/verax/core/artifacts/registry.js +154 -0
  44. package/src/verax/core/artifacts/verifier.js +980 -0
  45. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  46. package/src/verax/core/baseline/baseline.snapshot.js +231 -0
  47. package/src/verax/core/capabilities/gates.js +499 -0
  48. package/src/verax/core/capabilities/registry.js +475 -0
  49. package/src/verax/core/confidence/confidence-compute.js +137 -0
  50. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  51. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  52. package/src/verax/core/confidence/confidence-weights.js +44 -0
  53. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  54. package/src/verax/core/confidence/confidence.loader.js +79 -0
  55. package/src/verax/core/confidence/confidence.schema.js +94 -0
  56. package/src/verax/core/confidence-engine-refactor.js +484 -0
  57. package/src/verax/core/confidence-engine.js +486 -0
  58. package/src/verax/core/confidence-engine.js.backup +471 -0
  59. package/src/verax/core/contracts/index.js +29 -0
  60. package/src/verax/core/contracts/types.js +185 -0
  61. package/src/verax/core/contracts/validators.js +381 -0
  62. package/src/verax/core/decision-snapshot.js +30 -3
  63. package/src/verax/core/decisions/decision.trace.js +276 -0
  64. package/src/verax/core/determinism/contract-writer.js +89 -0
  65. package/src/verax/core/determinism/contract.js +139 -0
  66. package/src/verax/core/determinism/diff.js +364 -0
  67. package/src/verax/core/determinism/engine.js +221 -0
  68. package/src/verax/core/determinism/finding-identity.js +148 -0
  69. package/src/verax/core/determinism/normalize.js +438 -0
  70. package/src/verax/core/determinism/report-writer.js +92 -0
  71. package/src/verax/core/determinism/run-fingerprint.js +118 -0
  72. package/src/verax/core/dynamic-route-intelligence.js +528 -0
  73. package/src/verax/core/evidence/evidence-capture-service.js +307 -0
  74. package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
  75. package/src/verax/core/evidence-builder.js +487 -0
  76. package/src/verax/core/execution-mode-context.js +77 -0
  77. package/src/verax/core/execution-mode-detector.js +190 -0
  78. package/src/verax/core/failures/exit-codes.js +86 -0
  79. package/src/verax/core/failures/failure-summary.js +76 -0
  80. package/src/verax/core/failures/failure.factory.js +225 -0
  81. package/src/verax/core/failures/failure.ledger.js +132 -0
  82. package/src/verax/core/failures/failure.types.js +196 -0
  83. package/src/verax/core/failures/index.js +10 -0
  84. package/src/verax/core/ga/ga-report-writer.js +43 -0
  85. package/src/verax/core/ga/ga.artifact.js +49 -0
  86. package/src/verax/core/ga/ga.contract.js +434 -0
  87. package/src/verax/core/ga/ga.enforcer.js +86 -0
  88. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  89. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  90. package/src/verax/core/guardrails/policy.loader.js +83 -0
  91. package/src/verax/core/guardrails/policy.schema.js +110 -0
  92. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  93. package/src/verax/core/guardrails-engine.js +505 -0
  94. package/src/verax/core/observe/run-timeline.js +316 -0
  95. package/src/verax/core/perf/perf.contract.js +186 -0
  96. package/src/verax/core/perf/perf.display.js +65 -0
  97. package/src/verax/core/perf/perf.enforcer.js +91 -0
  98. package/src/verax/core/perf/perf.monitor.js +209 -0
  99. package/src/verax/core/perf/perf.report.js +198 -0
  100. package/src/verax/core/pipeline-tracker.js +238 -0
  101. package/src/verax/core/product-definition.js +127 -0
  102. package/src/verax/core/release/provenance.builder.js +271 -0
  103. package/src/verax/core/release/release-report-writer.js +40 -0
  104. package/src/verax/core/release/release.enforcer.js +159 -0
  105. package/src/verax/core/release/reproducibility.check.js +221 -0
  106. package/src/verax/core/release/sbom.builder.js +283 -0
  107. package/src/verax/core/report/cross-index.js +192 -0
  108. package/src/verax/core/report/human-summary.js +222 -0
  109. package/src/verax/core/route-intelligence.js +419 -0
  110. package/src/verax/core/security/secrets.scan.js +326 -0
  111. package/src/verax/core/security/security-report.js +50 -0
  112. package/src/verax/core/security/security.enforcer.js +124 -0
  113. package/src/verax/core/security/supplychain.defaults.json +38 -0
  114. package/src/verax/core/security/supplychain.policy.js +326 -0
  115. package/src/verax/core/security/vuln.scan.js +265 -0
  116. package/src/verax/core/truth/truth.certificate.js +250 -0
  117. package/src/verax/core/ui-feedback-intelligence.js +515 -0
  118. package/src/verax/detect/confidence-engine.js +628 -40
  119. package/src/verax/detect/confidence-helper.js +33 -0
  120. package/src/verax/detect/detection-engine.js +18 -1
  121. package/src/verax/detect/dynamic-route-findings.js +335 -0
  122. package/src/verax/detect/expectation-chain-detector.js +417 -0
  123. package/src/verax/detect/expectation-model.js +3 -1
  124. package/src/verax/detect/findings-writer.js +141 -5
  125. package/src/verax/detect/index.js +229 -5
  126. package/src/verax/detect/journey-stall-detector.js +558 -0
  127. package/src/verax/detect/route-findings.js +218 -0
  128. package/src/verax/detect/ui-feedback-findings.js +207 -0
  129. package/src/verax/detect/verdict-engine.js +57 -3
  130. package/src/verax/detect/view-switch-correlator.js +242 -0
  131. package/src/verax/index.js +413 -45
  132. package/src/verax/learn/action-contract-extractor.js +682 -64
  133. package/src/verax/learn/route-validator.js +4 -1
  134. package/src/verax/observe/index.js +88 -843
  135. package/src/verax/observe/interaction-runner.js +25 -8
  136. package/src/verax/observe/observe-context.js +205 -0
  137. package/src/verax/observe/observe-helpers.js +191 -0
  138. package/src/verax/observe/observe-runner.js +226 -0
  139. package/src/verax/observe/observers/budget-observer.js +185 -0
  140. package/src/verax/observe/observers/console-observer.js +102 -0
  141. package/src/verax/observe/observers/coverage-observer.js +107 -0
  142. package/src/verax/observe/observers/interaction-observer.js +471 -0
  143. package/src/verax/observe/observers/navigation-observer.js +132 -0
  144. package/src/verax/observe/observers/network-observer.js +87 -0
  145. package/src/verax/observe/observers/safety-observer.js +82 -0
  146. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  147. package/src/verax/observe/ui-feedback-detector.js +742 -0
  148. package/src/verax/observe/ui-signal-sensor.js +148 -2
  149. package/src/verax/scan-summary-writer.js +42 -8
  150. package/src/verax/shared/artifact-manager.js +8 -5
  151. package/src/verax/shared/css-spinner-rules.js +204 -0
  152. package/src/verax/shared/view-switch-rules.js +208 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * PHASE 21.11 — Truth Command
3
+ *
4
+ * `verax truth` - Shows truth certificate summary
5
+ */
6
+
7
+ import { resolve } from 'path';
8
+ import { findLatestRunId } from '../util/run-resolver.js';
9
+ import { generateTruthCertificate, loadTruthCertificate } from '../../verax/core/truth/truth.certificate.js';
10
+
11
+ /**
12
+ * Truth command
13
+ *
14
+ * @param {string} projectDir - Project directory
15
+ * @param {Object} options - Command options
16
+ */
17
+ export async function truthCommand(projectDir, options = {}) {
18
+ const { json = false, runId: runIdOpt = null } = options;
19
+
20
+ const runId = runIdOpt || findLatestRunId(projectDir);
21
+
22
+ if (!runId) {
23
+ if (json) {
24
+ console.log(JSON.stringify({
25
+ error: 'NO_RUNS_FOUND',
26
+ message: 'No runs found. Run a scan first.'
27
+ }, null, 2));
28
+ } else {
29
+ console.log('\n=== Truth Certificate ===\n');
30
+ console.log('Error: No runs found. Run a scan first.\n');
31
+ }
32
+ return;
33
+ }
34
+
35
+ // Try to load existing certificate, otherwise generate
36
+ let certificate = loadTruthCertificate(projectDir, runId);
37
+
38
+ if (!certificate) {
39
+ certificate = await generateTruthCertificate(projectDir, runId);
40
+ if (certificate) {
41
+ const { writeTruthCertificate } = await import('../../verax/core/truth/truth.certificate.js');
42
+ writeTruthCertificate(projectDir, runId, certificate);
43
+ }
44
+ }
45
+
46
+ if (!certificate) {
47
+ if (json) {
48
+ console.log(JSON.stringify({
49
+ error: 'CERTIFICATE_GENERATION_FAILED',
50
+ message: 'Failed to generate truth certificate'
51
+ }, null, 2));
52
+ } else {
53
+ console.log('\n=== Truth Certificate ===\n');
54
+ console.log('Error: Failed to generate truth certificate\n');
55
+ }
56
+ return;
57
+ }
58
+
59
+ if (json) {
60
+ console.log(JSON.stringify(certificate, null, 2));
61
+ } else {
62
+ console.log('\n=== Truth Certificate ===\n');
63
+ console.log(`Run ID: ${certificate.runId}`);
64
+ console.log(`URL: ${certificate.url || 'N/A'}`);
65
+ console.log(`Generated: ${certificate.generatedAt}`);
66
+
67
+ console.log('\nEvidence Law:');
68
+ console.log(` Status: ${certificate.evidenceLaw.status}`);
69
+ console.log(` Violated: ${certificate.evidenceLaw.violated ? 'YES' : 'NO'}`);
70
+
71
+ console.log('\nDeterminism:');
72
+ console.log(` Verdict: ${certificate.determinism.verdict}`);
73
+ console.log(` Message: ${certificate.determinism.message}`);
74
+
75
+ console.log('\nFailures:');
76
+ console.log(` Total: ${certificate.failures.total}`);
77
+ console.log(` Blocking: ${certificate.failures.blocking ? 'YES' : 'NO'}`);
78
+ console.log(` Degraded: ${certificate.failures.degraded ? 'YES' : 'NO'}`);
79
+ console.log(` By Severity: ${JSON.stringify(certificate.failures.bySeverity)}`);
80
+
81
+ console.log('\nGA:');
82
+ console.log(` Verdict: ${certificate.ga.verdict}`);
83
+ console.log(` Ready: ${certificate.ga.ready ? 'YES' : 'NO'}`);
84
+ console.log(` Blockers: ${certificate.ga.blockers}`);
85
+ console.log(` Warnings: ${certificate.ga.warnings}`);
86
+
87
+ console.log('\nSecurity:');
88
+ console.log(` Overall: ${certificate.security.overall}`);
89
+ console.log(` Secrets: ${certificate.security.secrets}`);
90
+ console.log(` Vulnerabilities: ${certificate.security.vulnerabilities}`);
91
+
92
+ console.log('\nPerformance:');
93
+ console.log(` Verdict: ${certificate.performance.verdict}`);
94
+ console.log(` OK: ${certificate.performance.ok ? 'YES' : 'NO'}`);
95
+ console.log(` Violations: ${certificate.performance.violations}`);
96
+
97
+ console.log('\nBaseline:');
98
+ console.log(` Hash: ${certificate.baseline.hash || 'N/A'}`);
99
+ console.log(` Frozen: ${certificate.baseline.frozen ? 'YES' : 'NO'}`);
100
+ console.log(` Version: ${certificate.baseline.version || 'N/A'}`);
101
+
102
+ console.log('\nProvenance:');
103
+ console.log(` Hash: ${certificate.provenance.hash || 'N/A'}`);
104
+ console.log(` Version: ${certificate.provenance.version || 'N/A'}`);
105
+
106
+ console.log('\nOverall Verdict:');
107
+ console.log(` Status: ${certificate.overallVerdict.status}`);
108
+ if (certificate.overallVerdict.reasons.length > 0) {
109
+ console.log(` Reasons: ${certificate.overallVerdict.reasons.join('; ')}`);
110
+ }
111
+ console.log('');
112
+ }
113
+ }
114
+
package/src/cli/entry.js CHANGED
@@ -3,6 +3,11 @@
3
3
  /**
4
4
  * VERAX CLI Entry Point
5
5
  *
6
+ * PHASE 21.6.1: Two-Phase CLI Bootstrap
7
+ *
8
+ * Phase A: Raw argv parsing with zero side effects
9
+ * Phase B: Dispatch - inspection commands bypass execution bootstrap
10
+ *
6
11
  * Commands:
7
12
  * - verax (smart default with URL detection/prompting)
8
13
  * - verax run --url <url> (strict, non-interactive)
@@ -22,11 +27,47 @@ import { defaultCommand } from './commands/default.js';
22
27
  import { runCommand } from './commands/run.js';
23
28
  import { inspectCommand } from './commands/inspect.js';
24
29
  import { doctorCommand } from './commands/doctor.js';
30
+ import { gatesCommand } from './commands/gates.js';
31
+ import { gaCommand } from './commands/ga.js';
32
+ import { releaseCheckCommand } from './commands/release-check.js';
33
+ import { securityCheckCommand } from './commands/security-check.js';
34
+ import { baselineCommand } from './commands/baseline.js';
35
+ import { truthCommand } from './commands/truth.js';
25
36
  import { getExitCode, UsageError } from './util/errors.js';
37
+ import { getSourceCodeRequirementBanner } from '../verax/core/product-definition.js';
38
+ import { enableInspectionMode, disableInspectionMode } from './util/bootstrap-guard.js';
26
39
 
27
40
  const __filename = fileURLToPath(import.meta.url);
28
41
  const __dirname = dirname(__filename);
29
42
 
43
+ /**
44
+ * PHASE 21.6.1: CLI Self-Identification
45
+ * Prints diagnostic information to identify which binary is executed
46
+ */
47
+ function printCLIIdentity(args) {
48
+ const verbose = args.includes('--verbose');
49
+ const debugCli = process.env.VERAX_DEBUG_CLI === '1';
50
+
51
+ if (!verbose && !debugCli) {
52
+ return;
53
+ }
54
+
55
+ console.error('=== VERAX CLI IDENTITY ===');
56
+ console.error(`process.argv[1]: ${process.argv[1]}`);
57
+ console.error(`__filename: ${__filename}`);
58
+
59
+ try {
60
+ const pkgPath = resolve(__dirname, '../../package.json');
61
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
62
+ console.error(`package.json version: ${pkg.version}`);
63
+ console.error(`package.json location: ${pkgPath}`);
64
+ } catch (error) {
65
+ console.error(`Failed to read package.json: ${error.message}`);
66
+ }
67
+
68
+ console.error('========================');
69
+ }
70
+
30
71
  // Read package.json for version
31
72
  function getVersion() {
32
73
  try {
@@ -38,84 +79,263 @@ function getVersion() {
38
79
  }
39
80
  }
40
81
 
41
- async function main() {
42
- const args = process.argv.slice(2);
82
+ /**
83
+ * PHASE A: Raw argv parsing with zero side effects
84
+ *
85
+ * @param {string[]} args - Raw command line arguments
86
+ * @returns {Object} Parsed command structure
87
+ */
88
+ function parseCommand(args) {
89
+ // Handle --version (no side effects)
90
+ if (args.includes('--version') || args.includes('-v')) {
91
+ return { type: 'version' };
92
+ }
43
93
 
44
- try {
45
- // Handle --version
46
- if (args.includes('--version') || args.includes('-v')) {
47
- console.log(`verax ${getVersion()}`);
48
- process.exit(0);
94
+ // Handle explicit --help (no side effects)
95
+ if (args.includes('--help') || args.includes('-h')) {
96
+ return { type: 'help' };
97
+ }
98
+
99
+ // If no args, default to smart mode
100
+ if (args.length === 0) {
101
+ return { type: 'default', options: {} };
102
+ }
103
+
104
+ const command = args[0];
105
+
106
+ // Inspection commands (must bypass execution bootstrap)
107
+ if (command === 'inspect') {
108
+ if (args.length < 2) {
109
+ throw new UsageError('inspect command requires a run path argument');
49
110
  }
50
-
51
- // Handle explicit --help
52
- if (args.includes('--help') || args.includes('-h')) {
53
- showHelp();
54
- process.exit(0);
111
+ return {
112
+ type: 'inspect',
113
+ runPath: args[1],
114
+ json: args.includes('--json'),
115
+ timeline: args.includes('--timeline'),
116
+ decisions: args.includes('--decisions'),
117
+ failures: args.includes('--failures'),
118
+ performance: args.includes('--performance'),
119
+ evidence: args.includes('--evidence')
120
+ };
121
+ }
122
+
123
+ if (command === 'gates') {
124
+ return {
125
+ type: 'gates',
126
+ json: args.includes('--json'),
127
+ verbose: args.includes('--verbose')
128
+ };
129
+ }
130
+
131
+ if (command === 'ga') {
132
+ return {
133
+ type: 'ga',
134
+ runId: parseArg(args, '--run-id'),
135
+ json: args.includes('--json')
136
+ };
137
+ }
138
+
139
+ if (command === 'release:check' || command === 'release-check') {
140
+ return {
141
+ type: 'release:check',
142
+ json: args.includes('--json')
143
+ };
144
+ }
145
+
146
+ if (command === 'security:check' || command === 'security-check') {
147
+ return {
148
+ type: 'security:check',
149
+ json: args.includes('--json')
150
+ };
151
+ }
152
+
153
+ if (command === 'baseline') {
154
+ return {
155
+ type: 'baseline',
156
+ json: args.includes('--json')
157
+ };
158
+ }
159
+
160
+ if (command === 'truth') {
161
+ return {
162
+ type: 'truth',
163
+ runId: parseArg(args, '--run-id'),
164
+ json: args.includes('--json')
165
+ };
166
+ }
167
+
168
+ if (command === 'doctor') {
169
+ const allowedFlags = new Set(['--json']);
170
+ const extraFlags = args.slice(1).filter((a) => a.startsWith('-') && !allowedFlags.has(a));
171
+ return {
172
+ type: 'doctor',
173
+ json: args.includes('--json'),
174
+ extraFlags
175
+ };
176
+ }
177
+
178
+ // Execution commands
179
+ if (command === 'run') {
180
+ const url = parseArg(args, '--url');
181
+ const fixture = parseArg(args, '--fixture');
182
+ if (!url && !fixture) {
183
+ throw new UsageError('run command requires --url <url> or --fixture <fixture> argument');
55
184
  }
56
-
57
- // If no args, run default command
58
- if (args.length === 0) {
59
- await defaultCommand({});
60
- process.exit(0);
185
+ return {
186
+ type: 'run',
187
+ url,
188
+ fixture,
189
+ src: parseArg(args, '--src') || '.',
190
+ out: parseArg(args, '--out') || '.verax',
191
+ json: args.includes('--json'),
192
+ verbose: args.includes('--verbose'),
193
+ determinism: args.includes('--determinism'),
194
+ determinismRuns: args.includes('--determinism') ? parseInt(parseArg(args, '--determinism-runs') || '2', 10) : 0
195
+ };
196
+ }
197
+
198
+ if (command === 'help' || command === '--help' || command === '-h') {
199
+ return { type: 'help' };
200
+ }
201
+
202
+ // Default command: smart scanning mode
203
+ return {
204
+ type: 'default',
205
+ options: {
206
+ url: parseArg(args, '--url'),
207
+ src: parseArg(args, '--src') || '.',
208
+ out: parseArg(args, '--out') || '.verax',
209
+ json: args.includes('--json'),
210
+ verbose: args.includes('--verbose')
61
211
  }
212
+ };
213
+ }
214
+
215
+ /**
216
+ * PHASE B: Dispatch with isolation enforcement
217
+ *
218
+ * @param {Object} parsed - Parsed command from Phase A
219
+ */
220
+ async function dispatch(parsed) {
221
+ try {
222
+ // Inspection commands: enable guard mode
223
+ const isInspectionCommand = ['inspect', 'gates', 'ga', 'doctor', 'release:check', 'security:check', 'baseline', 'truth'].includes(parsed.type);
62
224
 
63
- const command = args[0];
64
-
65
- // Handle 'run' command
66
- if (command === 'run') {
67
- const url = parseArg(args, '--url');
68
- const src = parseArg(args, '--src') || '.';
69
- const out = parseArg(args, '--out') || '.verax';
70
- const json = args.includes('--json');
71
- const verbose = args.includes('--verbose');
72
-
73
- if (!url) {
74
- throw new UsageError('run command requires --url <url> argument');
75
- }
76
-
77
- await runCommand({ url, src, out, json, verbose });
78
- process.exit(0);
225
+ if (isInspectionCommand) {
226
+ enableInspectionMode();
79
227
  }
80
228
 
81
- // Handle 'inspect' command
82
- if (command === 'inspect') {
83
- if (args.length < 2) {
84
- throw new UsageError('inspect command requires a run path argument');
229
+ try {
230
+ switch (parsed.type) {
231
+ case 'version':
232
+ console.log(`verax ${getVersion()}`);
233
+ process.exit(0);
234
+ break;
235
+
236
+ case 'help':
237
+ showHelp();
238
+ process.exit(0);
239
+ break;
240
+
241
+ case 'inspect':
242
+ await inspectCommand(parsed.runPath, {
243
+ json: parsed.json,
244
+ timeline: parsed.timeline,
245
+ decisions: parsed.decisions,
246
+ failures: parsed.failures,
247
+ performance: parsed.performance,
248
+ evidence: parsed.evidence
249
+ });
250
+ process.exit(0);
251
+ break;
252
+
253
+ case 'gates':
254
+ await gatesCommand({ json: parsed.json, verbose: parsed.verbose });
255
+ // gatesCommand handles exit code internally
256
+ return;
257
+
258
+ case 'ga':
259
+ await gaCommand({ runId: parsed.runId, json: parsed.json });
260
+ // gaCommand handles exit code internally
261
+ return;
262
+
263
+ case 'release:check':
264
+ await releaseCheckCommand({ json: parsed.json });
265
+ // releaseCheckCommand handles exit code internally
266
+ return;
267
+
268
+ case 'security:check':
269
+ await securityCheckCommand({ json: parsed.json });
270
+ // securityCheckCommand handles exit code internally
271
+ return;
272
+
273
+ case 'baseline':
274
+ await baselineCommand(process.cwd(), { json: parsed.json });
275
+ process.exit(0);
276
+ break;
277
+
278
+ case 'truth':
279
+ await truthCommand(process.cwd(), { json: parsed.json, runId: parsed.runId });
280
+ process.exit(0);
281
+ break;
282
+
283
+ case 'doctor':
284
+ await doctorCommand({ json: parsed.json, extraFlags: parsed.extraFlags });
285
+ process.exit(0);
286
+ break;
287
+
288
+ case 'run':
289
+ await runCommand({
290
+ url: parsed.url,
291
+ fixture: parsed.fixture,
292
+ src: parsed.src,
293
+ out: parsed.out,
294
+ json: parsed.json,
295
+ verbose: parsed.verbose,
296
+ determinism: parsed.determinism,
297
+ determinismRuns: parsed.determinismRuns
298
+ });
299
+ process.exit(0);
300
+ break;
301
+
302
+ case 'default':
303
+ await defaultCommand(parsed.options);
304
+ process.exit(0);
305
+ break;
306
+
307
+ default:
308
+ throw new UsageError(`Unknown command: ${parsed.type}`);
309
+ }
310
+ } finally {
311
+ if (isInspectionCommand) {
312
+ disableInspectionMode();
85
313
  }
86
-
87
- const runPath = args[1];
88
- const json = args.includes('--json');
89
-
90
- await inspectCommand(runPath, { json });
91
- process.exit(0);
92
- }
93
-
94
- // Handle 'doctor' command
95
- if (command === 'doctor') {
96
- const allowedFlags = new Set(['--json']);
97
- const extraFlags = args.slice(1).filter((a) => a.startsWith('-') && !allowedFlags.has(a));
98
- const json = args.includes('--json');
99
- await doctorCommand({ json, extraFlags });
100
- process.exit(0);
101
314
  }
102
-
103
- // Handle 'help' command
104
- if (command === 'help' || command === '--help' || command === '-h') {
105
- showHelp();
106
- process.exit(0);
315
+ } catch (error) {
316
+ // Print error message
317
+ if (error.message) {
318
+ console.error(`Error: ${error.message}`);
107
319
  }
108
320
 
109
- // Default command: smart scanning mode
110
- // Options can be passed as flags before/after the default command position
111
- const url = parseArg(args, '--url');
112
- const src = parseArg(args, '--src') || '.';
113
- const out = parseArg(args, '--out') || '.verax';
114
- const json = args.includes('--json');
115
- const verbose = args.includes('--verbose');
321
+ // Get exit code
322
+ const exitCode = getExitCode(error);
323
+ process.exit(exitCode);
324
+ }
325
+ }
326
+
327
+ async function main() {
328
+ const args = process.argv.slice(2);
329
+
330
+ // PHASE 21.6.1: Print CLI identity for debugging
331
+ printCLIIdentity(args);
332
+
333
+ try {
334
+ // PHASE A: Parse command (zero side effects)
335
+ const parsed = parseCommand(args);
116
336
 
117
- await defaultCommand({ url, src, out, json, verbose });
118
- process.exit(0);
337
+ // PHASE B: Dispatch with isolation enforcement
338
+ await dispatch(parsed);
119
339
  } catch (error) {
120
340
  // Print error message
121
341
  if (error.message) {
@@ -130,24 +350,41 @@ async function main() {
130
350
 
131
351
  function showHelp() {
132
352
  const version = getVersion();
353
+ const banner = getSourceCodeRequirementBanner();
133
354
  console.log(`
134
355
  verax ${version}
135
356
  VERAX — Silent failure detection for websites
136
357
 
358
+ ${banner}
359
+ Canonical product contract: docs/README.md
360
+
137
361
  USAGE:
138
362
  verax [options] Smart mode (detects/prompts for URL)
139
363
  verax run --url <url> [options] Strict mode (non-interactive, CI-friendly)
140
364
  verax inspect <runPath> [--json] Inspect an existing run
365
+ verax inspect <runPath> --timeline Show chronological timeline
366
+ verax inspect <runPath> --decisions Show decision trace
367
+ verax inspect <runPath> --failures Show failure ledger
368
+ verax inspect <runPath> --performance Show performance metrics
369
+ verax inspect <runPath> --evidence Show evidence cross-index
141
370
  verax doctor [--json] Diagnose local environment
371
+ verax gates [--json] [--verbose] Evaluate capability gates (PHASE 19)
372
+ verax ga [--run-id <id>] [--json] Evaluate GA readiness (PHASE 21.6)
373
+ verax release:check [--json] Check release readiness (PHASE 21.7)
374
+ verax security:check [--json] Check security baseline (PHASE 21.8)
375
+ verax baseline [--json] Show baseline hash and drift status (PHASE 21.11)
376
+ verax truth [--run-id <id>] [--json] Show truth certificate (PHASE 21.11)
142
377
  verax --version Show version
143
378
  verax --help Show this help
144
379
 
145
380
  OPTIONS:
146
381
  --url <url> Target URL to scan
147
- --src <path> Source directory (default: .)
382
+ --src <path> Source directory (default: .) — required; URL-only scans are blocked
148
383
  --out <path> Output directory for artifacts (default: .verax)
149
384
  --json Output as JSON lines (progress events)
150
385
  --verbose Verbose output
386
+ --determinism Run determinism check (executes scan multiple times and compares results)
387
+ --determinism-runs <N> Number of runs for determinism check (default: 2)
151
388
  --help Show this help
152
389
  --version Show version
153
390