@veraxhq/verax 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/README.md +14 -18
  2. package/bin/verax.js +7 -0
  3. package/package.json +15 -5
  4. package/src/cli/commands/baseline.js +104 -0
  5. package/src/cli/commands/default.js +323 -111
  6. package/src/cli/commands/doctor.js +36 -4
  7. package/src/cli/commands/ga.js +243 -0
  8. package/src/cli/commands/gates.js +95 -0
  9. package/src/cli/commands/inspect.js +131 -2
  10. package/src/cli/commands/release-check.js +213 -0
  11. package/src/cli/commands/run.js +498 -103
  12. package/src/cli/commands/security-check.js +211 -0
  13. package/src/cli/commands/truth.js +114 -0
  14. package/src/cli/entry.js +305 -68
  15. package/src/cli/util/angular-component-extractor.js +179 -0
  16. package/src/cli/util/angular-navigation-detector.js +141 -0
  17. package/src/cli/util/angular-network-detector.js +161 -0
  18. package/src/cli/util/angular-state-detector.js +162 -0
  19. package/src/cli/util/ast-interactive-detector.js +546 -0
  20. package/src/cli/util/ast-network-detector.js +603 -0
  21. package/src/cli/util/ast-usestate-detector.js +602 -0
  22. package/src/cli/util/bootstrap-guard.js +86 -0
  23. package/src/cli/util/detection-engine.js +4 -3
  24. package/src/cli/util/determinism-runner.js +123 -0
  25. package/src/cli/util/determinism-writer.js +129 -0
  26. package/src/cli/util/env-url.js +4 -0
  27. package/src/cli/util/events.js +76 -0
  28. package/src/cli/util/expectation-extractor.js +380 -74
  29. package/src/cli/util/findings-writer.js +126 -15
  30. package/src/cli/util/learn-writer.js +3 -1
  31. package/src/cli/util/observation-engine.js +69 -23
  32. package/src/cli/util/observe-writer.js +3 -1
  33. package/src/cli/util/paths.js +6 -14
  34. package/src/cli/util/project-discovery.js +23 -0
  35. package/src/cli/util/project-writer.js +3 -1
  36. package/src/cli/util/redact.js +2 -2
  37. package/src/cli/util/run-resolver.js +64 -0
  38. package/src/cli/util/runtime-budget.js +147 -0
  39. package/src/cli/util/source-requirement.js +55 -0
  40. package/src/cli/util/summary-writer.js +13 -1
  41. package/src/cli/util/svelte-navigation-detector.js +163 -0
  42. package/src/cli/util/svelte-network-detector.js +80 -0
  43. package/src/cli/util/svelte-sfc-extractor.js +147 -0
  44. package/src/cli/util/svelte-state-detector.js +243 -0
  45. package/src/cli/util/vue-navigation-detector.js +177 -0
  46. package/src/cli/util/vue-sfc-extractor.js +162 -0
  47. package/src/cli/util/vue-state-detector.js +215 -0
  48. package/src/types/global.d.ts +28 -0
  49. package/src/types/ts-ast.d.ts +24 -0
  50. package/src/verax/cli/doctor.js +2 -2
  51. package/src/verax/cli/finding-explainer.js +56 -3
  52. package/src/verax/cli/init.js +1 -1
  53. package/src/verax/cli/url-safety.js +12 -2
  54. package/src/verax/cli/wizard.js +13 -2
  55. package/src/verax/core/artifacts/registry.js +154 -0
  56. package/src/verax/core/artifacts/verifier.js +980 -0
  57. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  58. package/src/verax/core/baseline/baseline.snapshot.js +231 -0
  59. package/src/verax/core/budget-engine.js +1 -1
  60. package/src/verax/core/capabilities/gates.js +499 -0
  61. package/src/verax/core/capabilities/registry.js +475 -0
  62. package/src/verax/core/confidence/confidence-compute.js +137 -0
  63. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  64. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  65. package/src/verax/core/confidence/confidence-weights.js +44 -0
  66. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  67. package/src/verax/core/confidence/confidence.loader.js +79 -0
  68. package/src/verax/core/confidence/confidence.schema.js +94 -0
  69. package/src/verax/core/confidence-engine-refactor.js +484 -0
  70. package/src/verax/core/confidence-engine.js +486 -0
  71. package/src/verax/core/confidence-engine.js.backup +471 -0
  72. package/src/verax/core/contracts/index.js +29 -0
  73. package/src/verax/core/contracts/types.js +185 -0
  74. package/src/verax/core/contracts/validators.js +381 -0
  75. package/src/verax/core/decision-snapshot.js +31 -4
  76. package/src/verax/core/decisions/decision.trace.js +276 -0
  77. package/src/verax/core/determinism/contract-writer.js +89 -0
  78. package/src/verax/core/determinism/contract.js +139 -0
  79. package/src/verax/core/determinism/diff.js +364 -0
  80. package/src/verax/core/determinism/engine.js +221 -0
  81. package/src/verax/core/determinism/finding-identity.js +148 -0
  82. package/src/verax/core/determinism/normalize.js +438 -0
  83. package/src/verax/core/determinism/report-writer.js +92 -0
  84. package/src/verax/core/determinism/run-fingerprint.js +118 -0
  85. package/src/verax/core/determinism-model.js +35 -6
  86. package/src/verax/core/dynamic-route-intelligence.js +528 -0
  87. package/src/verax/core/evidence/evidence-capture-service.js +307 -0
  88. package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
  89. package/src/verax/core/evidence-builder.js +487 -0
  90. package/src/verax/core/execution-mode-context.js +77 -0
  91. package/src/verax/core/execution-mode-detector.js +190 -0
  92. package/src/verax/core/failures/exit-codes.js +86 -0
  93. package/src/verax/core/failures/failure-summary.js +76 -0
  94. package/src/verax/core/failures/failure.factory.js +225 -0
  95. package/src/verax/core/failures/failure.ledger.js +132 -0
  96. package/src/verax/core/failures/failure.types.js +196 -0
  97. package/src/verax/core/failures/index.js +10 -0
  98. package/src/verax/core/ga/ga-report-writer.js +43 -0
  99. package/src/verax/core/ga/ga.artifact.js +49 -0
  100. package/src/verax/core/ga/ga.contract.js +434 -0
  101. package/src/verax/core/ga/ga.enforcer.js +86 -0
  102. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  103. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  104. package/src/verax/core/guardrails/policy.loader.js +83 -0
  105. package/src/verax/core/guardrails/policy.schema.js +110 -0
  106. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  107. package/src/verax/core/guardrails-engine.js +505 -0
  108. package/src/verax/core/incremental-store.js +15 -7
  109. package/src/verax/core/observe/run-timeline.js +316 -0
  110. package/src/verax/core/perf/perf.contract.js +186 -0
  111. package/src/verax/core/perf/perf.display.js +65 -0
  112. package/src/verax/core/perf/perf.enforcer.js +91 -0
  113. package/src/verax/core/perf/perf.monitor.js +209 -0
  114. package/src/verax/core/perf/perf.report.js +198 -0
  115. package/src/verax/core/pipeline-tracker.js +238 -0
  116. package/src/verax/core/product-definition.js +127 -0
  117. package/src/verax/core/release/provenance.builder.js +271 -0
  118. package/src/verax/core/release/release-report-writer.js +40 -0
  119. package/src/verax/core/release/release.enforcer.js +159 -0
  120. package/src/verax/core/release/reproducibility.check.js +221 -0
  121. package/src/verax/core/release/sbom.builder.js +283 -0
  122. package/src/verax/core/replay-validator.js +4 -4
  123. package/src/verax/core/replay.js +1 -1
  124. package/src/verax/core/report/cross-index.js +192 -0
  125. package/src/verax/core/report/human-summary.js +222 -0
  126. package/src/verax/core/route-intelligence.js +419 -0
  127. package/src/verax/core/security/secrets.scan.js +326 -0
  128. package/src/verax/core/security/security-report.js +50 -0
  129. package/src/verax/core/security/security.enforcer.js +124 -0
  130. package/src/verax/core/security/supplychain.defaults.json +38 -0
  131. package/src/verax/core/security/supplychain.policy.js +326 -0
  132. package/src/verax/core/security/vuln.scan.js +265 -0
  133. package/src/verax/core/silence-impact.js +1 -1
  134. package/src/verax/core/silence-model.js +9 -7
  135. package/src/verax/core/truth/truth.certificate.js +250 -0
  136. package/src/verax/core/ui-feedback-intelligence.js +515 -0
  137. package/src/verax/detect/comparison.js +8 -3
  138. package/src/verax/detect/confidence-engine.js +645 -57
  139. package/src/verax/detect/confidence-helper.js +33 -0
  140. package/src/verax/detect/detection-engine.js +19 -2
  141. package/src/verax/detect/dynamic-route-findings.js +335 -0
  142. package/src/verax/detect/evidence-index.js +15 -65
  143. package/src/verax/detect/expectation-chain-detector.js +417 -0
  144. package/src/verax/detect/expectation-model.js +56 -3
  145. package/src/verax/detect/explanation-helpers.js +1 -1
  146. package/src/verax/detect/finding-detector.js +2 -2
  147. package/src/verax/detect/findings-writer.js +149 -20
  148. package/src/verax/detect/flow-detector.js +4 -4
  149. package/src/verax/detect/index.js +265 -15
  150. package/src/verax/detect/interactive-findings.js +3 -4
  151. package/src/verax/detect/journey-stall-detector.js +558 -0
  152. package/src/verax/detect/route-findings.js +218 -0
  153. package/src/verax/detect/signal-mapper.js +2 -2
  154. package/src/verax/detect/skip-classifier.js +4 -4
  155. package/src/verax/detect/ui-feedback-findings.js +207 -0
  156. package/src/verax/detect/verdict-engine.js +61 -9
  157. package/src/verax/detect/view-switch-correlator.js +242 -0
  158. package/src/verax/flow/flow-engine.js +3 -2
  159. package/src/verax/flow/flow-spec.js +1 -2
  160. package/src/verax/index.js +413 -33
  161. package/src/verax/intel/effect-detector.js +1 -1
  162. package/src/verax/intel/index.js +2 -2
  163. package/src/verax/intel/route-extractor.js +3 -3
  164. package/src/verax/intel/vue-navigation-extractor.js +81 -18
  165. package/src/verax/intel/vue-router-extractor.js +4 -2
  166. package/src/verax/learn/action-contract-extractor.js +684 -66
  167. package/src/verax/learn/ast-contract-extractor.js +53 -1
  168. package/src/verax/learn/index.js +36 -2
  169. package/src/verax/learn/manifest-writer.js +28 -14
  170. package/src/verax/learn/route-extractor.js +1 -1
  171. package/src/verax/learn/route-validator.js +12 -8
  172. package/src/verax/learn/state-extractor.js +1 -1
  173. package/src/verax/learn/static-extractor-navigation.js +1 -1
  174. package/src/verax/learn/static-extractor-validation.js +2 -2
  175. package/src/verax/learn/static-extractor.js +8 -7
  176. package/src/verax/learn/ts-contract-resolver.js +14 -12
  177. package/src/verax/observe/browser.js +22 -3
  178. package/src/verax/observe/console-sensor.js +2 -2
  179. package/src/verax/observe/expectation-executor.js +2 -1
  180. package/src/verax/observe/focus-sensor.js +1 -1
  181. package/src/verax/observe/human-driver.js +29 -10
  182. package/src/verax/observe/index.js +92 -844
  183. package/src/verax/observe/interaction-discovery.js +27 -15
  184. package/src/verax/observe/interaction-runner.js +31 -14
  185. package/src/verax/observe/loading-sensor.js +6 -0
  186. package/src/verax/observe/navigation-sensor.js +1 -1
  187. package/src/verax/observe/observe-context.js +205 -0
  188. package/src/verax/observe/observe-helpers.js +191 -0
  189. package/src/verax/observe/observe-runner.js +226 -0
  190. package/src/verax/observe/observers/budget-observer.js +185 -0
  191. package/src/verax/observe/observers/console-observer.js +102 -0
  192. package/src/verax/observe/observers/coverage-observer.js +107 -0
  193. package/src/verax/observe/observers/interaction-observer.js +471 -0
  194. package/src/verax/observe/observers/navigation-observer.js +132 -0
  195. package/src/verax/observe/observers/network-observer.js +87 -0
  196. package/src/verax/observe/observers/safety-observer.js +82 -0
  197. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  198. package/src/verax/observe/settle.js +1 -0
  199. package/src/verax/observe/state-sensor.js +8 -4
  200. package/src/verax/observe/state-ui-sensor.js +7 -1
  201. package/src/verax/observe/traces-writer.js +27 -16
  202. package/src/verax/observe/ui-feedback-detector.js +742 -0
  203. package/src/verax/observe/ui-signal-sensor.js +155 -2
  204. package/src/verax/scan-summary-writer.js +46 -9
  205. package/src/verax/shared/artifact-manager.js +9 -6
  206. package/src/verax/shared/budget-profiles.js +2 -2
  207. package/src/verax/shared/caching.js +1 -1
  208. package/src/verax/shared/config-loader.js +1 -2
  209. package/src/verax/shared/css-spinner-rules.js +204 -0
  210. package/src/verax/shared/dynamic-route-utils.js +12 -6
  211. package/src/verax/shared/retry-policy.js +1 -6
  212. package/src/verax/shared/root-artifacts.js +1 -1
  213. package/src/verax/shared/view-switch-rules.js +208 -0
  214. package/src/verax/shared/zip-artifacts.js +1 -0
  215. package/src/verax/validate/context-validator.js +1 -1
  216. package/src/verax/observe/index.js.backup +0 -1
  217. package/src/verax/validate/context-validator.js.bak +0 -0
