@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,82 @@
1
+ /**
2
+ * PHASE 21.3 — Safety Observer
3
+ *
4
+ * Responsibilities:
5
+ * - Network interception (cross-origin blocking, write method blocking)
6
+ * - NO file I/O
7
+ * - NO side effects outside its scope
8
+ */
9
+
10
+ /**
11
+ * Setup network interception firewall
12
+ *
13
+ * @param {ObserveContext} context - Observe context
14
+ * @returns {Promise<void>}
15
+ */
16
+ export async function setupNetworkInterception(context) {
17
+ const { page, baseOrigin, safetyFlags, silenceTracker, blockedNetworkWrites, blockedCrossOrigin } = context;
18
+ const { allowWrites = false, allowCrossOrigin = false } = safetyFlags;
19
+
20
+ await page.route('**/*', (route) => {
21
+ const request = route.request();
22
+ const method = request.method();
23
+ const requestUrl = request.url();
24
+ const resourceType = request.resourceType();
25
+
26
+ // Check cross-origin blocking (skip for file:// URLs)
27
+ if (!allowCrossOrigin && !requestUrl.startsWith('file://')) {
28
+ try {
29
+ const reqOrigin = new URL(requestUrl).origin;
30
+ if (reqOrigin !== baseOrigin) {
31
+ blockedCrossOrigin.push({
32
+ url: requestUrl,
33
+ origin: reqOrigin,
34
+ method,
35
+ resourceType,
36
+ timestamp: Date.now()
37
+ });
38
+
39
+ silenceTracker.record({
40
+ scope: 'safety',
41
+ reason: 'cross_origin_blocked',
42
+ description: `Cross-origin request blocked: ${method} ${requestUrl}`,
43
+ context: { url: requestUrl, origin: reqOrigin, method, baseOrigin },
44
+ impact: 'request_blocked'
45
+ });
46
+
47
+ return route.abort('blockedbyclient');
48
+ }
49
+ } catch (e) {
50
+ // Invalid URL, allow and let browser handle
51
+ }
52
+ }
53
+
54
+ // Check write method blocking
55
+ if (!allowWrites && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
56
+ // Check if it's a GraphQL mutation (best-effort)
57
+ const isGraphQLMutation = requestUrl.includes('/graphql') && method === 'POST';
58
+
59
+ blockedNetworkWrites.push({
60
+ url: requestUrl,
61
+ method,
62
+ resourceType,
63
+ isGraphQLMutation,
64
+ timestamp: Date.now()
65
+ });
66
+
67
+ silenceTracker.record({
68
+ scope: 'safety',
69
+ reason: 'blocked_network_write',
70
+ description: `Network write blocked: ${method} ${requestUrl}${isGraphQLMutation ? ' (GraphQL mutation)' : ''}`,
71
+ context: { url: requestUrl, method, resourceType, isGraphQLMutation },
72
+ impact: 'write_blocked'
73
+ });
74
+
75
+ return route.abort('blockedbyclient');
76
+ }
77
+
78
+ // Allow request
79
+ route.continue();
80
+ });
81
+ }
82
+
@@ -0,0 +1,99 @@
1
+ /**
2
+ * PHASE 21.3 — UI Feedback Observer
3
+ *
4
+ * Responsibilities:
5
+ * - DOM mutation observation
6
+ * - Loading / disabled / feedback signals
7
+ * - UI settle signals (NO adaptive waiting - that's in settle.js)
8
+ *
9
+ * NO file I/O
10
+ * NO side effects outside its scope
11
+ */
12
+
13
+ import { UISignalSensor } from '../ui-signal-sensor.js';
14
+ import { captureDomSignature } from '../dom-signature.js';
15
+
16
+ /**
17
+ * Observe UI feedback and DOM state on current page
18
+ *
19
+ * @param {ObserveContext} context - Observe context
20
+ * @param {RunState} runState - Current run state
21
+ * @returns {Promise<Array<Observation>>} Array of UI feedback observations
22
+ */
23
+ export async function observe(context, runState) {
24
+ const { page, currentUrl, timestamp } = context;
25
+ const observations = [];
26
+
27
+ try {
28
+ // Capture current UI signals
29
+ const uiSignalSensor = new UISignalSensor();
30
+ const uiSignals = await uiSignalSensor.snapshot(page);
31
+
32
+ // Capture DOM signature for mutation tracking
33
+ const domSignature = await captureDomSignature(page);
34
+
35
+ // Create observation for UI signals
36
+ observations.push({
37
+ type: 'ui_feedback',
38
+ scope: 'page',
39
+ data: {
40
+ hasLoadingIndicator: uiSignals.hasLoadingIndicator,
41
+ hasDialog: uiSignals.hasDialog,
42
+ hasErrorSignal: uiSignals.hasErrorSignal,
43
+ hasStatusSignal: uiSignals.hasStatusSignal,
44
+ hasLiveRegion: uiSignals.hasLiveRegion,
45
+ validationFeedbackDetected: uiSignals.validationFeedbackDetected,
46
+ disabledElementsCount: uiSignals.disabledElements?.length || 0,
47
+ explanation: uiSignals.explanation || []
48
+ },
49
+ timestamp,
50
+ url: currentUrl
51
+ });
52
+
53
+ // Create observation for DOM state
54
+ observations.push({
55
+ type: 'dom_state',
56
+ scope: 'page',
57
+ data: {
58
+ domHash: domSignature,
59
+ hasDom: !!domSignature
60
+ },
61
+ timestamp,
62
+ url: currentUrl
63
+ });
64
+
65
+ // If there are loading indicators, create specific observation
66
+ if (uiSignals.hasLoadingIndicator) {
67
+ observations.push({
68
+ type: 'ui_loading',
69
+ scope: 'page',
70
+ data: {
71
+ loading: true,
72
+ explanation: uiSignals.explanation?.filter(e => e.includes('loading') || e.includes('busy')) || []
73
+ },
74
+ timestamp,
75
+ url: currentUrl
76
+ });
77
+ }
78
+
79
+ // If there are disabled elements, create observation
80
+ if (uiSignals.disabledElements && uiSignals.disabledElements.length > 0) {
81
+ observations.push({
82
+ type: 'ui_disabled',
83
+ scope: 'page',
84
+ data: {
85
+ disabledCount: uiSignals.disabledElements.length,
86
+ disabledElements: uiSignals.disabledElements.slice(0, 10) // Limit to 10
87
+ },
88
+ timestamp,
89
+ url: currentUrl
90
+ });
91
+ }
92
+ } catch (error) {
93
+ // Propagate error - no silent catch
94
+ throw new Error(`UI feedback observer failed: ${error.message}`);
95
+ }
96
+
97
+ return observations;
98
+ }
99
+
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * WAVE 2: Deterministic DOM settle logic
3
3
  * Waits for page to stabilize after navigation or interaction
