@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,242 @@
1
+ /**
2
+ * VIEW SWITCH CORRELATOR
3
+ *
4
+ * Correlates view switch promises with observed UI changes (no URL change).
5
+ * Requires at least 2 independent signals for CONFIRMED.
6
+ *
7
+ * TRUTH BOUNDARY:
8
+ * - CONFIRMED: 2+ independent signals (DOM signature + landmark/focus/aria-live)
9
+ * - SUSPECTED: 1 signal only
10
+ * - INFORMATIONAL: Interaction blocked/disabled/prevented
11
+ */
12
+
13
+ /**
14
+ * Reason codes for correlation decisions
15
+ */
16
+ export const VIEW_SWITCH_REASON_CODES = {
17
+ CONFIRMED_TWO_SIGNALS: 'CONFIRMED_TWO_SIGNALS',
18
+ CONFIRMED_THREE_SIGNALS: 'CONFIRMED_THREE_SIGNALS',
19
+ SUSPECTED_ONE_SIGNAL: 'SUSPECTED_ONE_SIGNAL',
20
+ INFORMATIONAL_BLOCKED: 'INFORMATIONAL_BLOCKED',
21
+ INFORMATIONAL_DISABLED: 'INFORMATIONAL_DISABLED',
22
+ INFORMATIONAL_PREVENTED: 'INFORMATIONAL_PREVENTED',
23
+ NO_SIGNALS: 'NO_SIGNALS'
24
+ };
25
+
26
+ /**
27
+ * Correlate view switch promise with observed UI changes.
28
+ *
29
+ * @param {Object} expectation - View switch promise expectation
30
+ * @param {Object} trace - Interaction trace with sensors
31
+ * @param {string} beforeUrl - URL before interaction
32
+ * @param {string} afterUrl - URL after interaction
33
+ * @returns {Object} - { outcome, severity, reasonCode, signals }
34
+ */
35
+ export function correlateViewSwitch(expectation, trace, beforeUrl, afterUrl) {
36
+ if (!expectation || expectation.kind !== 'VIEW_SWITCH_PROMISE') {
37
+ return { outcome: null, severity: null, reasonCode: null, signals: [] };
38
+ }
39
+
40
+ const sensors = trace.sensors || {};
41
+ const navigation = sensors.navigation || {};
42
+ const uiSignals = sensors.uiSignals || {};
43
+ const stateUi = sensors.stateUi || {};
44
+ const uiFeedback = sensors.uiFeedback || {};
45
+
46
+ // Check if URL changed (if so, this is not a state-driven navigation)
47
+ const urlChanged = navigation.urlChanged === true || (beforeUrl !== afterUrl);
48
+ if (urlChanged) {
49
+ return { outcome: null, severity: null, reasonCode: 'URL_CHANGED', signals: [] };
50
+ }
51
+
52
+ // Check if interaction was blocked/disabled/prevented
53
+ const interaction = trace.interaction || {};
54
+ const isDisabled = interaction.disabled === true;
55
+ const isBlocked = interaction.blocked === true;
56
+ const isPrevented = interaction.prevented === true;
57
+
58
+ if (isDisabled) {
59
+ return {
60
+ outcome: 'INFORMATIONAL',
61
+ severity: 'INFORMATIONAL',
62
+ reasonCode: VIEW_SWITCH_REASON_CODES.INFORMATIONAL_DISABLED,
63
+ signals: []
64
+ };
65
+ }
66
+
67
+ if (isBlocked) {
68
+ return {
69
+ outcome: 'INFORMATIONAL',
70
+ severity: 'INFORMATIONAL',
71
+ reasonCode: VIEW_SWITCH_REASON_CODES.INFORMATIONAL_BLOCKED,
72
+ signals: []
73
+ };
74
+ }
75
+
76
+ if (isPrevented) {
77
+ return {
78
+ outcome: 'INFORMATIONAL',
79
+ severity: 'INFORMATIONAL',
80
+ reasonCode: VIEW_SWITCH_REASON_CODES.INFORMATIONAL_PREVENTED,
81
+ signals: []
82
+ };
83
+ }
84
+
85
+ // Collect independent signals
86
+ const signals = [];
87
+
88
+ // Signal 1: DOM signature change (stable hash)
89
+ const beforeDom = trace.before?.domSignature || trace.before?.domHash;
90
+ const afterDom = trace.after?.domSignature || trace.after?.domHash;
91
+ if (beforeDom && afterDom && beforeDom !== afterDom) {
92
+ signals.push({
93
+ type: 'DOM_SIGNATURE_CHANGE',
94
+ before: beforeDom,
95
+ after: afterDom
96
+ });
97
+ }
98
+
99
+ // Signal 2: Visible landmark change (heading/main role change)
100
+ const beforeLandmarks = extractLandmarks(trace.before);
101
+ const afterLandmarks = extractLandmarks(trace.after);
102
+ if (beforeLandmarks.length > 0 && afterLandmarks.length > 0) {
103
+ const landmarksChanged = JSON.stringify(beforeLandmarks) !== JSON.stringify(afterLandmarks);
104
+ if (landmarksChanged) {
105
+ signals.push({
106
+ type: 'LANDMARK_CHANGE',
107
+ before: beforeLandmarks,
108
+ after: afterLandmarks
109
+ });
110
+ }
111
+ }
112
+
113
+ // Signal 3: Focus moved to new container
114
+ const beforeFocus = trace.before?.focus || {};
115
+ const afterFocus = trace.after?.focus || {};
116
+ if (beforeFocus.selector && afterFocus.selector && beforeFocus.selector !== afterFocus.selector) {
117
+ const beforeContainer = getContainerSelector(beforeFocus.selector);
118
+ const afterContainer = getContainerSelector(afterFocus.selector);
119
+ if (beforeContainer !== afterContainer) {
120
+ signals.push({
121
+ type: 'FOCUS_CONTAINER_CHANGE',
122
+ before: beforeContainer,
123
+ after: afterContainer
124
+ });
125
+ }
126
+ }
127
+
128
+ // Signal 4: aria-live message
129
+ const ariaLiveBefore = extractAriaLive(trace.before);
130
+ const ariaLiveAfter = extractAriaLive(trace.after);
131
+ if (ariaLiveAfter.length > ariaLiveBefore.length) {
132
+ signals.push({
133
+ type: 'ARIA_LIVE_MESSAGE',
134
+ messages: ariaLiveAfter.slice(ariaLiveBefore.length)
135
+ });
136
+ }
137
+
138
+ // Signal 5: UI feedback signals (optional but counts)
139
+ if (uiFeedback.signals) {
140
+ const feedbackSignals = uiFeedback.signals;
141
+ if (feedbackSignals.domChange?.happened === true) {
142
+ signals.push({
143
+ type: 'UI_FEEDBACK_DOM_CHANGE',
144
+ details: feedbackSignals.domChange
145
+ });
146
+ }
147
+ if (feedbackSignals.focusChange?.happened === true) {
148
+ signals.push({
149
+ type: 'UI_FEEDBACK_FOCUS_CHANGE',
150
+ details: feedbackSignals.focusChange
151
+ });
152
+ }
153
+ }
154
+
155
+ // Determine outcome based on signal count
156
+ if (signals.length >= 2) {
157
+ return {
158
+ outcome: 'CONFIRMED',
159
+ severity: 'CONFIRMED',
160
+ reasonCode: signals.length >= 3
161
+ ? VIEW_SWITCH_REASON_CODES.CONFIRMED_THREE_SIGNALS
162
+ : VIEW_SWITCH_REASON_CODES.CONFIRMED_TWO_SIGNALS,
163
+ signals
164
+ };
165
+ } else if (signals.length === 1) {
166
+ return {
167
+ outcome: 'SUSPECTED',
168
+ severity: 'SUSPECTED',
169
+ reasonCode: VIEW_SWITCH_REASON_CODES.SUSPECTED_ONE_SIGNAL,
170
+ signals
171
+ };
172
+ } else {
173
+ return {
174
+ outcome: 'NO_SIGNALS',
175
+ severity: 'SUSPECTED',
176
+ reasonCode: VIEW_SWITCH_REASON_CODES.NO_SIGNALS,
177
+ signals: []
178
+ };
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Extract landmarks (headings, main role) from trace snapshot
184
+ */
185
+ function extractLandmarks(snapshot) {
186
+ if (!snapshot) return [];
187
+
188
+ const landmarks = [];
189
+
190
+ // Extract headings (h1-h6)
191
+ if (snapshot.headings) {
192
+ landmarks.push(...snapshot.headings.map(h => ({ type: 'heading', level: h.level, text: h.text?.slice(0, 50) })));
193
+ }
194
+
195
+ // Extract main role elements
196
+ if (snapshot.mainElements) {
197
+ landmarks.push(...snapshot.mainElements.map(m => ({ type: 'main', text: m.text?.slice(0, 50) })));
198
+ }
199
+
200
+ return landmarks;
201
+ }
202
+
203
+ /**
204
+ * Get container selector from element selector
205
+ */
206
+ function getContainerSelector(selector) {
207
+ if (!selector) return null;
208
+
209
+ // Extract parent container (simplified - assumes common patterns)
210
+ const parts = selector.split(' > ');
211
+ if (parts.length > 1) {
212
+ return parts[parts.length - 2]; // Second to last part
213
+ }
214
+
215
+ // Try to extract container from selector
216
+ const match = selector.match(/([^>]+) > [^>]+$/);
217
+ if (match) {
218
+ return match[1].trim();
219
+ }
220
+
221
+ return selector; // Fallback to full selector
222
+ }
223
+
224
+ /**
225
+ * Extract aria-live messages from trace snapshot
226
+ */
227
+ function extractAriaLive(snapshot) {
228
+ if (!snapshot) return [];
229
+
230
+ const messages = [];
231
+
232
+ if (snapshot.ariaLiveRegions) {
233
+ snapshot.ariaLiveRegions.forEach(region => {
234
+ if (region.text) {
235
+ messages.push(region.text.slice(0, 100));
236
+ }
237
+ });
238
+ }
239
+
240
+ return messages;
241
+ }
242
+
@@ -63,7 +63,7 @@ export async function executeFlow(page, spec, sensors = {}) {
63
63
  };
64
64
  }
65
65
 
66
- async function executeStep(page, step, idx, spec, sensors, secretValues) {
66
+ async function executeStep(page, step, idx, spec, _sensors, _secretValues) {
67
67
  const baseResult = {
68
68
  stepIndex: idx,
69
69
  type: step.type,
@@ -131,7 +131,8 @@ async function stepGoto(page, step, result, spec) {
131
131
  return result;
132
132
  }
133
133
 
134
- await page.goto(url, { waitUntil: 'networkidle' });
134
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
135
+ await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
135
136
  await waitForSettle(page, { timeoutMs: 3000, settleMs: 500 });
136
137
 
137
138
  result.success = true;
@@ -111,10 +111,9 @@ export function validateFlowSpec(spec) {
111
111
  * Returns actual value or throws if not found.
112
112
  *
113
113
  * @param {string} value - String containing $ENV:VARNAME references
114
- * @param {Object} secrets - Map of secret keys to env var names
115
114
  * @returns {string} - Resolved value
116
115
  */
117
- export function resolveSecrets(value, secrets = {}) {
116
+ export function resolveSecrets(value, _secrets = {}) {
118
117
  if (typeof value !== 'string') return value;
119
118
 
120
119
  // Replace $ENV:VARNAME with actual env var value