@@ -0,0 +1,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
+
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Global type declarations for VERAX
3
+ * These extend built-in types to support runtime-injected properties
4
+ */
5
+
6
+ // Extend Window interface for browser-injected properties
7
+ declare global {
8
+ interface Window {
9
+ __veraxNavTracking?: any;
10
+ next?: any;
11
+ __REDUX_STORE__?: any;
12
+ store?: any;
13
+ __REDUX_DEVTOOLS_EXTENSION__?: any;
14
+ __REACT_DEVTOOLS_GLOBAL_HOOK__?: any;
15
+ __VERAX_STATE_SENSOR__?: any;
16
+ __unhandledRejections?: any[];
17
+ __ZUSTAND_STORE__?: any;
18
+ }
19
+ }
20
+
21
+ // Playwright Page type (imported from playwright)
22
+ import type { Page as PlaywrightPage } from 'playwright';
23
+
24
+ // Re-export for use in JS files
25
+ export type Page = PlaywrightPage;
26
+
27
+ export {};
28
+
@@ -0,0 +1,24 @@
1
+ /**
2
+ * TypeScript AST Node type extensions
3
+ * These extend the base Node type to include properties used by VERAX
4
+ */
5
+
6
+ import type * as ts from 'typescript';
7
+
8
+ declare module 'typescript' {
9
+ interface Node {
10
+ attributes?: ts.NodeArray<ts.JSDocAttribute>;
11
+ tagName?: ts.Identifier;
12
+ body?: ts.Node;
13
+ arguments?: ts.NodeArray<ts.Expression>;
14
+ initializer?: ts.Expression;
15
+ expression?: ts.Expression;
16
+ children?: ts.NodeArray<ts.Node>;
17
+ }
18
+
19
+ namespace ts {
20
+ // Add isFalseKeyword if it doesn't exist (it might be in a different version)
21
+ function isFalseKeyword(node: ts.Node): node is ts.FalseKeyword;
22
+ }
23
+ }
24
+
@@ -4,7 +4,7 @@
4
4
  * Checks environment, dependencies, and project setup.
