@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,162 @@
1
+ /**
2
+ * PHASE 20 — Vue SFC (Single File Component) Extractor
3
+ *
4
+ * Extracts <script>, <script setup>, and <template> content from .vue files.
5
+ * Deterministic and robust (no external runtime execution).
6
+ */
7
+
8
+ /**
9
+ * PHASE 20: Extract Vue SFC blocks
10
+ *
11
+ * @param {string} content - Full .vue file content
12
+ * @param {string} filePath - Path to the .vue file (for context)
13
+ * @returns {Object} { scriptBlocks: [{content, lang, startLine}], template: {content, startLine} }
14
+ */
15
+ export function extractVueSFC(content) {
16
+ const scriptBlocks = [];
17
+ let template = null;
18
+
19
+ // Extract <script> blocks (including <script setup>)
20
+ const scriptRegex = /<script(?:\s+setup)?(?:\s+lang=["']([^"']+)["'])?[^>]*>([\s\S]*?)<\/script>/gi;
21
+ let scriptMatch;
22
+ let lineOffset = 1;
23
+
24
+ while ((scriptMatch = scriptRegex.exec(content)) !== null) {
25
+ const isSetup = scriptMatch[0].includes('setup');
26
+ const lang = scriptMatch[1] || 'js';
27
+ const scriptContent = scriptMatch[2];
28
+
29
+ // Calculate start line
30
+ const beforeMatch = content.substring(0, scriptMatch.index);
31
+ const startLine = (beforeMatch.match(/\n/g) || []).length + 1;
32
+
33
+ scriptBlocks.push({
34
+ content: scriptContent.trim(),
35
+ lang: lang.toLowerCase(),
36
+ startLine,
37
+ isSetup,
38
+ });
39
+ }
40
+
41
+ // Extract <template> block
42
+ const templateRegex = /<template[^>]*>([\s\S]*?)<\/template>/i;
43
+ const templateMatch = content.match(templateRegex);
44
+
45
+ if (templateMatch) {
46
+ const beforeTemplate = content.substring(0, templateMatch.index);
47
+ const templateStartLine = (beforeTemplate.match(/\n/g) || []).length + 1;
48
+
49
+ template = {
50
+ content: templateMatch[1].trim(),
51
+ startLine: templateStartLine,
52
+ };
53
+ }
54
+
55
+ return {
56
+ scriptBlocks,
57
+ template,
58
+ };
59
+ }
60
+
61
+ /**
62
+ * PHASE 20: Extract template bindings and references
63
+ *
64
+ * @param {string} templateContent - Template content
65
+ * @returns {Object} { bindings: string[], routerLinks: Array, eventHandlers: Array }
66
+ */
67
+ export function extractTemplateBindings(templateContent) {
68
+ const bindings = [];
69
+ const routerLinks = [];
70
+ const eventHandlers = [];
71
+
72
+ // Extract variable bindings: {{ var }}, :prop="var", v-if="var", etc.
73
+ const bindingPatterns = [
74
+ /\{\{\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\}\}/g, // {{ var }}
75
+ /:([a-zA-Z-]+)=["']([^"']+)["']/g, // :prop="value"
76
+ /v-if=["']([^"']+)["']/g, // v-if="condition"
77
+ /v-show=["']([^"']+)["']/g, // v-show="condition"
78
+ /v-model=["']([^"']+)["']/g, // v-model="value"
79
+ ];
80
+
81
+ for (const pattern of bindingPatterns) {
82
+ let match;
83
+ while ((match = pattern.exec(templateContent)) !== null) {
84
+ const binding = match[1] || match[2];
85
+ if (binding && !bindings.includes(binding)) {
86
+ bindings.push(binding);
87
+ }
88
+ }
89
+ }
90
+
91
+ // Extract <router-link> usage
92
+ const routerLinkRegex = /<router-link[^>]*\s+to=["']([^"']+)["'][^>]*>/gi;
93
+ let routerLinkMatch;
94
+ while ((routerLinkMatch = routerLinkRegex.exec(templateContent)) !== null) {
95
+ routerLinks.push({
96
+ to: routerLinkMatch[1],
97
+ fullMatch: routerLinkMatch[0],
98
+ });
99
+ }
100
+
101
+ // Extract event handlers: @click="handler", @submit.prevent="handler"
102
+ const eventHandlerRegex = /@([a-z]+)(?:\.([a-z]+)*)?=["']([^"']+)["']/gi;
103
+ let eventMatch;
104
+ while ((eventMatch = eventHandlerRegex.exec(templateContent)) !== null) {
105
+ eventHandlers.push({
106
+ event: eventMatch[1],
107
+ modifiers: eventMatch[2] ? eventMatch[2].split('.') : [],
108
+ handler: eventMatch[3],
109
+ });
110
+ }
111
+
112
+ return {
113
+ bindings,
114
+ routerLinks,
115
+ eventHandlers,
116
+ };
117
+ }
118
+
119
+ /**
120
+ * PHASE 20: Map template handlers to script functions
121
+ *
122
+ * @param {Object} templateBindings - Result from extractTemplateBindings
123
+ * @param {Array} scriptBlocks - Script blocks from extractVueSFC
124
+ * @returns {Map} handlerName -> { scriptBlock, functionInfo }
125
+ */
126
+ export function mapTemplateHandlersToScript(templateBindings, scriptBlocks) {
127
+ const handlerMap = new Map();
128
+
129
+ for (const handler of templateBindings.eventHandlers) {
130
+ const handlerName = handler.handler;
131
+
132
+ // Find handler in script blocks
133
+ for (const scriptBlock of scriptBlocks) {
134
+ const scriptContent = scriptBlock.content;
135
+
136
+ // Look for function declarations: function handlerName() {}
137
+ const functionRegex = new RegExp(`(?:function|const|let|var)\\s+${handlerName}\\s*[=(]`, 'g');
138
+ if (functionRegex.test(scriptContent)) {
139
+ handlerMap.set(handlerName, {
140
+ scriptBlock,
141
+ handler,
142
+ type: 'function',
143
+ });
144
+ break;
145
+ }
146
+
147
+ // Look for method definitions: methods: { handlerName() {} }
148
+ const methodRegex = new RegExp(`(?:methods|setup)\\s*:\\s*\\{[^}]*${handlerName}\\s*[:(]`, 's');
149
+ if (methodRegex.test(scriptContent)) {
150
+ handlerMap.set(handlerName, {
151
+ scriptBlock,
152
+ handler,
153
+ type: 'method',
154
+ });
155
+ break;
156
+ }
157
+ }
158
+ }
159
+
160
+ return handlerMap;
161
+ }
162
+
@@ -0,0 +1,215 @@
1
+ /**
2
+ * PHASE 20 — Vue State Promise Detection
3
+ *
4
+ * Detects ref/reactive mutations that are UI-bound:
5
+ * - ref declarations: const count = ref(0);
6
+ * - reactive: const state = reactive({ x: 1 });
7
+ * - Only emit if identifiers are used in template bindings
8
+ */
9
+
10
+ import { parse } from '@babel/parser';
11
+ import _traverse from '@babel/traverse';
12
+
13
+ const traverse = _traverse.default || _traverse;
14
+
15
+ /**
16
+ * PHASE 20: Detect Vue state promises
17
+ *
18
+ * @param {string} scriptContent - Script block content
19
+ * @param {string} filePath - File path
20
+ * @param {string} relPath - Relative path
21
+ * @param {Object} scriptBlock - Script block metadata
22
+ * @param {Object} templateBindings - Template bindings
23
+ * @returns {Array} State promises
24
+ */
25
+ export function detectVueStatePromises(scriptContent, filePath, relPath, scriptBlock, templateBindings) {
26
+ const promises = [];
27
+ const templateVars = new Set(templateBindings.bindings || []);
28
+
29
+ if (templateVars.size === 0) {
30
+ return promises; // No template bindings, skip
31
+ }
32
+
33
+ try {
34
+ const ast = parse(scriptContent, {
35
+ sourceType: 'module',
36
+ plugins: [
37
+ 'typescript',
38
+ 'classProperties',
39
+ 'optionalChaining',
40
+ 'nullishCoalescingOperator',
41
+ 'dynamicImport',
42
+ 'topLevelAwait',
43
+ 'objectRestSpread',
44
+ ],
45
+ errorRecovery: true,
46
+ });
47
+
48
+ const lines = scriptContent.split('\n');
49
+ const refDeclarations = new Map(); // varName -> { loc, astSource }
50
+ const reactiveDeclarations = new Map();
51
+
52
+ traverse(ast, {
53
+ // Detect ref() declarations
54
+ VariableDeclarator(path) {
55
+ const node = path.node;
56
+ const init = node.init;
57
+
58
+ if (init && init.type === 'CallExpression') {
59
+ const callee = init.callee;
60
+
61
+ // ref(0) or ref({})
62
+ if (callee.type === 'Identifier' && callee.name === 'ref') {
63
+ const varName = node.id.name;
64
+ if (templateVars.has(varName)) {
65
+ const loc = node.loc;
66
+ const line = loc ? loc.start.line : 1;
67
+ const astSource = lines.slice(line - 1, loc ? loc.end.line : line)
68
+ .join('\n')
69
+ .substring(0, 200);
70
+
71
+ refDeclarations.set(varName, {
72
+ loc,
73
+ astSource,
74
+ line,
75
+ });
76
+ }
77
+ }
78
+
79
+ // reactive({})
80
+ if (callee.type === 'Identifier' && callee.name === 'reactive') {
81
+ const varName = node.id.name;
82
+ if (templateVars.has(varName)) {
83
+ const loc = node.loc;
84
+ const line = loc ? loc.start.line : 1;
85
+ const astSource = lines.slice(line - 1, loc ? loc.end.line : line)
86
+ .join('\n')
87
+ .substring(0, 200);
88
+
89
+ reactiveDeclarations.set(varName, {
90
+ loc,
91
+ astSource,
92
+ line,
93
+ });
94
+ }
95
+ }
96
+ }
97
+ },
98
+
99
+ // Detect mutations: count.value = ... or state.x = ...
100
+ AssignmentExpression(path) {
101
+ const node = path.node;
102
+ const left = node.left;
103
+
104
+ // count.value = ...
105
+ if (left.type === 'MemberExpression' &&
106
+ left.property.name === 'value' &&
107
+ left.object.type === 'Identifier') {
108
+ const varName = left.object.name;
109
+
110
+ if (refDeclarations.has(varName) && templateVars.has(varName)) {
111
+ const decl = refDeclarations.get(varName);
112
+ const loc = node.loc;
113
+ const line = loc ? loc.start.line : 1;
114
+ const column = loc ? loc.start.column : 0;
115
+
116
+ const astSource = lines.slice(line - 1, loc ? loc.end.line : line)
117
+ .join('\n')
118
+ .substring(0, 200);
119
+
120
+ const context = buildContext(path);
121
+
122
+ promises.push({
123
+ type: 'state',
124
+ promise: {
125
+ kind: 'state-change',
126
+ value: `${varName}.value`,
127
+ stateVar: varName,
128
+ },
129
+ source: {
130
+ file: relPath,
131
+ line,
132
+ column,
133
+ context,
134
+ astSource,
135
+ },
136
+ confidence: 0.9,
137
+ });
138
+ }
139
+ }
140
+
141
+ // state.x = ...
142
+ if (left.type === 'MemberExpression' &&
143
+ left.object.type === 'Identifier') {
144
+ const varName = left.object.name;
145
+
146
+ if (reactiveDeclarations.has(varName) && templateVars.has(varName)) {
147
+ const loc = node.loc;
148
+ const line = loc ? loc.start.line : 1;
149
+ const column = loc ? loc.start.column : 0;
150
+
151
+ const astSource = lines.slice(line - 1, loc ? loc.end.line : line)
152
+ .join('\n')
153
+ .substring(0, 200);
154
+
155
+ const context = buildContext(path);
156
+ const propName = left.property.name || '<property>';
157
+
158
+ promises.push({
159
+ type: 'state',
160
+ promise: {
161
+ kind: 'state-change',
162
+ value: `${varName}.${propName}`,
163
+ stateVar: varName,
164
+ },
165
+ source: {
166
+ file: relPath,
167
+ line,
168
+ column,
169
+ context,
170
+ astSource,
171
+ },
172
+ confidence: 0.9,
173
+ });
174
+ }
175
+ }
176
+ },
177
+ });
178
+ } catch (error) {
179
+ // Parse error - skip
180
+ }
181
+
182
+ return promises;
183
+ }
184
+
185
+ /**
186
+ * Build context chain from AST path
187
+ */
188
+ function buildContext(path) {
189
+ const context = [];
190
+ let current = path;
191
+
192
+ while (current) {
193
+ if (current.isFunctionDeclaration()) {
194
+ context.push({
195
+ type: 'function',
196
+ name: current.node.id?.name || '<anonymous>',
197
+ });
198
+ } else if (current.isArrowFunctionExpression()) {
199
+ context.push({
200
+ type: 'arrow-function',
201
+ name: '<arrow>',
202
+ });
203
+ } else if (current.isMethodDefinition()) {
204
+ context.push({
205
+ type: 'method',
206
+ name: current.node.key?.name || '<method>',
207
+ });
208
+ }
209
+
210
+ current = current.parentPath;
211
+ }
212
+
213
+ return context.reverse().map(c => `${c.type}:${c.name}`).join(' > ');
214
+ }
215
+
@@ -14,11 +14,22 @@
14
14
  export function formatFinding(finding, expectation = null) {
15
15
  const lines = [];
16
16
 
17
- // Finding type and confidence
18
- const confidenceLevel = finding.confidence?.level || 'UNKNOWN';
19
- const confidenceScore = finding.confidence?.score || 0;
17
+ // PHASE 15: Finding type and unified confidence
18
+ const confidenceLevel = finding.confidenceLevel || finding.confidence?.level || 'UNPROVEN';
19
+ const confidenceScore = finding.confidence !== undefined
20
+ ? (finding.confidence <= 1 ? Math.round(finding.confidence * 100) : finding.confidence)
21
+ : (finding.confidence?.score || 0);
22
+ const confidenceReasons = finding.confidenceReasons || [];
23
+
20
24
  lines.push(` [${confidenceLevel} (${confidenceScore}%)] ${finding.type || 'unknown'}`);
21
25
 
26
+ // PHASE 15: Show top confidence reasons
27
+ if (confidenceReasons.length > 0) {
28
+ const topReasons = confidenceReasons.slice(0, 3);
29
+ const reasonText = topReasons.join(', ');
30
+ lines.push(` └─ Confidence: ${reasonText}`);
31
+ }
32
+
22
33
  // Expectation (what was promised)
23
34
  if (expectation) {
24
35
  let expectationDesc = '';
@@ -84,6 +95,48 @@ export function formatFinding(finding, expectation = null) {
84
95
  lines.push(` └─ Source: ${expectation.source.file}${sourceLine}`);
85
96
  }
86
97
 
98
+ // PHASE 16: Show evidence completeness
99
+ if (finding.evidencePackage) {
100
+ if (finding.evidencePackage.isComplete) {
101
+ lines.push(` └─ Evidence: Complete`);
102
+ } else {
103
+ lines.push(` └─ Evidence: Incomplete (missing: ${finding.evidencePackage.missingEvidence.join(', ')})`);
104
+ }
105
+ }
106
+
107
+ // PHASE 16: Show downgrade reason if evidence was incomplete
108
+ if (finding.evidenceCompleteness?.downgraded) {
109
+ lines.push(` └─ Downgraded: ${finding.evidenceCompleteness.downgradeReason}`);
110
+ }
111
+
112
+ // PHASE 17/23: Show guardrails applied and reconciliation
113
+ if (finding.guardrails) {
114
+ const guardrails = finding.guardrails;
115
+ if (guardrails.appliedRules && guardrails.appliedRules.length > 0) {
116
+ const ruleCodes = guardrails.appliedRules.map(r => r.code || r.ruleId).filter(Boolean);
117
+ if (ruleCodes.length > 0) {
118
+ lines.push(` └─ Final status due to guardrails: ${ruleCodes.join(', ')}`);
119
+ }
120
+ }
121
+ if (guardrails.contradictions && guardrails.contradictions.length > 0) {
122
+ lines.push(` └─ Contradiction: ${guardrails.contradictions[0].message}`);
123
+ }
124
+
125
+ // PHASE 23: Show confidence reconciliation if present
126
+ if (guardrails.reconciliation) {
127
+ const recon = guardrails.reconciliation;
128
+ if (recon.confidenceBefore !== recon.confidenceAfter) {
129
+ const beforePercent = Math.round(recon.confidenceBefore * 100);
130
+ const afterPercent = Math.round(recon.confidenceAfter * 100);
131
+ lines.push(` └─ Confidence: ${beforePercent}% → ${afterPercent}% (${recon.confidenceLevelBefore} → ${recon.confidenceLevelAfter})`);
132
+ }
133
+ if (recon.reconciliationReasons && recon.reconciliationReasons.length > 0) {
134
+ const topReasons = recon.reconciliationReasons.slice(0, 2);
135
+ lines.push(` └─ Reconciliation: ${topReasons.join(', ')}`);
136
+ }
137
+ }
138
+ }
139
+
87
140
  return lines.join('\n');
88
141
  }
89
142
 
@@ -0,0 +1,154 @@
1
+ import { join } from 'path';
2
+
3
+ export const ARTIFACT_REGISTRY = {
4
+ runStatus: {
5
+ key: 'runStatus',
6
+ filename: 'run.status.json',
7
+ stage: 'init',
8
+ contractVersion: 1,
9
+ type: 'file'
10
+ },
11
+ runMeta: {
12
+ key: 'runMeta',
13
+ filename: 'run.meta.json',
14
+ stage: 'init',
15
+ contractVersion: 1,
16
+ type: 'file'
17
+ },
18
+ summary: {
19
+ key: 'summary',
20
+ filename: 'summary.json',
21
+ stage: 'finalize',
22
+ contractVersion: 1,
23
+ type: 'file'
24
+ },
25
+ findings: {
26
+ key: 'findings',
27
+ filename: 'findings.json',
28
+ stage: 'detect',
29
+ contractVersion: 1,
30
+ type: 'file'
31
+ },
32
+ learn: {
33
+ key: 'learn',
34
+ filename: 'learn.json',
35
+ stage: 'learn',
36
+ contractVersion: 1,
37
+ type: 'file'
38
+ },
39
+ observe: {
40
+ key: 'observe',
41
+ filename: 'observe.json',
42
+ stage: 'observe',
43
+ contractVersion: 1,
44
+ type: 'file'
45
+ },
46
+ project: {
47
+ key: 'project',
48
+ filename: 'project.json',
49
+ stage: 'init',
50
+ contractVersion: 1,
51
+ type: 'file'
52
+ },
53
+ traces: {
54
+ key: 'traces',
55
+ filename: 'traces.jsonl',
56
+ stage: 'finalize',
57
+ contractVersion: 1,
58
+ type: 'file'
59
+ },
60
+ evidence: {
61
+ key: 'evidence',
62
+ filename: 'evidence',
63
+ stage: 'observe',
64
+ contractVersion: 1,
65
+ type: 'directory'
66
+ },
67
+ scanSummary: {
68
+ key: 'scanSummary',
69
+ filename: 'scan-summary.json',
70
+ stage: 'finalize',
71
+ contractVersion: 1,
72
+ type: 'file'
73
+ },
74
+ determinismReport: {
75
+ key: 'determinismReport',
76
+ filename: 'determinism.report.json',
77
+ stage: 'finalize',
78
+ contractVersion: 1,
79
+ type: 'file'
80
+ },
81
+ evidenceIntent: {
82
+ key: 'evidenceIntent',
83
+ filename: 'evidence.intent.json',
84
+ stage: 'detect',
85
+ contractVersion: 1,
86
+ type: 'file'
87
+ },
88
+ guardrailsReport: {
89
+ key: 'guardrailsReport',
90
+ filename: 'guardrails.report.json',
91
+ stage: 'detect',
92
+ contractVersion: 1,
93
+ type: 'file'
94
+ },
95
+ confidenceReport: {
96
+ key: 'confidenceReport',
97
+ filename: 'confidence.report.json',
98
+ stage: 'detect',
99
+ contractVersion: 1,
100
+ type: 'file'
101
+ },
102
+ determinismContract: {
103
+ key: 'determinismContract',
104
+ filename: 'determinism.contract.json',
105
+ stage: 'observe',
106
+ contractVersion: 1,
107
+ type: 'file'
108
+ },
109
+ determinismReport: {
110
+ key: 'determinismReport',
111
+ filename: 'determinism.report.json',
112
+ stage: 'verify',
113
+ contractVersion: 1,
114
+ type: 'file'
115
+ },
116
+ runMeta: {
117
+ key: 'runMeta',
118
+ filename: 'run.meta.json',
119
+ stage: 'learn',
120
+ contractVersion: 1,
121
+ type: 'file'
122
+ }
123
+ };
124
+
125
+ export function getArtifactVersions() {
126
+ const versions = {};
127
+ for (const [key, def] of Object.entries(ARTIFACT_REGISTRY)) {
128
+ versions[key] = def.contractVersion;
129
+ }
130
+ return versions;
131
+ }
132
+
133
+ export function buildRunArtifactPaths(baseDir) {
134
+ return {
135
+ baseDir,
136
+ runStatusJson: join(baseDir, ARTIFACT_REGISTRY.runStatus.filename),
137
+ runMetaJson: join(baseDir, ARTIFACT_REGISTRY.runMeta.filename),
138
+ summaryJson: join(baseDir, ARTIFACT_REGISTRY.summary.filename),
139
+ findingsJson: join(baseDir, ARTIFACT_REGISTRY.findings.filename),
140
+ tracesJsonl: join(baseDir, ARTIFACT_REGISTRY.traces.filename),
141
+ evidenceDir: join(baseDir, ARTIFACT_REGISTRY.evidence.filename),
142
+ learnJson: join(baseDir, ARTIFACT_REGISTRY.learn.filename),
143
+ observeJson: join(baseDir, ARTIFACT_REGISTRY.observe.filename),
144
+ projectJson: join(baseDir, ARTIFACT_REGISTRY.project.filename),
145
+ scanSummaryJson: join(baseDir, ARTIFACT_REGISTRY.scanSummary.filename),
146
+ evidenceIntentJson: join(baseDir, ARTIFACT_REGISTRY.evidenceIntent.filename),
147
+ guardrailsReportJson: join(baseDir, ARTIFACT_REGISTRY.guardrailsReport.filename),
148
+ confidenceReportJson: join(baseDir, ARTIFACT_REGISTRY.confidenceReport.filename),
149
+ determinismContractJson: join(baseDir, ARTIFACT_REGISTRY.determinismContract.filename),
150
+ determinismReportJson: join(baseDir, ARTIFACT_REGISTRY.determinismReport.filename),
151
+ runMetaJson: join(baseDir, ARTIFACT_REGISTRY.runMeta.filename),
152
+ artifactVersions: getArtifactVersions()
153
+ };
154
+ }