4
+ * @typedef {import('playwright').Page} Page
4
5
  */
5
6
 
6
7
  import { DEFAULT_SCAN_BUDGET } from '../shared/scan-budget.js';
@@ -58,7 +58,10 @@ class ReduxSensor {
58
58
  resolve();
59
59
  } else {
60
60
  // Wait up to 5 seconds for store initialization
61
- const timeout = setTimeout(() => resolve(), 5000);
61
+ const timeout = setTimeout(() => {
62
+ clearInterval(check);
63
+ resolve();
64
+ }, 5000);
62
65
  const check = setInterval(() => {
63
66
  if (window.__REDUX_STORE__) {
64
67
  clearInterval(check);
@@ -125,7 +128,7 @@ class ReduxSensor {
125
128
  // Shallow copy of top-level keys only (privacy: no values)
126
129
  const snapshot = {};
127
130
  for (const key in state) {
128
- if (state.hasOwnProperty(key)) {
131
+ if (Object.prototype.hasOwnProperty.call(state, key)) {
129
132
  snapshot[key] = '[REDACTED]'; // Never store values, only keys
130
133
  }
131
134
  }
@@ -222,8 +225,9 @@ class ZustandSensor {
222
225
  // Look for common Zustand patterns in window object
223
226
  for (const key in window) {
224
227
  if (key.startsWith('use') && typeof window[key] === 'function') {
225
- const store = window[key];
226
- if (store.getState && typeof store.getState === 'function') {
228
+ // Dynamic property access on window for Zustand store detection (runtime property)
229
+ const store = /** @type {any} */ (window[key]);
230
+ if (store && typeof store === 'object' && 'getState' in store && typeof store.getState === 'function') {
227
231
  return true;
228
232
  }
229
233
  }
@@ -22,13 +22,14 @@ export class StateUISensor {
22
22
  */
23
23
  async snapshot(page, contextSelector = null) {
24
24
  try {
25
- const snapshot = await page.evaluate(({ selector }) => {
25
+ const snapshot = await page.evaluate(() => {
26
26
  const signals = {};
27
27
  const rawSnapshot = {};
28
28
 
29
29
  // 1. Dialog/Modal signals
30
30
  signals.dialogs = [];
31
31
  const dialogs = document.querySelectorAll('[role="dialog"]');
32
+ // @ts-expect-error - NodeListOf is iterable in browser context
32
33
  for (const dialog of dialogs) {
33
34
  const isVisible = dialog.offsetParent !== null || dialog.hasAttribute('open');
34
35
  const ariaModal = dialog.getAttribute('aria-modal');
@@ -46,6 +47,7 @@ export class StateUISensor {
46
47
  // 2. Expansion state (aria-expanded)
47
48
  signals.expandedElements = [];
48
49
  const expandables = document.querySelectorAll('[aria-expanded]');
50
+ // @ts-expect-error - NodeListOf is iterable in browser context
49
51
  for (const el of expandables) {
50
52
  const expanded = el.getAttribute('aria-expanded') === 'true';
51
53
  signals.expandedElements.push({
@@ -58,6 +60,7 @@ export class StateUISensor {
58
60
  // 3. Tab selection (role=tab with aria-selected)
59
61
  signals.selectedTabs = [];
60
62
  const tabs = document.querySelectorAll('[role="tab"]');
63
+ // @ts-expect-error - NodeListOf is iterable in browser context
61
64
  for (const tab of tabs) {
62
65
  const selected = tab.getAttribute('aria-selected') === 'true';
63
66
  signals.selectedTabs.push({
@@ -70,6 +73,7 @@ export class StateUISensor {
70
73
  // 4. Checkbox/toggle state (aria-checked)
71
74
  signals.checkedElements = [];
72
75
  const checkables = document.querySelectorAll('[aria-checked]');
76
+ // @ts-expect-error - NodeListOf is iterable in browser context
73
77
  for (const el of checkables) {
74
78
  const checked = el.getAttribute('aria-checked') === 'true';
75
79
  signals.checkedElements.push({
@@ -82,6 +86,7 @@ export class StateUISensor {
82
86
  // 5. Alert/Status changes (role=alert, role=status)
83
87
  signals.alerts = [];
84
88
  const alerts = document.querySelectorAll('[role="alert"], [role="status"]');
89
+ // @ts-expect-error - NodeListOf is iterable in browser context
85
90
  for (const alert of alerts) {
86
91
  const text = alert.textContent?.trim() || '';
87
92
  signals.alerts.push({
@@ -96,6 +101,7 @@ export class StateUISensor {
96
101
  // Count visible nodes and text nodes (excluding style/comment nodes)
97
102
  const countMeaningfulNodes = () => {
98
103
  let count = 0;
104
+ // @ts-expect-error - NodeListOf is iterable in browser context
99
105
  for (const node of document.querySelectorAll('*')) {
100
106
  if (node.offsetParent !== null) { // Visible
101
107
  count++;
@@ -1,7 +1,23 @@
1
- import { resolve } from 'path';
2
1
  import { writeFileSync, mkdirSync } from 'fs';
3
2
  import { getArtifactPath, getRunArtifactDir } from '../core/run-id.js';
4
3
 
4
+ /**
5
+ * @typedef {Object} WriteTracesResult
6
+ * @property {number} version
7
+ * @property {string} observedAt
8
+ * @property {string} url
9
+ * @property {Array} traces
10
+ * @property {Array} [observedExpectations]
11
+ * @property {Object} [coverage]
12
+ * @property {Array} [warnings]
13
+ * @property {Object} [silences] - Added by writeTraces if silenceTracker provided
14
+ * @property {string} tracesPath
15
+ * @property {Object} observeTruth
16
+ * @property {Object} [expectationExecution] - Added by caller after writeTraces
17
+ * @property {Array} [expectationCoverageGaps] - Added by caller after writeTraces
18
+ * @property {Object} [incremental] - Added by caller after writeTraces
19
+ */
20
+
5
21
  /**
6
22
  * SILENCE TRACKING: Write observation traces with explicit silence tracking.
7
23
  * All gaps, skips, caps, and unknowns must be recorded and surfaced.
@@ -11,24 +27,19 @@ import { getArtifactPath, getRunArtifactDir } from '../core/run-id.js';
11
27
  * @param {string} projectDir - Project directory
12
28
  * @param {string} url - URL observed
13
29
  * @param {Array} traces - Execution traces
14
- * @param {Object} coverage - Coverage data (if capped, this is a silence)
15
- * @param {Array} warnings - Warnings (caps are silences)
16
- * @param {Array} observedExpectations - Observed expectations
17
- * @param {Object} silenceTracker - Silence tracker (optional)
18
- * @param {string} runId - Run identifier (Phase 5)
30
+ * @param {Object} [coverage] - Coverage data (if capped, this is a silence)
31
+ * @param {Array} [warnings] - Warnings (caps are silences)
32
+ * @param {Array} [observedExpectations] - Observed expectations
33
+ * @param {Object} [silenceTracker] - Silence tracker (optional)
34
+ * @param {string} [runId] - Run identifier (Phase 5) - required but optional in signature for type compatibility
35
+ * @returns {WriteTracesResult}
19
36
  */
20
37
  export function writeTraces(projectDir, url, traces, coverage = null, warnings = [], observedExpectations = [], silenceTracker = null, runId = null) {
21
- // PHASE 5: Use deterministic artifact path if runId provided, otherwise fall back to old path
22
- let observeDir, tracesPath;
23
- if (runId) {
24
- observeDir = getRunArtifactDir(projectDir, runId);
25
- tracesPath = getArtifactPath(projectDir, runId, 'traces.json');
26
- } else {
27
- // Backwards compatibility for tests
28
- observeDir = resolve(projectDir, '.veraxverax', 'observe');
29
- tracesPath = resolve(observeDir, 'observation-traces.json');
38
+ if (!runId) {
39
+ throw new Error('runId is required');
30
40
  }
31
-
41
+ const observeDir = getRunArtifactDir(projectDir, runId);
42
+ const tracesPath = getArtifactPath(projectDir, runId, 'traces.json');
32
43
  mkdirSync(observeDir, { recursive: true });
33
44
 
34
45
  const observation = {