5
5
  */
6
6
 
7
- import { existsSync, mkdirSync, writeFileSync, unlinkSync } from 'fs';
7
+ import { mkdirSync, writeFileSync, unlinkSync } from 'fs';
8
8
  import { resolve } from 'path';
9
9
  import { chromium } from 'playwright';
10
10
  import { get } from 'http';
@@ -182,7 +182,7 @@ async function checkUrlReachability(url) {
182
182
  * @returns {Promise<Object>} Doctor results
183
183
  */
184
184
  export async function runDoctor(options = {}) {
185
- const { projectRoot = process.cwd(), url = null, json = false } = options;
185
+ const { projectRoot = process.cwd(), url = null, json: _json = false } = options;
186
186
 
187
187
  const checks = [];
188
188
  let overallStatus = 'ok';
@@ -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
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { existsSync, writeFileSync, mkdirSync } from 'fs';
8
- import { resolve, dirname } from 'path';
8
+ import { resolve } from 'path';
9
9
  import { getDefaultConfig } from '../shared/config-loader.js';
10
10
 
11
11
  /**
@@ -68,11 +68,21 @@ export function checkUrlSafety(url) {
68
68
  }
69
69
  }
70
70
 
71
+ /**
72
+ * @typedef {Object} ReadlineInterface
73
+ * @property {function(string): Promise<string>} question - Prompt user with question
74
+ * @property {function(): void} close - Close the readline interface
75
+ */
76
+
77
+ /**
78
+ * @typedef {Object} ConfirmExternalUrlOptions
79
+ * @property {ReadlineInterface} [readlineInterface] - Readline interface (injectable)
80
+ */
81
+
71
82
  /**
72
83
  * Prompt for external URL confirmation
73
84
  * @param {string} hostname - Hostname to confirm
74
- * @param {Object} options - Options
75
- * @param {Function} options.readlineInterface - Readline interface (injectable)
85
+ * @param {ConfirmExternalUrlOptions} [options={}] - Options
76
86
  * @returns {Promise<boolean>} True if confirmed
77
87
  */
78
88
  export async function confirmExternalUrl(hostname, options = {}) {
@@ -4,8 +4,15 @@
4
4
  * Guides users through VERAX configuration with friendly prompts.
5
5
  */
6
6
 
7
+ /**
8
+ * @typedef {Object} ReadlineInterface
9
+ * @property {function(string): Promise<string>} question - Prompt user with question
10
+ * @property {function(): void} close - Close the readline interface
11
+ */
12
+
7
13
  /**
8
14
  * Create a readline interface (can be injected for testing)
15
+ * @returns {Promise<ReadlineInterface>}
9
16
  */
10
17
  async function createReadlineInterface(input = process.stdin, output = process.stdout) {
11
18
  const readline = await import('readline/promises');
@@ -16,10 +23,14 @@ async function createReadlineInterface(input = process.stdin, output = process.s
16
23
  });
17
24
  }
18
25
 
26
+ /**
27
+ * @typedef {Object} WizardOptions
28
+ * @property {ReadlineInterface} [readlineInterface] - Readline interface (injectable for testing)
29
+ */
30
+
19
31
  /**
20
32
  * Run interactive wizard
21
- * @param {Object} options - Options for wizard
22
- * @param {Function} options.readlineInterface - Readline interface (injectable for testing)
33
+ * @param {WizardOptions} [options={}] - Options for wizard
23
34
  * @returns {Promise<Object>} Wizard results
24
35
  */
25
36
  export async function runWizard(options = {}) {
@@ -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
+ }