@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,192 @@
1
+ /**
2
+ * EXECUTION MODE DETECTOR
3
+ *
4
+ * Automatically detects whether VERAX is running in:
5
+ * 1. PROJECT_SCAN: Local source code is available for analysis
6
+ * 2. WEB_SCAN_LIMITED: Only URL provided, no source code available
7
+ *
8
+ * This determines:
9
+ * - What analysis techniques can be used
10
+ * - Maximum confidence ceiling (0.45 for WEB_SCAN_LIMITED)
11
+ * - What explanations to provide to users
12
+ *
13
+ * PRINCIPLES:
14
+ * - Detection is automatic and implicit (no user configuration needed)
15
+ * - Behavior changes based on what's available, not explicit flags
16
+ * - Users understand limitations from generated explanations
17
+ */
18
+
19
+ import { existsSync, readdirSync, statSync } from 'fs';
20
+ import { join as _join } from 'path';
21
+
22
+ /**
23
+ * Execution mode constants
24
+ */
25
+ export const EXECUTION_MODES = {
26
+ PROJECT_SCAN: 'PROJECT_SCAN', // Full analysis with source code
27
+ WEB_SCAN_LIMITED: 'WEB_SCAN_LIMITED' // URL-only analysis without source
28
+ };
29
+
30
+ /**
31
+ * Confidence ceiling by mode
32
+ */
33
+ export const CONFIDENCE_CEILINGS = {
34
+ [EXECUTION_MODES.PROJECT_SCAN]: 1.0, // No ceiling, full range [0, 1]
35
+ [EXECUTION_MODES.WEB_SCAN_LIMITED]: 0.45 // Limited to 45% max confidence
36
+ };
37
+
38
+ /**
39
+ * Detect execution mode based on available inputs
40
+ * @param {string} srcPath - Path to source code directory
41
+ * @param {string} _url - Target URL
42
+ * @ts-expect-error - JSDoc param documented but unused
43
+ * @returns {Object} - { mode, ceiling, explanation }
44
+ */
45
+ export function detectExecutionMode(srcPath, _url) {
46
+ // Check if source code is available and viable
47
+ const hasSourceCode = isSourceCodeAvailable(srcPath);
48
+
49
+ if (hasSourceCode) {
50
+ return {
51
+ mode: EXECUTION_MODES.PROJECT_SCAN,
52
+ ceiling: CONFIDENCE_CEILINGS[EXECUTION_MODES.PROJECT_SCAN],
53
+ explanation: 'Full project analysis: source code is available for static analysis, expectations extraction, and dynamic behavior correlation.',
54
+ reason: 'Source code detected at ' + srcPath
55
+ };
56
+ } else {
57
+ return {
58
+ mode: EXECUTION_MODES.WEB_SCAN_LIMITED,
59
+ ceiling: CONFIDENCE_CEILINGS[EXECUTION_MODES.WEB_SCAN_LIMITED],
60
+ explanation: 'Limited web scan: no local source code available. Analysis is based solely on runtime behavior observation. Confidence is capped at 45% due to inability to correlate with code-level expectations.',
61
+ reason: 'No source code available; analyzing runtime behavior only'
62
+ };
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Check if source code is available and viable for analysis
68
+ * @param {string} srcPath - Path to source code directory
69
+ * @returns {boolean} - True if source code appears to be available
70
+ */
71
+ function isSourceCodeAvailable(srcPath) {
72
+ // Check if path exists
73
+ if (!existsSync(srcPath)) {
74
+ return false;
75
+ }
76
+
77
+ // Check if it's a directory
78
+ try {
79
+ const stats = statSync(srcPath);
80
+ if (!stats.isDirectory()) {
81
+ return false;
82
+ }
83
+ } catch {
84
+ return false;
85
+ }
86
+
87
+ // Check for minimum viable source indicators
88
+ return hasSourceIndicators(srcPath);
89
+ }
90
+
91
+ /**
92
+ * Check for presence of source code indicators
93
+ * @param {string} srcPath - Path to potential source directory
94
+ * @returns {boolean} - True if source indicators are present
95
+ */
96
+ function hasSourceIndicators(srcPath) {
97
+ try {
98
+ const entries = readdirSync(srcPath, { withFileTypes: true });
99
+
100
+ // Look for common source code patterns
101
+ const indicators = {
102
+ hasJs: false, // .js, .jsx, .ts, .tsx files
103
+ hasSrc: false, // src/ directory
104
+ hasPackageJson: false,
105
+ hasPythonFiles: false,
106
+ hasGoFiles: false
107
+ };
108
+
109
+ for (const entry of entries) {
110
+ const name = entry.name;
111
+ const lowerName = name.toLowerCase();
112
+
113
+ // Check for source directories
114
+ if (entry.isDirectory() &&
115
+ (lowerName === 'src' || lowerName === 'lib' || lowerName === 'app' ||
116
+ lowerName === 'pages' || lowerName === 'components' || lowerName === 'python')) {
117
+ indicators.hasSrc = true;
118
+ }
119
+
120
+ // Check for package.json (Node.js projects)
121
+ if (name === 'package.json') {
122
+ indicators.hasPackageJson = true;
123
+ }
124
+
125
+ // Check for JS/TS files
126
+ if (lowerName.endsWith('.js') || lowerName.endsWith('.jsx') ||
127
+ lowerName.endsWith('.ts') || lowerName.endsWith('.tsx') ||
128
+ lowerName.endsWith('.mjs') || lowerName.endsWith('.cjs')) {
129
+ indicators.hasJs = true;
130
+ }
131
+
132
+ // Check for Python files
133
+ if (lowerName.endsWith('.py')) {
134
+ indicators.hasPythonFiles = true;
135
+ }
136
+
137
+ // Check for Go files
138
+ if (lowerName.endsWith('.go')) {
139
+ indicators.hasGoFiles = true;
140
+ }
141
+ }
142
+
143
+ // Multiple indicators needed to confirm source code is present
144
+ const indicatorCount = Object.values(indicators).filter(Boolean).length;
145
+ return indicatorCount >= 2; // Need at least 2 indicators
146
+
147
+ } catch (error) {
148
+ return false;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Apply confidence ceiling to a score
154
+ * @param {number} score - Confidence score (0..1 float)
155
+ * @param {string} mode - Execution mode
156
+ * @returns {number} - Capped confidence score (0..1 float)
157
+ */
158
+ export function applyConfidenceCeiling(score, mode) {
159
+ const ceiling = CONFIDENCE_CEILINGS[mode] || 1.0;
160
+ return Math.min(score, ceiling);
161
+ }
162
+
163
+ /**
164
+ * Generate execution mode explanation for output
165
+ * @param {string} mode - Execution mode
166
+ * @param {string} ceiling - Confidence ceiling
167
+ * @returns {string} - Human-readable explanation
168
+ */
169
+ export function generateModeExplanation(mode, ceiling) {
170
+ switch (mode) {
171
+ case EXECUTION_MODES.PROJECT_SCAN:
172
+ return `Running in PROJECT_SCAN mode. Full analysis enabled with source code available.`;
173
+
174
+ case EXECUTION_MODES.WEB_SCAN_LIMITED:
175
+ // @ts-expect-error - Arithmetic on constant
176
+ return `Running in WEB_SCAN_LIMITED mode. No source code available; analysis limited to runtime observation. Confidence capped at ${Math.round(ceiling * 100)}%.`;
177
+
178
+ default:
179
+ return 'Execution mode unknown.';
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Format execution mode info for CLI output
185
+ * @param {Object} modeInfo - Result from detectExecutionMode()
186
+ * @returns {string} - Formatted text for console output
187
+ */
188
+ export function formatModeForOutput(modeInfo) {
189
+ return `Execution Mode: ${modeInfo.mode}
190
+ Confidence Ceiling: ${Math.round(modeInfo.ceiling * 100)}%
191
+ Reason: ${modeInfo.reason}`;
192
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Exit Codes Contract v1
3
+ *
4
+ * Exit codes with explicit precedence (highest wins):
5
+ * - 64: USAGE ERROR (invalid CLI usage)
6
+ * - 2: TOOL FAILURE (crash, invariant, runtime error)
7
+ * - 20: FAILURE (any CONFIRMED finding)
8
+ * - 10: WARNING (only SUSPECTED/INFORMATIONAL findings)
9
+ * - 0: OK (no CONFIRMED findings)
10
+ */
11
+
12
+ import { FAILURE_SEVERITY as _FAILURE_SEVERITY } from './failure.types.js';
13
+
14
+ /**
15
+ * Exit Code Constants (Contract v1)
16
+ */
17
+ export const EXIT_CODE = {
18
+ OK: 0, // No CONFIRMED findings
19
+ WARNING: 10, // Only SUSPECTED/INFORMATIONAL
20
+ FAILURE: 20, // Any CONFIRMED finding
21
+ TOOL_FAILURE: 2, // Crash, invariant, runtime error
22
+ USAGE_ERROR: 64 // Invalid CLI usage
23
+ };
24
+
25
+ /**
26
+ * Determine exit code with precedence (highest wins)
27
+ * Precedence: 64 > 2 > 20 > 10 > 0
28
+ *
29
+ * @param {Object} ledgerSummary - Failure ledger summary
30
+ * @param {string} _determinismVerdict - Determinism verdict
31
+ * @ts-expect-error - JSDoc param documented but unused
32
+ * @param {boolean} evidenceLawViolated - Whether Evidence Law was violated
33
+ * @param {boolean} policyInvalid - Whether policy was invalid
34
+ * @returns {number} Exit code
35
+ */
36
+ export function determineExitCode(ledgerSummary, _determinismVerdict = null, evidenceLawViolated = false, policyInvalid = false) {
37
+ // Precedence 1: USAGE ERROR (64)
38
+ if (policyInvalid) {
39
+ return EXIT_CODE.USAGE_ERROR;
40
+ }
41
+
42
+ // Precedence 2: TOOL FAILURE (2) - Internal corruption or contract violations
43
+ const hasInternalCorruption = ledgerSummary.byCategory?.INTERNAL > 0 ||
44
+ ledgerSummary.byCategory?.CONTRACT > 0;
45
+ if (hasInternalCorruption) {
46
+ return EXIT_CODE.TOOL_FAILURE;
47
+ }
48
+
49
+ // Precedence 2: TOOL FAILURE (2) - BLOCKING failures
50
+ if (ledgerSummary.bySeverity?.BLOCKING > 0) {
51
+ return EXIT_CODE.TOOL_FAILURE;
52
+ }
53
+
54
+ // Precedence 2: TOOL FAILURE (2) - DEGRADED failures
55
+ if (ledgerSummary.bySeverity?.DEGRADED > 0) {
56
+ return EXIT_CODE.TOOL_FAILURE;
57
+ }
58
+
59
+ // Precedence 2: TOOL FAILURE (2) - Evidence Law violation
60
+ if (evidenceLawViolated) {
61
+ return EXIT_CODE.TOOL_FAILURE;
62
+ }
63
+
64
+ // Note: Precedence 3-5 (FAILURE/WARNING/OK) handled by run-result.js
65
+ // This function handles system failures only
66
+
67
+ // No system failures → delegate to findings-based logic
68
+ return EXIT_CODE.OK;
69
+ }
70
+
71
+ /**
72
+ * Get exit code meaning
73
+ *
74
+ * @param {number} exitCode - Exit code
75
+ * @returns {string} Human-readable meaning
76
+ */
77
+ export function getExitCodeMeaning(exitCode) {
78
+ const meanings = {
79
+ [EXIT_CODE.OK]: 'OK (no CONFIRMED findings)',
80
+ [EXIT_CODE.WARNING]: 'WARNING (only SUSPECTED/INFORMATIONAL findings)',
81
+ [EXIT_CODE.FAILURE]: 'FAILURE (CONFIRMED finding detected)',
82
+ [EXIT_CODE.TOOL_FAILURE]: 'TOOL FAILURE (crash, invariant, or runtime error)',
83
+ [EXIT_CODE.USAGE_ERROR]: 'USAGE ERROR (invalid CLI usage)'
84
+ };
85
+
86
+ return meanings[exitCode] || `Unknown exit code: ${exitCode}`;
87
+ }
88
+
@@ -0,0 +1,76 @@
1
+ /**
2
+ * PHASE 21.5 — Failure Summary Formatter
3
+ *
4
+ * Formats failure summaries for CLI output.
5
+ */
6
+
7
+ import { determineExitCode, getExitCodeMeaning as _getExitCodeMeaning } from './exit-codes.js';
8
+
9
+ /**
10
+ * Format failure summary for CLI
11
+ *
12
+ * @param {Object} ledgerSummary - Failure ledger summary
13
+ * @param {string} determinismVerdict - Determinism verdict
14
+ * @param {boolean} evidenceLawViolated - Whether Evidence Law was violated
15
+ * @param {string} ledgerPath - Path to failure ledger file
16
+ * @returns {string} Formatted summary
17
+ */
18
+ export function formatFailureSummary(ledgerSummary, determinismVerdict = null, evidenceLawViolated = false, ledgerPath = null) {
19
+ const lines = [];
20
+
21
+ lines.push('\n═══════════════════════════════════════');
22
+ lines.push('EXECUTION VERDICT');
23
+ lines.push('═══════════════════════════════════════');
24
+
25
+ // Determine verdict
26
+ const highestSeverity = ledgerSummary.highestSeverity;
27
+ let verdict = 'CLEAN';
28
+ if (highestSeverity === 'BLOCKING') {
29
+ verdict = 'BLOCKING';
30
+ } else if (highestSeverity === 'DEGRADED') {
31
+ verdict = 'DEGRADED';
32
+ } else if (highestSeverity === 'WARNING') {
33
+ verdict = 'WARNINGS';
34
+ }
35
+
36
+ lines.push(`Verdict: ${verdict}`);
37
+
38
+ // Determinism verdict
39
+ if (determinismVerdict) {
40
+ lines.push(`Deterministic: ${determinismVerdict === 'DETERMINISTIC' ? 'YES' : 'NO'}`);
41
+ } else {
42
+ lines.push('Deterministic: UNKNOWN');
43
+ }
44
+
45
+ // Evidence Law status
46
+ lines.push(`Evidence Law: ${evidenceLawViolated ? 'VIOLATED' : 'ENFORCED'}`);
47
+
48
+ // Failure summary
49
+ lines.push('');
50
+ lines.push('Failures:');
51
+ lines.push(` BLOCKING: ${ledgerSummary.bySeverity?.BLOCKING || 0}`);
52
+ lines.push(` DEGRADED: ${ledgerSummary.bySeverity?.DEGRADED || 0}`);
53
+ lines.push(` WARNING: ${ledgerSummary.bySeverity?.WARNING || 0}`);
54
+
55
+ // Ledger path
56
+ if (ledgerPath) {
57
+ lines.push('');
58
+ lines.push(`See: ${ledgerPath}`);
59
+ }
60
+
61
+ return lines.join('\n');
62
+ }
63
+
64
+ /**
65
+ * Get exit code from failure ledger and system state
66
+ *
67
+ * @param {Object} ledgerSummary - Failure ledger summary
68
+ * @param {string} determinismVerdict - Determinism verdict
69
+ * @param {boolean} evidenceLawViolated - Whether Evidence Law was violated
70
+ * @param {boolean} policyInvalid - Whether policy was invalid
71
+ * @returns {number} Exit code
72
+ */
73
+ export function getExitCodeFromLedger(ledgerSummary, determinismVerdict = null, evidenceLawViolated = false, policyInvalid = false) {
74
+ return determineExitCode(ledgerSummary, determinismVerdict, evidenceLawViolated, policyInvalid);
75
+ }
76
+
@@ -0,0 +1,225 @@
1
+ /**
2
+ * PHASE 21.5 — Failure Factory
3
+ *
4
+ * Creates properly classified failure objects.
5
+ * No ad-hoc error creation allowed.
6
+ */
7
+
8
+ import { FAILURE_CODE as _FAILURE_CODE, FAILURE_CATEGORY, FAILURE_SEVERITY, EXECUTION_PHASE, validateFailure } from './failure.types.js';
9
+
10
+ /**
11
+ * Create a failure object
12
+ *
13
+ * @param {Object} params
14
+ * @param {string} params.code - Failure code
15
+ * @param {string} params.category - Failure category
16
+ * @param {string} params.severity - Failure severity
17
+ * @param {string} params.phase - Execution phase
18
+ * @param {boolean} params.isRecoverable - Whether recoverable
19
+ * @param {string} params.message - Human-readable message
20
+ * @param {string} params.component - Component name
21
+ * @param {Object} [params.context] - Additional context
22
+ * @param {string} [params.stack] - Stack trace
23
+ * @param {string} [params.recoveryAction] - Recovery action
24
+ * @param {string} [params.impact] - Impact description
25
+ * @returns {Object} Validated failure object
26
+ */
27
+ export function createFailure(params) {
28
+ const {
29
+ code,
30
+ category,
31
+ severity,
32
+ phase,
33
+ isRecoverable,
34
+ message,
35
+ component,
36
+ context = {},
37
+ stack = null,
38
+ recoveryAction = null,
39
+ impact = null
40
+ } = params;
41
+
42
+ const failure = {
43
+ code,
44
+ category,
45
+ severity,
46
+ phase,
47
+ isRecoverable,
48
+ message,
49
+ component,
50
+ timestamp: Date.now(),
51
+ context,
52
+ ...(stack && { stack }),
53
+ ...(recoveryAction && { recoveryAction }),
54
+ ...(impact && { impact })
55
+ };
56
+
57
+ validateFailure(failure);
58
+ return failure;
59
+ }
60
+
61
+ /**
62
+ * Create evidence law failure
63
+ */
64
+ export function createEvidenceFailure(code, message, component, context = {}) {
65
+ return createFailure({
66
+ code,
67
+ category: FAILURE_CATEGORY.EVIDENCE,
68
+ severity: FAILURE_SEVERITY.BLOCKING,
69
+ phase: EXECUTION_PHASE.DETECT,
70
+ isRecoverable: false,
71
+ message,
72
+ component,
73
+ context,
74
+ impact: 'Cannot produce CONFIRMED findings without complete evidence'
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Create determinism failure
80
+ */
81
+ export function createDeterminismFailure(code, message, component, context = {}) {
82
+ return createFailure({
83
+ code,
84
+ category: FAILURE_CATEGORY.DETERMINISM,
85
+ severity: FAILURE_SEVERITY.DEGRADED,
86
+ phase: EXECUTION_PHASE.OBSERVE,
87
+ isRecoverable: false,
88
+ message,
89
+ component,
90
+ context,
91
+ impact: 'Determinism verdict downgraded to NON_DETERMINISTIC'
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Create observation failure
97
+ */
98
+ export function createObserveFailure(code, message, component, context = {}, isRecoverable = false) {
99
+ return createFailure({
100
+ code,
101
+ category: FAILURE_CATEGORY.OBSERVE,
102
+ severity: isRecoverable ? FAILURE_SEVERITY.DEGRADED : FAILURE_SEVERITY.BLOCKING,
103
+ phase: EXECUTION_PHASE.OBSERVE,
104
+ isRecoverable,
105
+ message,
106
+ component,
107
+ context
108
+ });
109
+ }
110
+
111
+ /**
112
+ * Create detection failure
113
+ */
114
+ export function createDetectFailure(code, message, component, context = {}, isRecoverable = false) {
115
+ return createFailure({
116
+ code,
117
+ category: FAILURE_CATEGORY.DETECT,
118
+ severity: isRecoverable ? FAILURE_SEVERITY.DEGRADED : FAILURE_SEVERITY.BLOCKING,
119
+ phase: EXECUTION_PHASE.DETECT,
120
+ isRecoverable,
121
+ message,
122
+ component,
123
+ context
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Create I/O failure
129
+ */
130
+ export function createIOFailure(code, message, component, context = {}, isRecoverable = false) {
131
+ return createFailure({
132
+ code,
133
+ category: FAILURE_CATEGORY.IO,
134
+ severity: isRecoverable ? FAILURE_SEVERITY.WARNING : FAILURE_SEVERITY.BLOCKING,
135
+ phase: EXECUTION_PHASE.REPORT,
136
+ isRecoverable,
137
+ message,
138
+ component,
139
+ context
140
+ });
141
+ }
142
+
143
+ /**
144
+ * Create policy failure
145
+ */
146
+ export function createPolicyFailure(code, message, component, context = {}) {
147
+ return createFailure({
148
+ code,
149
+ category: FAILURE_CATEGORY.POLICY,
150
+ severity: FAILURE_SEVERITY.BLOCKING,
151
+ phase: EXECUTION_PHASE.DETECT,
152
+ isRecoverable: false,
153
+ message,
154
+ component,
155
+ context,
156
+ impact: 'Invalid policy prevents execution'
157
+ });
158
+ }
159
+
160
+ /**
161
+ * Create contract failure
162
+ */
163
+ export function createContractFailure(code, message, component, context = {}, stack = null) {
164
+ return createFailure({
165
+ code,
166
+ category: FAILURE_CATEGORY.CONTRACT,
167
+ severity: FAILURE_SEVERITY.BLOCKING,
168
+ phase: EXECUTION_PHASE.DETECT,
169
+ isRecoverable: false,
170
+ message,
171
+ component,
172
+ context,
173
+ stack,
174
+ impact: 'Invariant violation - system integrity compromised'
175
+ });
176
+ }
177
+
178
+ /**
179
+ * Create internal failure
180
+ */
181
+ export function createInternalFailure(code, message, component, context = {}, stack = null) {
182
+ return createFailure({
183
+ code,
184
+ category: FAILURE_CATEGORY.INTERNAL,
185
+ severity: FAILURE_SEVERITY.BLOCKING,
186
+ phase: EXECUTION_PHASE.DETECT,
187
+ isRecoverable: false,
188
+ message,
189
+ component,
190
+ context,
191
+ stack,
192
+ impact: 'Internal error - system state may be corrupted'
193
+ });
194
+ }
195
+
196
+ /**
197
+ * Convert error to failure
198
+ *
199
+ * @param {Error} error - JavaScript error
200
+ * @param {string} code - Failure code
201
+ * @param {string} category - Failure category
202
+ * @param {string} phase - Execution phase
203
+ * @param {string} component - Component name
204
+ * @param {Object} context - Additional context
205
+ * @returns {Object} Failure object
206
+ */
207
+ export function errorToFailure(error, code, category, phase, component, context = {}) {
208
+ return createFailure({
209
+ code,
210
+ category,
211
+ severity: FAILURE_SEVERITY.BLOCKING,
212
+ phase,
213
+ isRecoverable: false,
214
+ message: error.message || 'Unexpected error',
215
+ component,
216
+ context: {
217
+ ...context,
218
+ errorName: error.name,
219
+ errorType: error.constructor?.name
220
+ },
221
+ stack: error.stack || null,
222
+ impact: 'Unexpected error - execution may be incomplete'
223
+ });
224
+ }
225
+
@@ -0,0 +1,133 @@
1
+ /**
2
+ * PHASE 21.5 — Failure Ledger
3
+ *
4
+ * Enterprise artifact that records all failures (even recovered ones).
5
+ * Deterministic, append-only, never missing.
6
+ */
7
+
8
+ import { writeFileSync, mkdirSync } from 'fs';
9
+ import { resolve, dirname as _dirname } from 'path';
10
+ import { validateFailure } from './failure.types.js';
11
+
12
+ /**
13
+ * Failure Ledger
14
+ *
15
+ * Maintains an ordered list of all failures during execution.
16
+ */
17
+ export class FailureLedger {
18
+ constructor(runId, projectDir) {
19
+ this.runId = runId;
20
+ this.projectDir = projectDir;
21
+ this.failures = [];
22
+ this.startTime = Date.now();
23
+ }
24
+
25
+ /**
26
+ * Record a failure
27
+ *
28
+ * @param {Object} failure - Failure object
29
+ * @ts-expect-error - Failure type not imported
30
+ */
31
+ record(failure) {
32
+ validateFailure(failure);
33
+
34
+ // Add sequence number for deterministic ordering
35
+ const sequencedFailure = {
36
+ ...failure,
37
+ sequence: this.failures.length,
38
+ relativeTime: Date.now() - this.startTime
39
+ };
40
+
41
+ this.failures.push(sequencedFailure);
42
+ }
43
+
44
+ /**
45
+ * Get failure summary
46
+ *
47
+ * @returns {Object} Summary with counts by severity
48
+ */
49
+ getSummary() {
50
+ const summary = {
51
+ total: this.failures.length,
52
+ bySeverity: {
53
+ BLOCKING: 0,
54
+ DEGRADED: 0,
55
+ WARNING: 0
56
+ },
57
+ byCategory: {},
58
+ byPhase: {},
59
+ highestSeverity: null
60
+ };
61
+
62
+ for (const failure of this.failures) {
63
+ summary.bySeverity[failure.severity] = (summary.bySeverity[failure.severity] || 0) + 1;
64
+ summary.byCategory[failure.category] = (summary.byCategory[failure.category] || 0) + 1;
65
+ summary.byPhase[failure.phase] = (summary.byPhase[failure.phase] || 0) + 1;
66
+ }
67
+
68
+ // Determine highest severity
69
+ if (summary.bySeverity.BLOCKING > 0) {
70
+ summary.highestSeverity = 'BLOCKING';
71
+ } else if (summary.bySeverity.DEGRADED > 0) {
72
+ summary.highestSeverity = 'DEGRADED';
73
+ } else if (summary.bySeverity.WARNING > 0) {
74
+ summary.highestSeverity = 'WARNING';
75
+ }
76
+
77
+ return summary;
78
+ }
79
+
80
+ /**
81
+ * Get highest severity for exit code determination
82
+ *
83
+ * @returns {string|null} Highest severity or null if no failures
84
+ */
85
+ getHighestSeverity() {
86
+ const summary = this.getSummary();
87
+ return summary.highestSeverity;
88
+ }
89
+
90
+ /**
91
+ * Write ledger to file
92
+ *
93
+ * @returns {string} Path to ledger file
94
+ */
95
+ write() {
96
+ if (!this.runId || !this.projectDir) {
97
+ throw new Error('Cannot write failure ledger: runId and projectDir required');
98
+ }
99
+
100
+ const runsDir = resolve(this.projectDir, '.verax', 'runs', this.runId);
101
+ mkdirSync(runsDir, { recursive: true });
102
+
103
+ const ledgerPath = resolve(runsDir, 'failure.ledger.json');
104
+
105
+ const ledgerData = {
106
+ runId: this.runId,
107
+ startTime: this.startTime,
108
+ endTime: Date.now(),
109
+ duration: Date.now() - this.startTime,
110
+ summary: this.getSummary(),
111
+ failures: this.failures
112
+ };
113
+
114
+ writeFileSync(ledgerPath, JSON.stringify(ledgerData, null, 2), 'utf-8');
115
+
116
+ return ledgerPath;
117
+ }
118
+
119
+ /**
120
+ * Export ledger data (for testing)
121
+ *
122
+ * @returns {Object} Ledger data
123
+ */
124
+ export() {
125
+ return {
126
+ runId: this.runId,
127
+ startTime: this.startTime,
128
+ summary: this.getSummary(),
129
+ failures: this.failures
130
+ };
131
+ }
132
+ }
133
+