@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,190 @@
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 } 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
+ * @returns {Object} - { mode, ceiling, explanation }
43
+ */
44
+ export function detectExecutionMode(srcPath, url) {
45
+ // Check if source code is available and viable
46
+ const hasSourceCode = isSourceCodeAvailable(srcPath);
47
+
48
+ if (hasSourceCode) {
49
+ return {
50
+ mode: EXECUTION_MODES.PROJECT_SCAN,
51
+ ceiling: CONFIDENCE_CEILINGS[EXECUTION_MODES.PROJECT_SCAN],
52
+ explanation: 'Full project analysis: source code is available for static analysis, expectations extraction, and dynamic behavior correlation.',
53
+ reason: 'Source code detected at ' + srcPath
54
+ };
55
+ } else {
56
+ return {
57
+ mode: EXECUTION_MODES.WEB_SCAN_LIMITED,
58
+ ceiling: CONFIDENCE_CEILINGS[EXECUTION_MODES.WEB_SCAN_LIMITED],
59
+ 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.',
60
+ reason: 'No source code available; analyzing runtime behavior only'
61
+ };
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Check if source code is available and viable for analysis
67
+ * @param {string} srcPath - Path to source code directory
68
+ * @returns {boolean} - True if source code appears to be available
69
+ */
70
+ function isSourceCodeAvailable(srcPath) {
71
+ // Check if path exists
72
+ if (!existsSync(srcPath)) {
73
+ return false;
74
+ }
75
+
76
+ // Check if it's a directory
77
+ try {
78
+ const stats = statSync(srcPath);
79
+ if (!stats.isDirectory()) {
80
+ return false;
81
+ }
82
+ } catch {
83
+ return false;
84
+ }
85
+
86
+ // Check for minimum viable source indicators
87
+ return hasSourceIndicators(srcPath);
88
+ }
89
+
90
+ /**
91
+ * Check for presence of source code indicators
92
+ * @param {string} srcPath - Path to potential source directory
93
+ * @returns {boolean} - True if source indicators are present
94
+ */
95
+ function hasSourceIndicators(srcPath) {
96
+ try {
97
+ const entries = readdirSync(srcPath, { withFileTypes: true });
98
+
99
+ // Look for common source code patterns
100
+ const indicators = {
101
+ hasJs: false, // .js, .jsx, .ts, .tsx files
102
+ hasSrc: false, // src/ directory
103
+ hasPackageJson: false,
104
+ hasPythonFiles: false,
105
+ hasGoFiles: false
106
+ };
107
+
108
+ for (const entry of entries) {
109
+ const name = entry.name;
110
+ const lowerName = name.toLowerCase();
111
+
112
+ // Check for source directories
113
+ if (entry.isDirectory() &&
114
+ (lowerName === 'src' || lowerName === 'lib' || lowerName === 'app' ||
115
+ lowerName === 'pages' || lowerName === 'components' || lowerName === 'python')) {
116
+ indicators.hasSrc = true;
117
+ }
118
+
119
+ // Check for package.json (Node.js projects)
120
+ if (name === 'package.json') {
121
+ indicators.hasPackageJson = true;
122
+ }
123
+
124
+ // Check for JS/TS files
125
+ if (lowerName.endsWith('.js') || lowerName.endsWith('.jsx') ||
126
+ lowerName.endsWith('.ts') || lowerName.endsWith('.tsx') ||
127
+ lowerName.endsWith('.mjs') || lowerName.endsWith('.cjs')) {
128
+ indicators.hasJs = true;
129
+ }
130
+
131
+ // Check for Python files
132
+ if (lowerName.endsWith('.py')) {
133
+ indicators.hasPythonFiles = true;
134
+ }
135
+
136
+ // Check for Go files
137
+ if (lowerName.endsWith('.go')) {
138
+ indicators.hasGoFiles = true;
139
+ }
140
+ }
141
+
142
+ // Multiple indicators needed to confirm source code is present
143
+ const indicatorCount = Object.values(indicators).filter(Boolean).length;
144
+ return indicatorCount >= 2; // Need at least 2 indicators
145
+
146
+ } catch (error) {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Apply confidence ceiling to a score
153
+ * @param {number} score - Confidence score (0..1 float)
154
+ * @param {string} mode - Execution mode
155
+ * @returns {number} - Capped confidence score (0..1 float)
156
+ */
157
+ export function applyConfidenceCeiling(score, mode) {
158
+ const ceiling = CONFIDENCE_CEILINGS[mode] || 1.0;
159
+ return Math.min(score, ceiling);
160
+ }
161
+
162
+ /**
163
+ * Generate execution mode explanation for output
164
+ * @param {string} mode - Execution mode
165
+ * @param {string} ceiling - Confidence ceiling
166
+ * @returns {string} - Human-readable explanation
167
+ */
168
+ export function generateModeExplanation(mode, ceiling) {
169
+ switch (mode) {
170
+ case EXECUTION_MODES.PROJECT_SCAN:
171
+ return `Running in PROJECT_SCAN mode. Full analysis enabled with source code available.`;
172
+
173
+ case EXECUTION_MODES.WEB_SCAN_LIMITED:
174
+ return `Running in WEB_SCAN_LIMITED mode. No source code available; analysis limited to runtime observation. Confidence capped at ${Math.round(ceiling * 100)}%.`;
175
+
176
+ default:
177
+ return 'Execution mode unknown.';
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Format execution mode info for CLI output
183
+ * @param {Object} modeInfo - Result from detectExecutionMode()
184
+ * @returns {string} - Formatted text for console output
185
+ */
186
+ export function formatModeForOutput(modeInfo) {
187
+ return `Execution Mode: ${modeInfo.mode}
188
+ Confidence Ceiling: ${Math.round(modeInfo.ceiling * 100)}%
189
+ Reason: ${modeInfo.reason}`;
190
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * PHASE 21.5 — Exit Code Contract
3
+ *
4
+ * Enterprise-grade exit code mapping based on failure ledger.
5
+ * Exit codes must match failure severity and system state.
6
+ */
7
+
8
+ import { FAILURE_SEVERITY } from './failure.types.js';
9
+
10
+ /**
11
+ * Exit Code Meanings
12
+ */
13
+ export const EXIT_CODE = {
14
+ CLEAN: 0, // Clean run, no failures
15
+ WARNINGS: 1, // Warnings only
16
+ DEGRADED: 2, // DEGRADED run (truth preserved, partial capability loss)
17
+ BLOCKING: 3, // BLOCKING failure (truth incomplete)
18
+ INVALID_INPUT: 64, // Invalid input / policy
19
+ INTERNAL_CORRUPTION: 70 // Internal corruption / invariant violation
20
+ };
21
+
22
+ /**
23
+ * Determine exit code from failure ledger
24
+ *
25
+ * @param {Object} ledgerSummary - Failure ledger summary
26
+ * @param {string} determinismVerdict - Determinism verdict (DETERMINISTIC | NON_DETERMINISTIC)
27
+ * @param {boolean} evidenceLawViolated - Whether Evidence Law was violated
28
+ * @param {boolean} policyInvalid - Whether policy was invalid
29
+ * @returns {number} Exit code
30
+ */
31
+ export function determineExitCode(ledgerSummary, determinismVerdict = null, evidenceLawViolated = false, policyInvalid = false) {
32
+ // Policy invalid → 64
33
+ if (policyInvalid) {
34
+ return EXIT_CODE.INVALID_INPUT;
35
+ }
36
+
37
+ // Internal corruption → 70
38
+ const hasInternalCorruption = ledgerSummary.byCategory?.INTERNAL > 0 ||
39
+ ledgerSummary.byCategory?.CONTRACT > 0;
40
+ if (hasInternalCorruption) {
41
+ return EXIT_CODE.INTERNAL_CORRUPTION;
42
+ }
43
+
44
+ // BLOCKING failures → 3
45
+ if (ledgerSummary.bySeverity?.BLOCKING > 0) {
46
+ return EXIT_CODE.BLOCKING;
47
+ }
48
+
49
+ // DEGRADED failures → 2
50
+ if (ledgerSummary.bySeverity?.DEGRADED > 0) {
51
+ return EXIT_CODE.DEGRADED;
52
+ }
53
+
54
+ // WARNING only → 1
55
+ if (ledgerSummary.bySeverity?.WARNING > 0) {
56
+ return EXIT_CODE.WARNINGS;
57
+ }
58
+
59
+ // Evidence Law violation → 3 (BLOCKING)
60
+ if (evidenceLawViolated) {
61
+ return EXIT_CODE.BLOCKING;
62
+ }
63
+
64
+ // Clean run → 0
65
+ return EXIT_CODE.CLEAN;
66
+ }
67
+
68
+ /**
69
+ * Get exit code meaning
70
+ *
71
+ * @param {number} exitCode - Exit code
72
+ * @returns {string} Human-readable meaning
73
+ */
74
+ export function getExitCodeMeaning(exitCode) {
75
+ const meanings = {
76
+ [EXIT_CODE.CLEAN]: 'Clean run, no failures',
77
+ [EXIT_CODE.WARNINGS]: 'Warnings only',
78
+ [EXIT_CODE.DEGRADED]: 'DEGRADED run (truth preserved, partial capability loss)',
79
+ [EXIT_CODE.BLOCKING]: 'BLOCKING failure (truth incomplete)',
80
+ [EXIT_CODE.INVALID_INPUT]: 'Invalid input / policy',
81
+ [EXIT_CODE.INTERNAL_CORRUPTION]: 'Internal corruption / invariant violation'
82
+ };
83
+
84
+ return meanings[exitCode] || `Unknown exit code: ${exitCode}`;
85
+ }
86
+
@@ -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 } 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, 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 {Failure} 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 {Failure} 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,132 @@
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 } 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 {Failure} failure - Failure object
29
+ */
30
+ record(failure) {
31
+ validateFailure(failure);
32
+
33
+ // Add sequence number for deterministic ordering
34
+ const sequencedFailure = {
35
+ ...failure,
36
+ sequence: this.failures.length,
37
+ relativeTime: Date.now() - this.startTime
38
+ };
39
+
40
+ this.failures.push(sequencedFailure);
41
+ }
42
+
43
+ /**
44
+ * Get failure summary
45
+ *
46
+ * @returns {Object} Summary with counts by severity
47
+ */
48
+ getSummary() {
49
+ const summary = {
50
+ total: this.failures.length,
51
+ bySeverity: {
52
+ BLOCKING: 0,
53
+ DEGRADED: 0,
54
+ WARNING: 0
55
+ },
56
+ byCategory: {},
57
+ byPhase: {},
58
+ highestSeverity: null
59
+ };
60
+
61
+ for (const failure of this.failures) {
62
+ summary.bySeverity[failure.severity] = (summary.bySeverity[failure.severity] || 0) + 1;
63
+ summary.byCategory[failure.category] = (summary.byCategory[failure.category] || 0) + 1;
64
+ summary.byPhase[failure.phase] = (summary.byPhase[failure.phase] || 0) + 1;
65
+ }
66
+
67
+ // Determine highest severity
68
+ if (summary.bySeverity.BLOCKING > 0) {
69
+ summary.highestSeverity = 'BLOCKING';
70
+ } else if (summary.bySeverity.DEGRADED > 0) {
71
+ summary.highestSeverity = 'DEGRADED';
72
+ } else if (summary.bySeverity.WARNING > 0) {
73
+ summary.highestSeverity = 'WARNING';
74
+ }
75
+
76
+ return summary;
77
+ }
78
+
79
+ /**
80
+ * Get highest severity for exit code determination
81
+ *
82
+ * @returns {string|null} Highest severity or null if no failures
83
+ */
84
+ getHighestSeverity() {
85
+ const summary = this.getSummary();
86
+ return summary.highestSeverity;
87
+ }
88
+
89
+ /**
90
+ * Write ledger to file
91
+ *
92
+ * @returns {string} Path to ledger file
93
+ */
94
+ write() {
95
+ if (!this.runId || !this.projectDir) {
96
+ throw new Error('Cannot write failure ledger: runId and projectDir required');
97
+ }
98
+
99
+ const runsDir = resolve(this.projectDir, '.verax', 'runs', this.runId);
100
+ mkdirSync(runsDir, { recursive: true });
101
+
102
+ const ledgerPath = resolve(runsDir, 'failure.ledger.json');
103
+
104
+ const ledgerData = {
105
+ runId: this.runId,
106
+ startTime: this.startTime,
107
+ endTime: Date.now(),
108
+ duration: Date.now() - this.startTime,
109
+ summary: this.getSummary(),
110
+ failures: this.failures
111
+ };
112
+
113
+ writeFileSync(ledgerPath, JSON.stringify(ledgerData, null, 2), 'utf-8');
114
+
115
+ return ledgerPath;
116
+ }
117
+
118
+ /**
119
+ * Export ledger data (for testing)
120
+ *
121
+ * @returns {Object} Ledger data
122
+ */
123
+ export() {
124
+ return {
125
+ runId: this.runId,
126
+ startTime: this.startTime,
127
+ summary: this.getSummary(),
128
+ failures: this.failures
129
+ };
130
+ }
131
+ }
132
+