@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,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 18 — Determinism Runner
|
|
3
|
+
*
|
|
4
|
+
* Wraps a scan execution to run it multiple times and compare results.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import { readFileSync, existsSync } from 'fs';
|
|
9
|
+
import { runDeterminismCheck } from '../../verax/core/determinism/engine.js';
|
|
10
|
+
import { verifyRun } from '../../verax/core/artifacts/verifier.js';
|
|
11
|
+
import { writeDeterminismReport } from './determinism-writer.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* PHASE 18: Run scan with determinism checking
|
|
15
|
+
*
|
|
16
|
+
* @param {Function} scanFn - Function that executes a scan and returns { runId }
|
|
17
|
+
* @param {Object} options - Options
|
|
18
|
+
* @param {number} options.runs - Number of runs (default: 2)
|
|
19
|
+
* @param {string} options.out - Output directory
|
|
20
|
+
* @returns {Promise<Object>} Determinism check results
|
|
21
|
+
*/
|
|
22
|
+
export async function runWithDeterminism(scanFn, options = {}) {
|
|
23
|
+
const { runs = 2, out = '.verax' } = options;
|
|
24
|
+
|
|
25
|
+
// Wrap scan function to return artifact paths
|
|
26
|
+
const runFn = async (runConfig) => {
|
|
27
|
+
const result = await scanFn({ ...options, ...runConfig });
|
|
28
|
+
|
|
29
|
+
// Extract artifact paths from result
|
|
30
|
+
const artifactPaths = {};
|
|
31
|
+
if (result.runId) {
|
|
32
|
+
const runDir = resolve(out, 'runs', result.runId);
|
|
33
|
+
|
|
34
|
+
// Map artifact keys to paths
|
|
35
|
+
const artifactMap = {
|
|
36
|
+
findings: resolve(runDir, 'findings.json'),
|
|
37
|
+
runStatus: resolve(runDir, 'run.status.json'),
|
|
38
|
+
summary: resolve(runDir, 'summary.json'),
|
|
39
|
+
learn: resolve(runDir, 'learn.json'),
|
|
40
|
+
observe: resolve(runDir, 'observe.json'),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
for (const [key, path] of Object.entries(artifactMap)) {
|
|
44
|
+
if (existsSync(path)) {
|
|
45
|
+
artifactPaths[key] = path;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
runId: result.runId,
|
|
52
|
+
artifactPaths,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// PHASE 25: Load run fingerprints from run.meta.json
|
|
57
|
+
const loadRunFingerprints = async (runMeta) => {
|
|
58
|
+
if (runMeta.runId) {
|
|
59
|
+
const runDir = resolve(out, 'runs', runMeta.runId);
|
|
60
|
+
const metaPath = resolve(runDir, 'run.meta.json');
|
|
61
|
+
if (existsSync(metaPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const metaContent = readFileSync(metaPath, 'utf-8');
|
|
64
|
+
const meta = JSON.parse(metaContent);
|
|
65
|
+
return meta.runFingerprint || null;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Run determinism check
|
|
75
|
+
const determinismResult = await runDeterminismCheck(runFn, {
|
|
76
|
+
runs,
|
|
77
|
+
config: options,
|
|
78
|
+
normalize: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// PHASE 25: Load run fingerprints for each run
|
|
82
|
+
for (const runMeta of determinismResult.runsMeta) {
|
|
83
|
+
runMeta.runFingerprint = await loadRunFingerprints(runMeta);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Verify each run
|
|
87
|
+
const verificationResults = [];
|
|
88
|
+
for (const runMeta of determinismResult.runsMeta) {
|
|
89
|
+
if (runMeta.runId) {
|
|
90
|
+
const runDir = resolve(out, 'runs', runMeta.runId);
|
|
91
|
+
if (existsSync(runDir)) {
|
|
92
|
+
try {
|
|
93
|
+
const { getArtifactVersions } = await import('../../verax/core/artifacts/registry.js');
|
|
94
|
+
const verification = verifyRun(runDir, getArtifactVersions());
|
|
95
|
+
verificationResults.push({
|
|
96
|
+
runId: runMeta.runId,
|
|
97
|
+
verification,
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// Verification failed
|
|
101
|
+
verificationResults.push({
|
|
102
|
+
runId: runMeta.runId,
|
|
103
|
+
verification: { ok: false, errors: [error.message] },
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Write determinism report
|
|
111
|
+
const reportPath = await writeDeterminismReport(
|
|
112
|
+
determinismResult,
|
|
113
|
+
verificationResults,
|
|
114
|
+
out
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
...determinismResult,
|
|
119
|
+
verificationResults,
|
|
120
|
+
reportPath,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 18 — Determinism Report Writer
|
|
3
|
+
*
|
|
4
|
+
* Writes determinism check results to artifact.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
9
|
+
import { ARTIFACT_REGISTRY, getArtifactVersions } from '../../verax/core/artifacts/registry.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* PHASE 18: Write determinism report
|
|
13
|
+
* PHASE 25: Enhanced with runFingerprint, contract validation, and structured verdicts
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} determinismResult - Result from runDeterminismCheck
|
|
16
|
+
* @param {Array} verificationResults - Verification results for each run
|
|
17
|
+
* @param {string} outDir - Output directory
|
|
18
|
+
* @returns {Promise<string>} Path to determinism report
|
|
19
|
+
*/
|
|
20
|
+
export async function writeDeterminismReport(determinismResult, verificationResults, outDir) {
|
|
21
|
+
const reportsDir = resolve(outDir, 'determinism');
|
|
22
|
+
mkdirSync(reportsDir, { recursive: true });
|
|
23
|
+
|
|
24
|
+
const reportId = `determinism-${Date.now()}`;
|
|
25
|
+
const reportPath = resolve(reportsDir, `${reportId}.json`);
|
|
26
|
+
|
|
27
|
+
// PHASE 25: Check run fingerprints
|
|
28
|
+
const runFingerprints = [];
|
|
29
|
+
const runFingerprintMismatches = [];
|
|
30
|
+
for (const runMeta of determinismResult.runsMeta) {
|
|
31
|
+
if (runMeta.runFingerprint) {
|
|
32
|
+
runFingerprints.push(runMeta.runFingerprint);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (runFingerprints.length > 1) {
|
|
36
|
+
const firstFingerprint = runFingerprints[0];
|
|
37
|
+
for (let i = 1; i < runFingerprints.length; i++) {
|
|
38
|
+
if (runFingerprints[i] !== firstFingerprint) {
|
|
39
|
+
runFingerprintMismatches.push({
|
|
40
|
+
runIndex: i + 1,
|
|
41
|
+
expected: firstFingerprint,
|
|
42
|
+
actual: runFingerprints[i]
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// PHASE 25: Check verifier errors
|
|
49
|
+
const verifierErrors = [];
|
|
50
|
+
for (const verification of verificationResults) {
|
|
51
|
+
if (verification.verification && !verification.verification.ok) {
|
|
52
|
+
verifierErrors.push({
|
|
53
|
+
runId: verification.runId,
|
|
54
|
+
errors: verification.verification.errors || [],
|
|
55
|
+
verdictStatus: verification.verification.verdictStatus
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// PHASE 25: Determine final verdict with expected/unexpected distinction
|
|
61
|
+
let finalVerdict = determinismResult.verdict;
|
|
62
|
+
if (runFingerprintMismatches.length > 0) {
|
|
63
|
+
finalVerdict = 'NON_DETERMINISTIC_UNEXPECTED';
|
|
64
|
+
} else if (verifierErrors.length > 0) {
|
|
65
|
+
finalVerdict = 'NON_DETERMINISTIC_UNEXPECTED';
|
|
66
|
+
} else if (determinismResult.adaptiveEvents && determinismResult.adaptiveEvents.length > 0) {
|
|
67
|
+
finalVerdict = 'NON_DETERMINISTIC_EXPECTED';
|
|
68
|
+
} else if (determinismResult.diffs && determinismResult.diffs.length > 0) {
|
|
69
|
+
const blockerDiffs = determinismResult.diffs.filter(d => d.severity === 'BLOCKER');
|
|
70
|
+
if (blockerDiffs.length > 0) {
|
|
71
|
+
finalVerdict = 'NON_DETERMINISTIC_UNEXPECTED';
|
|
72
|
+
} else {
|
|
73
|
+
finalVerdict = 'NON_DETERMINISTIC_EXPECTED';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// PHASE 25: Build top reasons
|
|
78
|
+
const topReasons = [];
|
|
79
|
+
if (runFingerprintMismatches.length > 0) {
|
|
80
|
+
topReasons.push({ code: 'RUN_FINGERPRINT_MISMATCH', count: runFingerprintMismatches.length });
|
|
81
|
+
}
|
|
82
|
+
if (verifierErrors.length > 0) {
|
|
83
|
+
topReasons.push({ code: 'VERIFIER_ERRORS_DETECTED', count: verifierErrors.length });
|
|
84
|
+
}
|
|
85
|
+
if (determinismResult.adaptiveEvents && determinismResult.adaptiveEvents.length > 0) {
|
|
86
|
+
topReasons.push({ code: 'EXPECTED_ADAPTIVE_BEHAVIOR', count: determinismResult.adaptiveEvents.length });
|
|
87
|
+
}
|
|
88
|
+
if (determinismResult.diffs && determinismResult.diffs.length > 0) {
|
|
89
|
+
const blockerCount = determinismResult.diffs.filter(d => d.severity === 'BLOCKER').length;
|
|
90
|
+
if (blockerCount > 0) {
|
|
91
|
+
topReasons.push({ code: 'ARTIFACT_DIFF_DETECTED', count: blockerCount });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const report = {
|
|
96
|
+
version: 2, // PHASE 25: Bump version
|
|
97
|
+
contractVersion: 1,
|
|
98
|
+
artifactVersions: getArtifactVersions(),
|
|
99
|
+
generatedAt: new Date().toISOString(),
|
|
100
|
+
verdict: finalVerdict,
|
|
101
|
+
summary: {
|
|
102
|
+
...determinismResult.summary,
|
|
103
|
+
runFingerprintMismatches: runFingerprintMismatches.length,
|
|
104
|
+
verifierErrors: verifierErrors.length,
|
|
105
|
+
topReasons: topReasons.slice(0, 10)
|
|
106
|
+
},
|
|
107
|
+
runsMeta: determinismResult.runsMeta,
|
|
108
|
+
runFingerprints,
|
|
109
|
+
runFingerprintMismatches,
|
|
110
|
+
verificationResults,
|
|
111
|
+
verifierErrors,
|
|
112
|
+
normalizationRulesApplied: [
|
|
113
|
+
'Stripped timestamps (startedAt, completedAt, detectedAt, etc.)',
|
|
114
|
+
'Stripped runId fields',
|
|
115
|
+
'Normalized absolute paths to relative',
|
|
116
|
+
'Normalized floating scores to 3 decimals',
|
|
117
|
+
'Sorted arrays by stable keys',
|
|
118
|
+
'Normalized evidence paths but preserved presence/absence',
|
|
119
|
+
],
|
|
120
|
+
diffs: determinismResult.diffs,
|
|
121
|
+
adaptiveEvents: determinismResult.adaptiveEvents || [],
|
|
122
|
+
stabilityScore: determinismResult.summary.stabilityScore,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
writeFileSync(reportPath, JSON.stringify(report, null, 2) + '\n');
|
|
126
|
+
|
|
127
|
+
return reportPath;
|
|
128
|
+
}
|
|
129
|
+
|
package/src/cli/util/env-url.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { assertExecutionBootstrapAllowed } from './bootstrap-guard.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Attempt to infer URL from environment variables and common dev configs
|
|
3
5
|
*/
|
|
4
6
|
export function tryResolveUrlFromEnv() {
|
|
7
|
+
// PHASE 21.6.1: Runtime guard - crash if called during inspection
|
|
8
|
+
assertExecutionBootstrapAllowed('tryResolveUrlFromEnv');
|
|
5
9
|
// Check common environment variables
|
|
6
10
|
const candidates = [
|
|
7
11
|
process.env.VERCEL_URL,
|
package/src/cli/util/events.js
CHANGED
|
@@ -5,6 +5,10 @@ export class RunEventEmitter {
|
|
|
5
5
|
constructor() {
|
|
6
6
|
this.events = [];
|
|
7
7
|
this.listeners = [];
|
|
8
|
+
this.heartbeatInterval = null;
|
|
9
|
+
this.heartbeatStartTime = null;
|
|
10
|
+
this.currentPhase = null;
|
|
11
|
+
this.heartbeatIntervalMs = 2500; // 2.5 seconds
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
on(event, handler) {
|
|
@@ -31,4 +35,76 @@ export class RunEventEmitter {
|
|
|
31
35
|
getEvents() {
|
|
32
36
|
return this.events;
|
|
33
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Start heartbeat for a phase
|
|
41
|
+
* @param {string} phase - Current phase name
|
|
42
|
+
* @param {boolean} jsonMode - Whether in JSON output mode
|
|
43
|
+
*/
|
|
44
|
+
startHeartbeat(phase, jsonMode = false) {
|
|
45
|
+
this.currentPhase = phase;
|
|
46
|
+
this.heartbeatStartTime = Date.now();
|
|
47
|
+
|
|
48
|
+
if (this.heartbeatInterval) {
|
|
49
|
+
clearInterval(this.heartbeatInterval);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.heartbeatInterval = setInterval(() => {
|
|
53
|
+
const elapsedMs = Date.now() - this.heartbeatStartTime;
|
|
54
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1000);
|
|
55
|
+
|
|
56
|
+
const heartbeatEvent = {
|
|
57
|
+
type: 'heartbeat',
|
|
58
|
+
phase: this.currentPhase,
|
|
59
|
+
elapsedMs,
|
|
60
|
+
elapsedSeconds,
|
|
61
|
+
timestamp: new Date().toISOString(),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Add to events array
|
|
65
|
+
this.events.push(heartbeatEvent);
|
|
66
|
+
|
|
67
|
+
// Emit to listeners
|
|
68
|
+
this.listeners.forEach(({ event: listenEvent, handler }) => {
|
|
69
|
+
if (listenEvent === 'heartbeat' || listenEvent === '*') {
|
|
70
|
+
if (jsonMode) {
|
|
71
|
+
// In JSON mode, emit as JSON line
|
|
72
|
+
handler(heartbeatEvent);
|
|
73
|
+
} else {
|
|
74
|
+
// Human-readable format: single line, overwrite-friendly
|
|
75
|
+
process.stdout.write(`\r…still working (phase=${this.currentPhase}, elapsed=${elapsedSeconds}s)`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}, this.heartbeatIntervalMs);
|
|
80
|
+
|
|
81
|
+
// CRITICAL: Unref the interval so it doesn't keep the process alive
|
|
82
|
+
// This allows tests to exit cleanly even if stopHeartbeat() is not called
|
|
83
|
+
if (this.heartbeatInterval && this.heartbeatInterval.unref) {
|
|
84
|
+
this.heartbeatInterval.unref();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Stop heartbeat
|
|
90
|
+
*/
|
|
91
|
+
stopHeartbeat() {
|
|
92
|
+
if (this.heartbeatInterval) {
|
|
93
|
+
clearInterval(this.heartbeatInterval);
|
|
94
|
+
this.heartbeatInterval = null;
|
|
95
|
+
}
|
|
96
|
+
// Clear the progress line in human mode
|
|
97
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
98
|
+
this.currentPhase = null;
|
|
99
|
+
this.heartbeatStartTime = null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Update current phase for heartbeat
|
|
104
|
+
* @param {string} phase - New phase name
|
|
105
|
+
*/
|
|
106
|
+
updatePhase(phase) {
|
|
107
|
+
this.currentPhase = phase;
|
|
108
|
+
this.heartbeatStartTime = Date.now();
|
|
109
|
+
}
|
|
34
110
|
}
|