@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.
- package/README.md +14 -18
- package/bin/verax.js +7 -0
- package/package.json +15 -5
- package/src/cli/commands/baseline.js +104 -0
- package/src/cli/commands/default.js +323 -111
- package/src/cli/commands/doctor.js +36 -4
- package/src/cli/commands/ga.js +243 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +131 -2
- package/src/cli/commands/release-check.js +213 -0
- package/src/cli/commands/run.js +498 -103
- package/src/cli/commands/security-check.js +211 -0
- package/src/cli/commands/truth.js +114 -0
- package/src/cli/entry.js +305 -68
- package/src/cli/util/angular-component-extractor.js +179 -0
- package/src/cli/util/angular-navigation-detector.js +141 -0
- package/src/cli/util/angular-network-detector.js +161 -0
- package/src/cli/util/angular-state-detector.js +162 -0
- package/src/cli/util/ast-interactive-detector.js +546 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/bootstrap-guard.js +86 -0
- package/src/cli/util/detection-engine.js +4 -3
- package/src/cli/util/determinism-runner.js +123 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/env-url.js +4 -0
- package/src/cli/util/events.js +76 -0
- package/src/cli/util/expectation-extractor.js +380 -74
- package/src/cli/util/findings-writer.js +126 -15
- package/src/cli/util/learn-writer.js +3 -1
- package/src/cli/util/observation-engine.js +69 -23
- package/src/cli/util/observe-writer.js +3 -1
- package/src/cli/util/paths.js +6 -14
- package/src/cli/util/project-discovery.js +23 -0
- package/src/cli/util/project-writer.js +3 -1
- package/src/cli/util/redact.js +2 -2
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/runtime-budget.js +147 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +13 -1
- package/src/cli/util/svelte-navigation-detector.js +163 -0
- package/src/cli/util/svelte-network-detector.js +80 -0
- package/src/cli/util/svelte-sfc-extractor.js +147 -0
- package/src/cli/util/svelte-state-detector.js +243 -0
- package/src/cli/util/vue-navigation-detector.js +177 -0
- package/src/cli/util/vue-sfc-extractor.js +162 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- package/src/types/global.d.ts +28 -0
- package/src/types/ts-ast.d.ts +24 -0
- package/src/verax/cli/doctor.js +2 -2
- package/src/verax/cli/finding-explainer.js +56 -3
- package/src/verax/cli/init.js +1 -1
- package/src/verax/cli/url-safety.js +12 -2
- package/src/verax/cli/wizard.js +13 -2
- package/src/verax/core/artifacts/registry.js +154 -0
- package/src/verax/core/artifacts/verifier.js +980 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +231 -0
- package/src/verax/core/budget-engine.js +1 -1
- package/src/verax/core/capabilities/gates.js +499 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +137 -0
- package/src/verax/core/confidence/confidence-invariants.js +234 -0
- package/src/verax/core/confidence/confidence-report-writer.js +112 -0
- package/src/verax/core/confidence/confidence-weights.js +44 -0
- package/src/verax/core/confidence/confidence.defaults.js +65 -0
- package/src/verax/core/confidence/confidence.loader.js +79 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +484 -0
- package/src/verax/core/confidence-engine.js +486 -0
- package/src/verax/core/confidence-engine.js.backup +471 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +185 -0
- package/src/verax/core/contracts/validators.js +381 -0
- package/src/verax/core/decision-snapshot.js +31 -4
- package/src/verax/core/decisions/decision.trace.js +276 -0
- package/src/verax/core/determinism/contract-writer.js +89 -0
- package/src/verax/core/determinism/contract.js +139 -0
- package/src/verax/core/determinism/diff.js +364 -0
- package/src/verax/core/determinism/engine.js +221 -0
- package/src/verax/core/determinism/finding-identity.js +148 -0
- package/src/verax/core/determinism/normalize.js +438 -0
- package/src/verax/core/determinism/report-writer.js +92 -0
- package/src/verax/core/determinism/run-fingerprint.js +118 -0
- package/src/verax/core/determinism-model.js +35 -6
- package/src/verax/core/dynamic-route-intelligence.js +528 -0
- package/src/verax/core/evidence/evidence-capture-service.js +307 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
- package/src/verax/core/evidence-builder.js +487 -0
- package/src/verax/core/execution-mode-context.js +77 -0
- package/src/verax/core/execution-mode-detector.js +190 -0
- package/src/verax/core/failures/exit-codes.js +86 -0
- package/src/verax/core/failures/failure-summary.js +76 -0
- package/src/verax/core/failures/failure.factory.js +225 -0
- package/src/verax/core/failures/failure.ledger.js +132 -0
- package/src/verax/core/failures/failure.types.js +196 -0
- package/src/verax/core/failures/index.js +10 -0
- package/src/verax/core/ga/ga-report-writer.js +43 -0
- package/src/verax/core/ga/ga.artifact.js +49 -0
- package/src/verax/core/ga/ga.contract.js +434 -0
- package/src/verax/core/ga/ga.enforcer.js +86 -0
- package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
- package/src/verax/core/guardrails/policy.defaults.js +210 -0
- package/src/verax/core/guardrails/policy.loader.js +83 -0
- package/src/verax/core/guardrails/policy.schema.js +110 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
- package/src/verax/core/guardrails-engine.js +505 -0
- package/src/verax/core/incremental-store.js +15 -7
- package/src/verax/core/observe/run-timeline.js +316 -0
- package/src/verax/core/perf/perf.contract.js +186 -0
- package/src/verax/core/perf/perf.display.js +65 -0
- package/src/verax/core/perf/perf.enforcer.js +91 -0
- package/src/verax/core/perf/perf.monitor.js +209 -0
- package/src/verax/core/perf/perf.report.js +198 -0
- package/src/verax/core/pipeline-tracker.js +238 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +271 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +159 -0
- package/src/verax/core/release/reproducibility.check.js +221 -0
- package/src/verax/core/release/sbom.builder.js +283 -0
- package/src/verax/core/replay-validator.js +4 -4
- package/src/verax/core/replay.js +1 -1
- package/src/verax/core/report/cross-index.js +192 -0
- package/src/verax/core/report/human-summary.js +222 -0
- package/src/verax/core/route-intelligence.js +419 -0
- package/src/verax/core/security/secrets.scan.js +326 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +124 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +326 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/silence-impact.js +1 -1
- package/src/verax/core/silence-model.js +9 -7
- package/src/verax/core/truth/truth.certificate.js +250 -0
- package/src/verax/core/ui-feedback-intelligence.js +515 -0
- package/src/verax/detect/comparison.js +8 -3
- package/src/verax/detect/confidence-engine.js +645 -57
- package/src/verax/detect/confidence-helper.js +33 -0
- package/src/verax/detect/detection-engine.js +19 -2
- package/src/verax/detect/dynamic-route-findings.js +335 -0
- package/src/verax/detect/evidence-index.js +15 -65
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +56 -3
- package/src/verax/detect/explanation-helpers.js +1 -1
- package/src/verax/detect/finding-detector.js +2 -2
- package/src/verax/detect/findings-writer.js +149 -20
- package/src/verax/detect/flow-detector.js +4 -4
- package/src/verax/detect/index.js +265 -15
- package/src/verax/detect/interactive-findings.js +3 -4
- package/src/verax/detect/journey-stall-detector.js +558 -0
- package/src/verax/detect/route-findings.js +218 -0
- package/src/verax/detect/signal-mapper.js +2 -2
- package/src/verax/detect/skip-classifier.js +4 -4
- package/src/verax/detect/ui-feedback-findings.js +207 -0
- package/src/verax/detect/verdict-engine.js +61 -9
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/flow/flow-engine.js +3 -2
- package/src/verax/flow/flow-spec.js +1 -2
- package/src/verax/index.js +413 -33
- package/src/verax/intel/effect-detector.js +1 -1
- package/src/verax/intel/index.js +2 -2
- package/src/verax/intel/route-extractor.js +3 -3
- package/src/verax/intel/vue-navigation-extractor.js +81 -18
- package/src/verax/intel/vue-router-extractor.js +4 -2
- package/src/verax/learn/action-contract-extractor.js +684 -66
- package/src/verax/learn/ast-contract-extractor.js +53 -1
- package/src/verax/learn/index.js +36 -2
- package/src/verax/learn/manifest-writer.js +28 -14
- package/src/verax/learn/route-extractor.js +1 -1
- package/src/verax/learn/route-validator.js +12 -8
- package/src/verax/learn/state-extractor.js +1 -1
- package/src/verax/learn/static-extractor-navigation.js +1 -1
- package/src/verax/learn/static-extractor-validation.js +2 -2
- package/src/verax/learn/static-extractor.js +8 -7
- package/src/verax/learn/ts-contract-resolver.js +14 -12
- package/src/verax/observe/browser.js +22 -3
- package/src/verax/observe/console-sensor.js +2 -2
- package/src/verax/observe/expectation-executor.js +2 -1
- package/src/verax/observe/focus-sensor.js +1 -1
- package/src/verax/observe/human-driver.js +29 -10
- package/src/verax/observe/index.js +92 -844
- package/src/verax/observe/interaction-discovery.js +27 -15
- package/src/verax/observe/interaction-runner.js +31 -14
- package/src/verax/observe/loading-sensor.js +6 -0
- package/src/verax/observe/navigation-sensor.js +1 -1
- package/src/verax/observe/observe-context.js +205 -0
- package/src/verax/observe/observe-helpers.js +191 -0
- package/src/verax/observe/observe-runner.js +226 -0
- package/src/verax/observe/observers/budget-observer.js +185 -0
- package/src/verax/observe/observers/console-observer.js +102 -0
- package/src/verax/observe/observers/coverage-observer.js +107 -0
- package/src/verax/observe/observers/interaction-observer.js +471 -0
- package/src/verax/observe/observers/navigation-observer.js +132 -0
- package/src/verax/observe/observers/network-observer.js +87 -0
- package/src/verax/observe/observers/safety-observer.js +82 -0
- package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
- package/src/verax/observe/settle.js +1 -0
- package/src/verax/observe/state-sensor.js +8 -4
- package/src/verax/observe/state-ui-sensor.js +7 -1
- package/src/verax/observe/traces-writer.js +27 -16
- package/src/verax/observe/ui-feedback-detector.js +742 -0
- package/src/verax/observe/ui-signal-sensor.js +155 -2
- package/src/verax/scan-summary-writer.js +46 -9
- package/src/verax/shared/artifact-manager.js +9 -6
- package/src/verax/shared/budget-profiles.js +2 -2
- package/src/verax/shared/caching.js +1 -1
- package/src/verax/shared/config-loader.js +1 -2
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/dynamic-route-utils.js +12 -6
- package/src/verax/shared/retry-policy.js +1 -6
- package/src/verax/shared/root-artifacts.js +1 -1
- package/src/verax/shared/view-switch-rules.js +208 -0
- package/src/verax/shared/zip-artifacts.js +1 -0
- package/src/verax/validate/context-validator.js +1 -1
- package/src/verax/observe/index.js.backup +0 -1
- 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
|
+
|
|
@@ -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(() =>
|
|
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 (
|
|
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
|
-
|
|
226
|
-
|
|
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((
|
|
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
|
-
|
|
22
|
-
|
|
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 = {
|