@veraxhq/verax 0.3.0 → 0.4.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 +28 -20
- package/bin/verax.js +11 -18
- package/package.json +28 -7
- package/src/cli/commands/baseline.js +1 -2
- package/src/cli/commands/default.js +72 -81
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +3 -0
- package/src/cli/commands/gates.js +1 -1
- package/src/cli/commands/inspect.js +6 -133
- package/src/cli/commands/release-check.js +2 -0
- package/src/cli/commands/run.js +74 -246
- package/src/cli/commands/security-check.js +2 -1
- package/src/cli/commands/truth.js +0 -1
- package/src/cli/entry.js +82 -309
- package/src/cli/util/angular-component-extractor.js +2 -2
- package/src/cli/util/angular-navigation-detector.js +2 -2
- package/src/cli/util/ast-interactive-detector.js +4 -6
- package/src/cli/util/ast-network-detector.js +3 -3
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +3 -3
- package/src/cli/util/atomic-write.js +12 -1
- package/src/cli/util/console-reporter.js +72 -0
- package/src/cli/util/detection-engine.js +105 -41
- package/src/cli/util/determinism-runner.js +2 -1
- package/src/cli/util/determinism-writer.js +1 -1
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/env-url.js +0 -4
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +217 -367
- package/src/cli/util/findings-writer.js +19 -126
- package/src/cli/util/framework-detector.js +572 -0
- package/src/cli/util/idgen.js +1 -1
- package/src/cli/util/interaction-planner.js +529 -0
- package/src/cli/util/learn-writer.js +2 -2
- package/src/cli/util/ledger-writer.js +110 -0
- package/src/cli/util/monorepo-resolver.js +162 -0
- package/src/cli/util/observation-engine.js +127 -278
- package/src/cli/util/observe-writer.js +2 -2
- package/src/cli/util/paths.js +12 -3
- package/src/cli/util/project-discovery.js +284 -3
- package/src/cli/util/project-writer.js +2 -2
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/summary-writer.js +2 -1
- package/src/cli/util/svelte-navigation-detector.js +3 -3
- package/src/cli/util/svelte-sfc-extractor.js +0 -1
- package/src/cli/util/svelte-state-detector.js +1 -2
- package/src/cli/util/trust-activation-integration.js +496 -0
- package/src/cli/util/trust-activation-wrapper.js +85 -0
- package/src/cli/util/trust-integration-hooks.js +164 -0
- package/src/cli/util/types.js +153 -0
- package/src/cli/util/url-validation.js +40 -0
- package/src/cli/util/vue-navigation-detector.js +4 -3
- package/src/cli/util/vue-sfc-extractor.js +1 -2
- package/src/cli/util/vue-state-detector.js +1 -1
- package/src/types/fs-augment.d.ts +23 -0
- package/src/types/global.d.ts +137 -0
- package/src/types/internal-types.d.ts +35 -0
- package/src/verax/cli/finding-explainer.js +3 -56
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +0 -15
- package/src/verax/core/artifacts/verifier.js +18 -8
- package/src/verax/core/baseline/baseline.snapshot.js +2 -0
- package/src/verax/core/capabilities/gates.js +7 -1
- package/src/verax/core/confidence/confidence-compute.js +14 -7
- package/src/verax/core/confidence/confidence.loader.js +1 -0
- package/src/verax/core/confidence-engine-refactor.js +8 -3
- package/src/verax/core/confidence-engine.js +162 -23
- package/src/verax/core/contracts/types.js +1 -0
- package/src/verax/core/contracts/validators.js +79 -4
- package/src/verax/core/decision-snapshot.js +3 -30
- package/src/verax/core/decisions/decision.trace.js +2 -0
- package/src/verax/core/determinism/contract-writer.js +2 -2
- package/src/verax/core/determinism/contract.js +1 -1
- package/src/verax/core/determinism/diff.js +42 -1
- package/src/verax/core/determinism/engine.js +7 -6
- package/src/verax/core/determinism/finding-identity.js +3 -2
- package/src/verax/core/determinism/normalize.js +32 -4
- package/src/verax/core/determinism/report-writer.js +1 -0
- package/src/verax/core/determinism/run-fingerprint.js +7 -2
- package/src/verax/core/dynamic-route-intelligence.js +8 -7
- package/src/verax/core/evidence/evidence-capture-service.js +1 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +2 -1
- package/src/verax/core/evidence-builder.js +2 -2
- package/src/verax/core/execution-mode-context.js +1 -1
- package/src/verax/core/execution-mode-detector.js +5 -3
- package/src/verax/core/failures/exit-codes.js +39 -37
- package/src/verax/core/failures/failure-summary.js +1 -1
- package/src/verax/core/failures/failure.factory.js +3 -3
- package/src/verax/core/failures/failure.ledger.js +3 -2
- package/src/verax/core/ga/ga.artifact.js +1 -1
- package/src/verax/core/ga/ga.contract.js +3 -2
- package/src/verax/core/ga/ga.enforcer.js +1 -0
- package/src/verax/core/guardrails/policy.loader.js +1 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +1 -1
- package/src/verax/core/guardrails-engine.js +2 -2
- package/src/verax/core/incremental-store.js +1 -0
- package/src/verax/core/integrity/budget.js +138 -0
- package/src/verax/core/integrity/determinism.js +342 -0
- package/src/verax/core/integrity/integrity.js +208 -0
- package/src/verax/core/integrity/poisoning.js +108 -0
- package/src/verax/core/integrity/transaction.js +140 -0
- package/src/verax/core/observe/run-timeline.js +2 -0
- package/src/verax/core/perf/perf.report.js +2 -0
- package/src/verax/core/pipeline-tracker.js +5 -0
- package/src/verax/core/release/provenance.builder.js +73 -214
- package/src/verax/core/release/release.enforcer.js +14 -9
- package/src/verax/core/release/reproducibility.check.js +1 -0
- package/src/verax/core/release/sbom.builder.js +32 -23
- package/src/verax/core/replay-validator.js +2 -0
- package/src/verax/core/replay.js +4 -0
- package/src/verax/core/report/cross-index.js +6 -3
- package/src/verax/core/report/human-summary.js +141 -1
- package/src/verax/core/route-intelligence.js +4 -3
- package/src/verax/core/run-id.js +6 -3
- package/src/verax/core/run-manifest.js +4 -3
- package/src/verax/core/security/secrets.scan.js +10 -7
- package/src/verax/core/security/security.enforcer.js +4 -0
- package/src/verax/core/security/supplychain.policy.js +9 -1
- package/src/verax/core/security/vuln.scan.js +2 -2
- package/src/verax/core/truth/truth.certificate.js +3 -1
- package/src/verax/core/ui-feedback-intelligence.js +12 -46
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +100 -660
- package/src/verax/detect/confidence-helper.js +1 -0
- package/src/verax/detect/detection-engine.js +1 -18
- package/src/verax/detect/dynamic-route-findings.js +17 -14
- package/src/verax/detect/expectation-chain-detector.js +1 -1
- package/src/verax/detect/expectation-model.js +3 -5
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +126 -166
- package/src/verax/detect/flow-detector.js +2 -2
- package/src/verax/detect/form-silent-failure.js +98 -0
- package/src/verax/detect/index.js +51 -234
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +4 -4
- package/src/verax/detect/navigation-silent-failure.js +82 -0
- package/src/verax/detect/problem-aggregator.js +361 -0
- package/src/verax/detect/route-findings.js +7 -6
- package/src/verax/detect/summary-writer.js +477 -0
- package/src/verax/detect/test-failure-cause-inference.js +314 -0
- package/src/verax/detect/ui-feedback-findings.js +18 -18
- package/src/verax/detect/verdict-engine.js +3 -57
- package/src/verax/detect/view-switch-correlator.js +2 -2
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +48 -412
- package/src/verax/intel/ts-program.js +1 -0
- package/src/verax/intel/vue-navigation-extractor.js +3 -0
- package/src/verax/learn/action-contract-extractor.js +67 -682
- package/src/verax/learn/ast-contract-extractor.js +1 -1
- package/src/verax/learn/flow-extractor.js +1 -0
- package/src/verax/learn/project-detector.js +5 -0
- package/src/verax/learn/react-router-extractor.js +2 -0
- package/src/verax/learn/route-validator.js +1 -4
- package/src/verax/learn/source-instrumenter.js +1 -0
- package/src/verax/learn/state-extractor.js +2 -1
- package/src/verax/learn/static-extractor.js +1 -0
- package/src/verax/observe/coverage-gaps.js +132 -0
- package/src/verax/observe/expectation-handler.js +126 -0
- package/src/verax/observe/incremental-skip.js +46 -0
- package/src/verax/observe/index.js +735 -84
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -530
- package/src/verax/observe/network-firewall.js +86 -0
- package/src/verax/observe/observation-builder.js +169 -0
- package/src/verax/observe/observe-context.js +1 -1
- package/src/verax/observe/observe-helpers.js +2 -1
- package/src/verax/observe/observe-runner.js +28 -24
- package/src/verax/observe/observers/budget-observer.js +3 -3
- package/src/verax/observe/observers/console-observer.js +4 -4
- package/src/verax/observe/observers/coverage-observer.js +4 -4
- package/src/verax/observe/observers/interaction-observer.js +3 -3
- package/src/verax/observe/observers/navigation-observer.js +4 -4
- package/src/verax/observe/observers/network-observer.js +4 -4
- package/src/verax/observe/observers/safety-observer.js +1 -1
- package/src/verax/observe/observers/ui-feedback-observer.js +4 -4
- package/src/verax/observe/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-signal-sensor.js +2 -148
- package/src/verax/scan-summary-writer.js +10 -42
- package/src/verax/shared/artifact-manager.js +30 -13
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/core/confidence-engine.js.backup +0 -471
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
package/src/verax/index.js
CHANGED
|
@@ -9,93 +9,40 @@ import SilenceTracker from './core/silence-model.js';
|
|
|
9
9
|
import { generateRunId, getRunArtifactDir, getArtifactPath } from './core/run-id.js';
|
|
10
10
|
import { createRunManifest, updateRunManifestHashes } from './core/run-manifest.js';
|
|
11
11
|
import { computeArtifactHashes } from './core/run-id.js';
|
|
12
|
-
import { FailureLedger } from './core/failures/failure.ledger.js';
|
|
13
|
-
import { errorToFailure, createIOFailure, createInternalFailure } from './core/failures/failure.factory.js';
|
|
14
|
-
import { FAILURE_CODE, EXECUTION_PHASE } from './core/failures/failure.types.js';
|
|
15
|
-
import { createPerformanceMonitor } from './core/perf/perf.monitor.js';
|
|
16
|
-
import { generatePerformanceReport, writePerformanceReport } from './core/perf/perf.report.js';
|
|
17
|
-
import { recordPerformanceViolations } from './core/perf/perf.enforcer.js';
|
|
18
|
-
import { PipelineTracker, PIPELINE_STAGES } from './core/pipeline-tracker.js';
|
|
19
|
-
import { verifyRun } from './core/artifacts/verifier.js';
|
|
20
|
-
import { getArtifactVersions } from './core/artifacts/registry.js';
|
|
21
12
|
|
|
22
13
|
export async function scan(projectDir, url, manifestPath = null, scanBudgetOverride = null, safetyFlags = {}) {
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
const failureLedger = new FailureLedger(null, projectDir);
|
|
26
|
-
|
|
27
|
-
// PHASE 21.9: Initialize performance monitor
|
|
28
|
-
const perfMonitor = createPerformanceMonitor();
|
|
29
|
-
perfMonitor.startPhase('LEARN');
|
|
30
|
-
|
|
31
|
-
// ARCHITECTURAL HARDENING: Initialize pipeline tracker early (before runId is known)
|
|
32
|
-
// We'll set runId on the tracker once it's generated
|
|
33
|
-
let pipelineTracker = null;
|
|
14
|
+
// VISION ENFORCEMENT: Zero-configuration mode (config files ignored unless explicit --use-config flag)
|
|
15
|
+
// VERAX adapts to the project, never requires project to adapt to VERAX
|
|
34
16
|
|
|
35
17
|
// If manifestPath is provided, read it first before learn() overwrites it
|
|
36
18
|
let loadedManifest = null;
|
|
37
19
|
if (manifestPath) {
|
|
38
20
|
const { readFileSync } = await import('fs');
|
|
39
21
|
try {
|
|
22
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
40
23
|
const manifestContent = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
41
24
|
loadedManifest = manifestContent;
|
|
42
25
|
} catch (e) {
|
|
43
|
-
//
|
|
44
|
-
const failure = createIOFailure(
|
|
45
|
-
FAILURE_CODE.IO_READ_FAILED,
|
|
46
|
-
`Failed to read manifest: ${e.message}`,
|
|
47
|
-
'scan',
|
|
48
|
-
{ manifestPath, error: e.message },
|
|
49
|
-
true // Recoverable - will fall through to learn
|
|
50
|
-
);
|
|
51
|
-
failureLedger.record(failure);
|
|
26
|
+
// Fall through to learn if we can't read the manifest
|
|
52
27
|
}
|
|
53
28
|
}
|
|
54
29
|
|
|
55
|
-
// ARCHITECTURAL HARDENING: Track LEARN stage
|
|
56
|
-
// Note: We can't track LEARN yet because we don't have runId, but we'll track it retroactively
|
|
57
|
-
const learnStartTime = Date.now();
|
|
58
30
|
const learnedManifest = await learn(projectDir);
|
|
59
|
-
const learnEndTime = Date.now();
|
|
60
|
-
perfMonitor.endPhase('LEARN');
|
|
61
31
|
|
|
62
|
-
//
|
|
63
|
-
// Rule: Loaded manifest routes take precedence, but learned manifest provides truth and project type
|
|
32
|
+
// Merge: prefer loaded manifest for routes, but use learned for project type and truth
|
|
64
33
|
let manifest;
|
|
65
34
|
if (loadedManifest) {
|
|
66
|
-
// Explicit merge: loaded manifest routes override learned, but learned provides truth
|
|
67
35
|
manifest = {
|
|
68
36
|
...learnedManifest,
|
|
69
|
-
// Routes from loaded manifest (if present) override learned routes
|
|
70
|
-
publicRoutes: loadedManifest.publicRoutes || learnedManifest.publicRoutes || [],
|
|
71
|
-
routes: loadedManifest.routes || learnedManifest.routes || [],
|
|
72
|
-
internalRoutes: loadedManifest.internalRoutes || learnedManifest.internalRoutes || [],
|
|
73
|
-
staticExpectations: loadedManifest.staticExpectations || learnedManifest.staticExpectations || [],
|
|
74
|
-
// Project type: prefer loaded, fallback to learned
|
|
75
37
|
projectType: loadedManifest.projectType || learnedManifest.projectType,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
manifestPath: manifestPath
|
|
81
|
-
mergeMetadata: {
|
|
82
|
-
loadedManifestProvided: true,
|
|
83
|
-
learnedManifestProvided: true,
|
|
84
|
-
routesSource: loadedManifest.routes ? 'loaded' : 'learned',
|
|
85
|
-
projectTypeSource: loadedManifest.projectType ? 'loaded' : 'learned'
|
|
86
|
-
}
|
|
38
|
+
publicRoutes: loadedManifest.publicRoutes || learnedManifest.publicRoutes,
|
|
39
|
+
routes: loadedManifest.routes || learnedManifest.routes,
|
|
40
|
+
internalRoutes: loadedManifest.internalRoutes || learnedManifest.internalRoutes,
|
|
41
|
+
staticExpectations: loadedManifest.staticExpectations || learnedManifest.staticExpectations,
|
|
42
|
+
manifestPath: manifestPath
|
|
87
43
|
};
|
|
88
44
|
} else {
|
|
89
|
-
manifest =
|
|
90
|
-
...learnedManifest,
|
|
91
|
-
manifestSource: 'learned',
|
|
92
|
-
mergeMetadata: {
|
|
93
|
-
loadedManifestProvided: false,
|
|
94
|
-
learnedManifestProvided: true,
|
|
95
|
-
routesSource: 'learned',
|
|
96
|
-
projectTypeSource: 'learned'
|
|
97
|
-
}
|
|
98
|
-
};
|
|
45
|
+
manifest = learnedManifest;
|
|
99
46
|
}
|
|
100
47
|
|
|
101
48
|
if (!url) {
|
|
@@ -110,8 +57,18 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
110
57
|
manifestPath: manifest.manifestPath
|
|
111
58
|
};
|
|
112
59
|
|
|
113
|
-
|
|
114
|
-
|
|
60
|
+
let validation = await validateRoutes(manifestForValidation, url);
|
|
61
|
+
|
|
62
|
+
if (!validation) {
|
|
63
|
+
// validateRoutes might return null if routes cannot be validated
|
|
64
|
+
validation = {
|
|
65
|
+
routesValidated: 0,
|
|
66
|
+
routesReachable: 0,
|
|
67
|
+
routesUnreachable: 0,
|
|
68
|
+
details: [],
|
|
69
|
+
warnings: []
|
|
70
|
+
};
|
|
71
|
+
}
|
|
115
72
|
if (validation.warnings && validation.warnings.length > 0) {
|
|
116
73
|
if (!manifest.learnTruth.warnings) {
|
|
117
74
|
manifest.learnTruth.warnings = [];
|
|
@@ -119,6 +76,9 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
119
76
|
manifest.learnTruth.warnings.push(...validation.warnings);
|
|
120
77
|
}
|
|
121
78
|
|
|
79
|
+
// Use budget profile if no override provided
|
|
80
|
+
const scanBudget = scanBudgetOverride || createScanBudgetWithProfile();
|
|
81
|
+
|
|
122
82
|
// PHASE 5: Generate deterministic runId and create run manifest
|
|
123
83
|
const { getBaseOrigin } = await import('./observe/domain-boundary.js');
|
|
124
84
|
const baseOrigin = getBaseOrigin(url);
|
|
@@ -130,41 +90,6 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
130
90
|
manifestPath
|
|
131
91
|
});
|
|
132
92
|
|
|
133
|
-
// PHASE 21.5: Set runId in failure ledger
|
|
134
|
-
failureLedger.runId = runId;
|
|
135
|
-
|
|
136
|
-
// ARCHITECTURAL HARDENING: Initialize pipeline tracker now that we have runId
|
|
137
|
-
// PHASE 25: Pass runFingerprint params to PipelineTracker
|
|
138
|
-
const runFingerprintParams = url ? {
|
|
139
|
-
url,
|
|
140
|
-
projectDir,
|
|
141
|
-
manifestPath: null,
|
|
142
|
-
fixtureId: null
|
|
143
|
-
} : null;
|
|
144
|
-
pipelineTracker = new PipelineTracker(projectDir, runId, runFingerprintParams);
|
|
145
|
-
|
|
146
|
-
// Record LEARN stage retroactively (it completed before we had runId)
|
|
147
|
-
try {
|
|
148
|
-
pipelineTracker.stages[PIPELINE_STAGES.LEARN] = {
|
|
149
|
-
name: PIPELINE_STAGES.LEARN,
|
|
150
|
-
startedAt: new Date(learnStartTime).toISOString(),
|
|
151
|
-
completedAt: new Date(learnEndTime).toISOString(),
|
|
152
|
-
durationMs: learnEndTime - learnStartTime,
|
|
153
|
-
status: 'COMPLETE'
|
|
154
|
-
};
|
|
155
|
-
pipelineTracker.completedStages.push(PIPELINE_STAGES.LEARN);
|
|
156
|
-
pipelineTracker._writeMeta();
|
|
157
|
-
} catch (error) {
|
|
158
|
-
const failure = createInternalFailure(
|
|
159
|
-
FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
|
|
160
|
-
`Failed to record LEARN stage: ${error.message}`,
|
|
161
|
-
'scan',
|
|
162
|
-
{ error: error.message },
|
|
163
|
-
error.stack
|
|
164
|
-
);
|
|
165
|
-
failureLedger.record(failure);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
93
|
// Create run manifest at start of execution
|
|
169
94
|
const runManifest = createRunManifest(projectDir, runId, {
|
|
170
95
|
url,
|
|
@@ -176,61 +101,15 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
176
101
|
});
|
|
177
102
|
|
|
178
103
|
const usedManifestPath = manifestPath || manifest.manifestPath;
|
|
179
|
-
|
|
180
|
-
// ARCHITECTURAL HARDENING: Track OBSERVE stage
|
|
181
|
-
pipelineTracker.startStage(PIPELINE_STAGES.OBSERVE);
|
|
182
|
-
perfMonitor.startPhase('OBSERVE');
|
|
183
|
-
let observation;
|
|
184
|
-
try {
|
|
185
|
-
observation = await observe(url, usedManifestPath, scanBudget, safetyFlags, projectDir, runId);
|
|
186
|
-
perfMonitor.endPhase('OBSERVE');
|
|
187
|
-
pipelineTracker.completeStage(PIPELINE_STAGES.OBSERVE, {
|
|
188
|
-
pagesVisited: observation.observeTruth?.pagesVisited || 0,
|
|
189
|
-
interactionsExecuted: observation.observeTruth?.interactionsExecuted || 0
|
|
190
|
-
});
|
|
191
|
-
} catch (error) {
|
|
192
|
-
perfMonitor.endPhase('OBSERVE');
|
|
193
|
-
pipelineTracker.failStage(PIPELINE_STAGES.OBSERVE, error);
|
|
194
|
-
const failure = errorToFailure(
|
|
195
|
-
error,
|
|
196
|
-
FAILURE_CODE.OBSERVE_EXECUTION_FAILED,
|
|
197
|
-
'OBSERVE',
|
|
198
|
-
EXECUTION_PHASE.OBSERVE,
|
|
199
|
-
'observe',
|
|
200
|
-
{ manifestPath: usedManifestPath }
|
|
201
|
-
);
|
|
202
|
-
failureLedger.record(failure);
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Update performance monitor with observed metrics
|
|
207
|
-
if (observation.observeTruth) {
|
|
208
|
-
const pagesVisited = observation.observeTruth.pagesVisited || 0;
|
|
209
|
-
const interactionsExecuted = observation.observeTruth.interactionsExecuted || observation.observeTruth.candidatesSelected || 0;
|
|
210
|
-
|
|
211
|
-
for (let i = 0; i < pagesVisited; i++) {
|
|
212
|
-
perfMonitor.incrementPages();
|
|
213
|
-
}
|
|
214
|
-
for (let i = 0; i < interactionsExecuted; i++) {
|
|
215
|
-
perfMonitor.incrementInteractions();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
104
|
+
const observation = await observe(url, usedManifestPath, scanBudget, safetyFlags, projectDir, runId);
|
|
218
105
|
|
|
219
106
|
// Write a copy of the manifest into canonical run directory for replay integrity
|
|
220
107
|
try {
|
|
221
108
|
const { writeFileSync } = await import('fs');
|
|
222
109
|
const manifestCopyPath = getArtifactPath(projectDir, runId, 'manifest.json');
|
|
223
110
|
writeFileSync(manifestCopyPath, JSON.stringify(manifest, null, 2));
|
|
224
|
-
} catch
|
|
225
|
-
//
|
|
226
|
-
const failure = createIOFailure(
|
|
227
|
-
FAILURE_CODE.IO_WRITE_FAILED,
|
|
228
|
-
`Failed to write manifest copy: ${error.message}`,
|
|
229
|
-
'scan',
|
|
230
|
-
{ manifestPath, error: error.message },
|
|
231
|
-
true
|
|
232
|
-
);
|
|
233
|
-
failureLedger.record(failure);
|
|
111
|
+
} catch {
|
|
112
|
+
// Ignore write errors
|
|
234
113
|
}
|
|
235
114
|
|
|
236
115
|
// Create silence tracker from observation silences
|
|
@@ -239,69 +118,27 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
239
118
|
silenceTracker.recordBatch(observation.silences.entries);
|
|
240
119
|
}
|
|
241
120
|
|
|
242
|
-
|
|
243
|
-
pipelineTracker.startStage(PIPELINE_STAGES.DETECT);
|
|
244
|
-
perfMonitor.startPhase('DETECT');
|
|
245
|
-
let findings;
|
|
246
|
-
try {
|
|
247
|
-
findings = await detect(usedManifestPath, observation.tracesPath, validation, observation.expectationCoverageGaps || [], silenceTracker);
|
|
248
|
-
perfMonitor.endPhase('DETECT');
|
|
249
|
-
pipelineTracker.completeStage(PIPELINE_STAGES.DETECT, {
|
|
250
|
-
findingsCount: findings.findings?.length || 0,
|
|
251
|
-
coverageGapsCount: findings.coverageGaps?.length || 0
|
|
252
|
-
});
|
|
253
|
-
} catch (error) {
|
|
254
|
-
perfMonitor.endPhase('DETECT');
|
|
255
|
-
pipelineTracker.failStage(PIPELINE_STAGES.DETECT, error);
|
|
256
|
-
const failure = errorToFailure(
|
|
257
|
-
error,
|
|
258
|
-
FAILURE_CODE.DETECT_FINDING_PROCESSING_FAILED,
|
|
259
|
-
'DETECT',
|
|
260
|
-
EXECUTION_PHASE.DETECT,
|
|
261
|
-
'detect',
|
|
262
|
-
{ manifestPath: usedManifestPath }
|
|
263
|
-
);
|
|
264
|
-
failureLedger.record(failure);
|
|
265
|
-
throw error; // Re-throw BLOCKING failures
|
|
266
|
-
}
|
|
121
|
+
const findings = await detect(usedManifestPath, observation.tracesPath, validation, observation.expectationCoverageGaps || [], silenceTracker);
|
|
267
122
|
|
|
268
123
|
const learnTruthWithValidation = {
|
|
269
124
|
...manifest.learnTruth,
|
|
270
125
|
validation: validation
|
|
271
126
|
};
|
|
272
127
|
|
|
273
|
-
// ARCHITECTURAL HARDENING: Track WRITE stage
|
|
274
|
-
pipelineTracker.startStage(PIPELINE_STAGES.WRITE);
|
|
275
128
|
const runDir = getRunArtifactDir(projectDir, runId);
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
findings.findings // PHASE 7: Pass findings array for decision snapshot
|
|
290
|
-
);
|
|
291
|
-
pipelineTracker.completeStage(PIPELINE_STAGES.WRITE);
|
|
292
|
-
} catch (error) {
|
|
293
|
-
pipelineTracker.failStage(PIPELINE_STAGES.WRITE, error);
|
|
294
|
-
const failure = errorToFailure(
|
|
295
|
-
error,
|
|
296
|
-
FAILURE_CODE.IO_WRITE_FAILED,
|
|
297
|
-
'WRITE',
|
|
298
|
-
EXECUTION_PHASE.WRITE,
|
|
299
|
-
'writeScanSummary',
|
|
300
|
-
{ runDir }
|
|
301
|
-
);
|
|
302
|
-
failureLedger.record(failure);
|
|
303
|
-
throw error;
|
|
304
|
-
}
|
|
129
|
+
const scanSummary = writeScanSummary(
|
|
130
|
+
projectDir,
|
|
131
|
+
url,
|
|
132
|
+
manifest.projectType,
|
|
133
|
+
learnTruthWithValidation,
|
|
134
|
+
observation.observeTruth,
|
|
135
|
+
findings.detectTruth,
|
|
136
|
+
manifest.manifestPath,
|
|
137
|
+
observation.tracesPath,
|
|
138
|
+
findings.findingsPath,
|
|
139
|
+
runDir,
|
|
140
|
+
findings.findings // PHASE 7: Pass findings array for decision snapshot
|
|
141
|
+
);
|
|
305
142
|
|
|
306
143
|
// Compute observation summary from scan results (not a verdict)
|
|
307
144
|
// Pass observation object (which includes traces) to observation engine
|
|
@@ -330,204 +167,9 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
330
167
|
);
|
|
331
168
|
observationSummary.evidenceIndexPath = evidenceIndexPath;
|
|
332
169
|
|
|
333
|
-
// PHASE
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const { loadGuardrailsPolicy, getPolicyReport: getGuardrailsPolicyReport } = await import('./core/guardrails/policy.loader.js');
|
|
337
|
-
const { loadConfidencePolicy, getPolicyReport: getConfidencePolicyReport } = await import('./core/confidence/confidence.loader.js');
|
|
338
|
-
|
|
339
|
-
const guardrailsPolicy = loadGuardrailsPolicy();
|
|
340
|
-
const confidencePolicy = loadConfidencePolicy();
|
|
341
|
-
|
|
342
|
-
const guardrailsPolicyPath = getArtifactPath(projectDir, failureLedger.runId, 'guardrails.policy.json');
|
|
343
|
-
const confidencePolicyPath = getArtifactPath(projectDir, failureLedger.runId, 'confidence.policy.json');
|
|
344
|
-
|
|
345
|
-
writeFileSync(guardrailsPolicyPath, JSON.stringify({
|
|
346
|
-
...getGuardrailsPolicyReport(guardrailsPolicy),
|
|
347
|
-
rules: guardrailsPolicy.rules.map(r => ({
|
|
348
|
-
id: r.id,
|
|
349
|
-
category: r.category,
|
|
350
|
-
action: r.action,
|
|
351
|
-
mandatory: r.mandatory
|
|
352
|
-
}))
|
|
353
|
-
}, null, 2));
|
|
354
|
-
|
|
355
|
-
writeFileSync(confidencePolicyPath, JSON.stringify(getConfidencePolicyReport(confidencePolicy), null, 2));
|
|
356
|
-
} catch (error) {
|
|
357
|
-
// PHASE 21.5: Record I/O failure (WARNING - recoverable)
|
|
358
|
-
const failure = createIOFailure(
|
|
359
|
-
FAILURE_CODE.IO_WRITE_FAILED,
|
|
360
|
-
`Failed to write policy artifacts: ${error.message}`,
|
|
361
|
-
'scan',
|
|
362
|
-
{ error: error.message },
|
|
363
|
-
true
|
|
364
|
-
);
|
|
365
|
-
failureLedger.record(failure);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
// ARCHITECTURAL HARDENING: Write failure ledger with fallback to run.status.json
|
|
370
|
-
let ledgerPath;
|
|
371
|
-
try {
|
|
372
|
-
ledgerPath = failureLedger.write();
|
|
373
|
-
} catch (error) {
|
|
374
|
-
// If ledger write fails, write fallback entry to run.status.json
|
|
375
|
-
const failure = createInternalFailure(
|
|
376
|
-
FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
|
|
377
|
-
`Failed to write failure ledger: ${error.message}`,
|
|
378
|
-
'scan',
|
|
379
|
-
{ error: error.message },
|
|
380
|
-
error.stack
|
|
381
|
-
);
|
|
382
|
-
failureLedger.record(failure);
|
|
383
|
-
|
|
384
|
-
// Write fallback failure entry to run.status.json
|
|
385
|
-
try {
|
|
386
|
-
const { writeFileSync, readFileSync } = await import('fs');
|
|
387
|
-
const runStatusPath = getArtifactPath(projectDir, runId, 'run.status.json');
|
|
388
|
-
let runStatus = { status: 'FAILED', failures: [] };
|
|
389
|
-
try {
|
|
390
|
-
const existing = readFileSync(runStatusPath, 'utf-8');
|
|
391
|
-
runStatus = JSON.parse(existing);
|
|
392
|
-
} catch {
|
|
393
|
-
// File doesn't exist or is invalid, use defaults
|
|
394
|
-
}
|
|
395
|
-
runStatus.failures = runStatus.failures || [];
|
|
396
|
-
runStatus.failures.push({
|
|
397
|
-
code: FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
|
|
398
|
-
message: `Failed to write failure ledger: ${error.message}`,
|
|
399
|
-
timestamp: new Date().toISOString(),
|
|
400
|
-
recoverable: false
|
|
401
|
-
});
|
|
402
|
-
runStatus.ledgerWriteFailed = true;
|
|
403
|
-
runStatus.ledgerWriteError = error.message;
|
|
404
|
-
writeFileSync(runStatusPath, JSON.stringify(runStatus, null, 2) + '\n', 'utf-8');
|
|
405
|
-
} catch (fallbackError) {
|
|
406
|
-
// Even fallback write failed - log only
|
|
407
|
-
console.error('CRITICAL: Failed to write failure ledger and fallback:', error.message, fallbackError.message);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// PHASE 21.9: Generate and write performance report
|
|
412
|
-
try {
|
|
413
|
-
perfMonitor.stop();
|
|
414
|
-
const monitorReport = perfMonitor.getFinalReport();
|
|
415
|
-
const profileName = process.env.VERAX_BUDGET_PROFILE || 'STANDARD';
|
|
416
|
-
const perfReport = generatePerformanceReport(projectDir, runId, monitorReport, profileName);
|
|
417
|
-
writePerformanceReport(projectDir, runId, perfReport);
|
|
418
|
-
|
|
419
|
-
// Record performance violations in failure ledger
|
|
420
|
-
recordPerformanceViolations(projectDir, runId, failureLedger);
|
|
421
|
-
} catch (error) {
|
|
422
|
-
// Record performance report failure (WARNING - recoverable)
|
|
423
|
-
const failure = createIOFailure(
|
|
424
|
-
FAILURE_CODE.IO_WRITE_FAILED,
|
|
425
|
-
`Failed to write performance report: ${error.message}`,
|
|
426
|
-
'scan',
|
|
427
|
-
{ error: error.message },
|
|
428
|
-
true
|
|
429
|
-
);
|
|
430
|
-
failureLedger.record(failure);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// ARCHITECTURAL HARDENING: Track VERIFY stage
|
|
434
|
-
pipelineTracker.startStage(PIPELINE_STAGES.VERIFY);
|
|
435
|
-
let verification = null;
|
|
436
|
-
try {
|
|
437
|
-
const artifactVersions = getArtifactVersions();
|
|
438
|
-
verification = verifyRun(runDir, artifactVersions);
|
|
439
|
-
pipelineTracker.completeStage(PIPELINE_STAGES.VERIFY, {
|
|
440
|
-
ok: verification.ok,
|
|
441
|
-
errorsCount: verification.errors.length,
|
|
442
|
-
warningsCount: verification.warnings.length
|
|
443
|
-
});
|
|
444
|
-
} catch (error) {
|
|
445
|
-
pipelineTracker.failStage(PIPELINE_STAGES.VERIFY, error);
|
|
446
|
-
const failure = errorToFailure(
|
|
447
|
-
error,
|
|
448
|
-
FAILURE_CODE.VERIFICATION_FAILED,
|
|
449
|
-
'VERIFY',
|
|
450
|
-
EXECUTION_PHASE.VERIFY,
|
|
451
|
-
'verifyRun',
|
|
452
|
-
{ runDir }
|
|
453
|
-
);
|
|
454
|
-
failureLedger.record(failure);
|
|
455
|
-
// Verification failure is not blocking, but we record it
|
|
456
|
-
verification = {
|
|
457
|
-
ok: false,
|
|
458
|
-
errors: [error.message],
|
|
459
|
-
warnings: [],
|
|
460
|
-
verifiedAt: new Date().toISOString()
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// ARCHITECTURAL HARDENING: Track VERDICT stage (only after verification completes)
|
|
465
|
-
pipelineTracker.startStage(PIPELINE_STAGES.VERDICT);
|
|
466
|
-
try {
|
|
467
|
-
// PHASE 5: Compute artifact hashes and update run manifest
|
|
468
|
-
const artifactHashes = computeArtifactHashes(projectDir, runId);
|
|
469
|
-
updateRunManifestHashes(projectDir, runId, artifactHashes);
|
|
470
|
-
|
|
471
|
-
// Verdict computation (determinism and evidence law checks)
|
|
472
|
-
let determinismVerdict = null;
|
|
473
|
-
let evidenceLawViolated = false;
|
|
474
|
-
try {
|
|
475
|
-
const decisionsPath = getArtifactPath(projectDir, runId, 'decisions.json');
|
|
476
|
-
const { readFileSync, existsSync } = await import('fs');
|
|
477
|
-
if (existsSync(decisionsPath)) {
|
|
478
|
-
const decisions = JSON.parse(readFileSync(decisionsPath, 'utf-8'));
|
|
479
|
-
const { DecisionRecorder } = await import('./core/determinism-model.js');
|
|
480
|
-
const recorder = DecisionRecorder.fromExport(decisions);
|
|
481
|
-
const { computeDeterminismVerdict } = await import('./core/determinism/contract.js');
|
|
482
|
-
const verdict = computeDeterminismVerdict(recorder);
|
|
483
|
-
determinismVerdict = verdict.verdict;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// Check for Evidence Law violations (incomplete evidence with CONFIRMED findings)
|
|
487
|
-
if (findings.findings) {
|
|
488
|
-
for (const finding of findings.findings) {
|
|
489
|
-
if ((finding.severity === 'CONFIRMED' || finding.status === 'CONFIRMED') &&
|
|
490
|
-
finding.evidencePackage && !finding.evidencePackage.isComplete) {
|
|
491
|
-
evidenceLawViolated = true;
|
|
492
|
-
break;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
} catch (error) {
|
|
497
|
-
// Record failure but don't block
|
|
498
|
-
const failure = createInternalFailure(
|
|
499
|
-
FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
|
|
500
|
-
`Failed to compute determinism verdict: ${error.message}`,
|
|
501
|
-
'scan',
|
|
502
|
-
{ error: error.message },
|
|
503
|
-
error.stack
|
|
504
|
-
);
|
|
505
|
-
failureLedger.record(failure);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
pipelineTracker.completeStage(PIPELINE_STAGES.VERDICT, {
|
|
509
|
-
determinismVerdict,
|
|
510
|
-
evidenceLawViolated,
|
|
511
|
-
verificationOk: verification?.ok || false
|
|
512
|
-
});
|
|
513
|
-
} catch (error) {
|
|
514
|
-
pipelineTracker.failStage(PIPELINE_STAGES.VERDICT, error);
|
|
515
|
-
const failure = errorToFailure(
|
|
516
|
-
error,
|
|
517
|
-
FAILURE_CODE.VERDICT_COMPUTATION_FAILED,
|
|
518
|
-
'VERDICT',
|
|
519
|
-
EXECUTION_PHASE.VERDICT,
|
|
520
|
-
'computeVerdict',
|
|
521
|
-
{}
|
|
522
|
-
);
|
|
523
|
-
failureLedger.record(failure);
|
|
524
|
-
throw error;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// Extract verdict data from pipeline tracker
|
|
528
|
-
const verdictStage = pipelineTracker.getStage(PIPELINE_STAGES.VERDICT);
|
|
529
|
-
const determinismVerdict = verdictStage?.determinismVerdict || null;
|
|
530
|
-
const evidenceLawViolated = verdictStage?.evidenceLawViolated || false;
|
|
170
|
+
// PHASE 5: Compute artifact hashes and update run manifest
|
|
171
|
+
const artifactHashes = computeArtifactHashes(projectDir, runId);
|
|
172
|
+
updateRunManifestHashes(projectDir, runId, artifactHashes);
|
|
531
173
|
|
|
532
174
|
return {
|
|
533
175
|
manifest,
|
|
@@ -537,14 +179,8 @@ export async function scan(projectDir, url, manifestPath = null, scanBudgetOverr
|
|
|
537
179
|
validation,
|
|
538
180
|
coverageGaps: findings.coverageGaps || [],
|
|
539
181
|
observationSummary,
|
|
540
|
-
runId
|
|
541
|
-
runManifest
|
|
542
|
-
failureLedger: failureLedger.export(),
|
|
543
|
-
ledgerPath,
|
|
544
|
-
determinismVerdict,
|
|
545
|
-
evidenceLawViolated,
|
|
546
|
-
verification,
|
|
547
|
-
pipelineStages: pipelineTracker.getAllStages()
|
|
182
|
+
runId,
|
|
183
|
+
runManifest
|
|
548
184
|
};
|
|
549
185
|
}
|
|
550
186
|
|
|
@@ -85,6 +85,7 @@ function extractFromFile(filePath, projectRoot, _program) {
|
|
|
85
85
|
// to handle template literals and complex navigation calls
|
|
86
86
|
try {
|
|
87
87
|
const content = readFileSync(filePath, 'utf-8');
|
|
88
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
88
89
|
const scriptMatch = content.match(/<script[^>]*>([\s\S]*?)<\/script>/);
|
|
89
90
|
if (scriptMatch) {
|
|
90
91
|
const scriptContent = scriptMatch[1];
|
|
@@ -162,6 +163,7 @@ function extractFromVueSFC(filePath, projectRoot) {
|
|
|
162
163
|
const content = readFileSync(filePath, 'utf-8');
|
|
163
164
|
|
|
164
165
|
// Extract template section
|
|
166
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
165
167
|
const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
|
|
166
168
|
if (templateMatch) {
|
|
167
169
|
const templateContent = templateMatch[1];
|
|
@@ -263,6 +265,7 @@ function extractFromVueSFC(filePath, projectRoot) {
|
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
// Extract script section for router.push/replace
|
|
268
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
266
269
|
const scriptMatch = content.match(/<script[^>]*>([\s\S]*?)<\/script>/);
|
|
267
270
|
if (scriptMatch) {
|
|
268
271
|
const scriptContent = scriptMatch[1];
|