@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,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.10 — Artifact Cross-Index
|
|
3
|
+
*
|
|
4
|
+
* Builds cross-index linking findingId to all related artifacts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readFileSync, existsSync, writeFileSync, readdirSync } from 'fs';
|
|
8
|
+
import { resolve, relative } from 'path';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build cross-index
|
|
12
|
+
*
|
|
13
|
+
* @param {string} projectDir - Project directory
|
|
14
|
+
* @param {string} runId - Run ID
|
|
15
|
+
* @returns {Object} Cross-index
|
|
16
|
+
*/
|
|
17
|
+
export function buildCrossIndex(projectDir, runId) {
|
|
18
|
+
const runDir = resolve(projectDir, '.verax', 'runs', runId);
|
|
19
|
+
|
|
20
|
+
if (!existsSync(runDir)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const index = {};
|
|
25
|
+
|
|
26
|
+
// Load findings
|
|
27
|
+
const findingsPath = resolve(runDir, 'findings.json');
|
|
28
|
+
if (!existsSync(findingsPath)) {
|
|
29
|
+
return {
|
|
30
|
+
runId,
|
|
31
|
+
findings: {},
|
|
32
|
+
summary: { total: 0 },
|
|
33
|
+
generatedAt: new Date().toISOString()
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const findings = JSON.parse(readFileSync(findingsPath, 'utf-8'));
|
|
38
|
+
const evidenceIndex = loadArtifact(runDir, 'evidence.index.json');
|
|
39
|
+
const decisionTrace = loadArtifact(runDir, 'decisions.trace.json');
|
|
40
|
+
const timeline = loadArtifact(runDir, 'run.timeline.json');
|
|
41
|
+
const failureLedger = loadArtifact(runDir, 'failure.ledger.json');
|
|
42
|
+
const performanceReport = loadArtifact(runDir, 'performance.report.json');
|
|
43
|
+
|
|
44
|
+
if (!Array.isArray(findings.findings)) {
|
|
45
|
+
return {
|
|
46
|
+
runId,
|
|
47
|
+
findings: {},
|
|
48
|
+
summary: { total: 0 },
|
|
49
|
+
generatedAt: new Date().toISOString()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for (const finding of findings.findings) {
|
|
54
|
+
const findingId = finding.findingId || finding.id || `finding-${Object.keys(index).length}`;
|
|
55
|
+
|
|
56
|
+
const entry = {
|
|
57
|
+
findingId,
|
|
58
|
+
type: finding.type || null,
|
|
59
|
+
status: finding.severity || finding.status || null,
|
|
60
|
+
|
|
61
|
+
// Evidence files
|
|
62
|
+
evidence: {
|
|
63
|
+
packageId: finding.evidencePackage?.id || null,
|
|
64
|
+
files: finding.evidencePackage?.files || [],
|
|
65
|
+
isComplete: finding.evidencePackage?.isComplete || false,
|
|
66
|
+
beforeScreenshot: finding.evidence?.before || null,
|
|
67
|
+
afterScreenshot: finding.evidence?.after || null
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Confidence reasons
|
|
71
|
+
confidence: {
|
|
72
|
+
level: finding.confidenceLevel || null,
|
|
73
|
+
score: finding.confidence !== undefined ? finding.confidence : null,
|
|
74
|
+
reasons: finding.confidenceReasons || [],
|
|
75
|
+
trace: decisionTrace?.findings?.find(t => t.findingId === findingId)?.confidence || null
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Guardrails rules
|
|
79
|
+
guardrails: {
|
|
80
|
+
applied: finding.guardrails?.appliedRules?.map(r => ({
|
|
81
|
+
id: r.id || r,
|
|
82
|
+
category: r.category || null,
|
|
83
|
+
action: r.action || null
|
|
84
|
+
})) || [],
|
|
85
|
+
finalDecision: finding.guardrails?.finalDecision || null,
|
|
86
|
+
contradictions: finding.guardrails?.contradictions || [],
|
|
87
|
+
trace: decisionTrace?.findings?.find(t => t.findingId === findingId)?.guardrails || null
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Failures (if any related)
|
|
91
|
+
failures: failureLedger?.failures?.filter(f =>
|
|
92
|
+
f.context?.findingId === findingId ||
|
|
93
|
+
f.message?.includes(findingId)
|
|
94
|
+
).map(f => ({
|
|
95
|
+
code: f.code,
|
|
96
|
+
message: f.message,
|
|
97
|
+
severity: f.severity,
|
|
98
|
+
timestamp: f.timestamp
|
|
99
|
+
})) || [],
|
|
100
|
+
|
|
101
|
+
// Performance impacts (if any)
|
|
102
|
+
performance: performanceReport?.violations?.some(v =>
|
|
103
|
+
v.message?.includes(findingId)
|
|
104
|
+
) ? {
|
|
105
|
+
impacted: true,
|
|
106
|
+
violations: performanceReport.violations.filter(v =>
|
|
107
|
+
v.message?.includes(findingId)
|
|
108
|
+
)
|
|
109
|
+
} : null,
|
|
110
|
+
|
|
111
|
+
// Timeline entries
|
|
112
|
+
timeline: timeline?.events?.filter(e =>
|
|
113
|
+
e.data?.findingId === findingId ||
|
|
114
|
+
(e.event === 'guardrails_applied' && e.data?.findingId === findingId) ||
|
|
115
|
+
(e.event === 'evidence_enforced' && e.data?.findingId === findingId)
|
|
116
|
+
).map(e => ({
|
|
117
|
+
timestamp: e.timestamp,
|
|
118
|
+
phase: e.phase,
|
|
119
|
+
event: e.event,
|
|
120
|
+
data: e.data
|
|
121
|
+
})) || []
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
index[findingId] = entry;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
runId,
|
|
129
|
+
findings: index,
|
|
130
|
+
summary: {
|
|
131
|
+
total: Object.keys(index).length,
|
|
132
|
+
withEvidence: Object.values(index).filter(e => e.evidence.files.length > 0).length,
|
|
133
|
+
withGuardrails: Object.values(index).filter(e => e.guardrails.applied.length > 0).length,
|
|
134
|
+
withFailures: Object.values(index).filter(e => e.failures.length > 0).length,
|
|
135
|
+
withTimeline: Object.values(index).filter(e => e.timeline.length > 0).length
|
|
136
|
+
},
|
|
137
|
+
generatedAt: new Date().toISOString()
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Load artifact JSON
|
|
143
|
+
*/
|
|
144
|
+
function loadArtifact(runDir, filename) {
|
|
145
|
+
const path = resolve(runDir, filename);
|
|
146
|
+
if (!existsSync(path)) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Write cross-index to file
|
|
158
|
+
*
|
|
159
|
+
* @param {string} projectDir - Project directory
|
|
160
|
+
* @param {string} runId - Run ID
|
|
161
|
+
* @param {Object} index - Cross-index
|
|
162
|
+
* @returns {string} Path to written file
|
|
163
|
+
*/
|
|
164
|
+
export function writeCrossIndex(projectDir, runId, index) {
|
|
165
|
+
const runDir = resolve(projectDir, '.verax', 'runs', runId);
|
|
166
|
+
const outputPath = resolve(runDir, 'artifacts.index.json');
|
|
167
|
+
writeFileSync(outputPath, JSON.stringify(index, null, 2), 'utf-8');
|
|
168
|
+
return outputPath;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Load cross-index from file
|
|
173
|
+
*
|
|
174
|
+
* @param {string} projectDir - Project directory
|
|
175
|
+
* @param {string} runId - Run ID
|
|
176
|
+
* @returns {Object|null} Cross-index or null
|
|
177
|
+
*/
|
|
178
|
+
export function loadCrossIndex(projectDir, runId) {
|
|
179
|
+
const runDir = resolve(projectDir, '.verax', 'runs', runId);
|
|
180
|
+
const indexPath = resolve(runDir, 'artifacts.index.json');
|
|
181
|
+
|
|
182
|
+
if (!existsSync(indexPath)) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
return JSON.parse(readFileSync(indexPath, 'utf-8'));
|
|
188
|
+
} catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.10 — Human Summary
|
|
3
|
+
*
|
|
4
|
+
* Generates human-readable summary for Enterprise UX.
|
|
5
|
+
* Clear, direct, no marketing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync } from 'fs';
|
|
9
|
+
import { resolve } from 'path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Load artifact JSON
|
|
13
|
+
*/
|
|
14
|
+
function loadArtifact(runDir, filename) {
|
|
15
|
+
const path = resolve(runDir, filename);
|
|
16
|
+
if (!existsSync(path)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Generate human summary
|
|
28
|
+
*
|
|
29
|
+
* @param {string} projectDir - Project directory
|
|
30
|
+
* @param {string} runId - Run ID
|
|
31
|
+
* @returns {Object} Human summary
|
|
32
|
+
*/
|
|
33
|
+
export async function generateHumanSummary(projectDir, runId) {
|
|
34
|
+
const runDir = resolve(projectDir, '.verax', 'runs', runId);
|
|
35
|
+
|
|
36
|
+
if (!existsSync(runDir)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const summary = loadArtifact(runDir, 'summary.json');
|
|
41
|
+
const findings = loadArtifact(runDir, 'findings.json');
|
|
42
|
+
const determinism = loadArtifact(runDir, 'decisions.json');
|
|
43
|
+
const performanceReport = loadArtifact(runDir, 'performance.report.json');
|
|
44
|
+
|
|
45
|
+
// Security reports are in release/ directory (project root)
|
|
46
|
+
// Use projectDir parameter directly (already resolved)
|
|
47
|
+
const releaseDir = resolve(projectDir, 'release');
|
|
48
|
+
const securitySecrets = loadArtifact(releaseDir, 'security.secrets.report.json');
|
|
49
|
+
const securityVuln = loadArtifact(releaseDir, 'security.vuln.report.json');
|
|
50
|
+
|
|
51
|
+
const gaStatus = loadArtifact(runDir, 'ga.status.json');
|
|
52
|
+
|
|
53
|
+
if (!summary) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const findingsArray = Array.isArray(findings?.findings) ? findings.findings : [];
|
|
58
|
+
const confirmedFindings = findingsArray.filter(f => (f.severity || f.status) === 'CONFIRMED');
|
|
59
|
+
const suspectedFindings = findingsArray.filter(f => (f.severity || f.status) === 'SUSPECTED');
|
|
60
|
+
|
|
61
|
+
// What VERAX is confident about
|
|
62
|
+
const confident = {
|
|
63
|
+
findings: confirmedFindings.length,
|
|
64
|
+
message: confirmedFindings.length > 0
|
|
65
|
+
? `${confirmedFindings.length} finding(s) with complete evidence`
|
|
66
|
+
: 'No findings with complete evidence',
|
|
67
|
+
details: confirmedFindings.map(f => ({
|
|
68
|
+
type: f.type,
|
|
69
|
+
outcome: f.outcome,
|
|
70
|
+
confidence: f.confidenceLevel || 'UNKNOWN'
|
|
71
|
+
}))
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// What VERAX is NOT confident about
|
|
75
|
+
const notConfident = {
|
|
76
|
+
findings: suspectedFindings.length,
|
|
77
|
+
message: suspectedFindings.length > 0
|
|
78
|
+
? `${suspectedFindings.length} finding(s) with incomplete evidence (SUSPECTED)`
|
|
79
|
+
: 'No findings with incomplete evidence',
|
|
80
|
+
details: suspectedFindings.map(f => ({
|
|
81
|
+
type: f.type,
|
|
82
|
+
outcome: f.outcome,
|
|
83
|
+
confidence: f.confidenceLevel || 'UNKNOWN',
|
|
84
|
+
missingEvidence: f.evidencePackage?.isComplete === false
|
|
85
|
+
}))
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Why some things were skipped
|
|
89
|
+
const skips = [];
|
|
90
|
+
if (summary.truth?.observe?.skips) {
|
|
91
|
+
for (const skip of summary.truth.observe.skips) {
|
|
92
|
+
skips.push({
|
|
93
|
+
reason: skip.reason || skip.code || 'UNKNOWN',
|
|
94
|
+
count: skip.count || 1,
|
|
95
|
+
message: skip.message || `Skipped: ${skip.reason || skip.code}`
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Determinism verdict
|
|
101
|
+
let determinismVerdict = 'UNKNOWN';
|
|
102
|
+
if (determinism) {
|
|
103
|
+
try {
|
|
104
|
+
const { DecisionRecorder } = await import('../../../core/determinism-model.js');
|
|
105
|
+
const recorder = DecisionRecorder.fromExport(determinism);
|
|
106
|
+
const { computeDeterminismVerdict } = await import('../../../core/determinism/contract.js');
|
|
107
|
+
const verdict = computeDeterminismVerdict(recorder);
|
|
108
|
+
determinismVerdict = verdict.verdict;
|
|
109
|
+
} catch {
|
|
110
|
+
determinismVerdict = summary.determinism?.verdict || 'UNKNOWN';
|
|
111
|
+
}
|
|
112
|
+
} else if (summary.determinism) {
|
|
113
|
+
determinismVerdict = summary.determinism.verdict || 'UNKNOWN';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Performance verdict
|
|
117
|
+
const performanceVerdict = performanceReport?.verdict || 'UNKNOWN';
|
|
118
|
+
const performanceOk = performanceReport?.ok !== false;
|
|
119
|
+
|
|
120
|
+
// Security verdict
|
|
121
|
+
const securityOk = !securitySecrets?.hasSecrets &&
|
|
122
|
+
!securityVuln?.blocking &&
|
|
123
|
+
(securitySecrets !== null || securityVuln !== null); // At least one report exists
|
|
124
|
+
|
|
125
|
+
// GA verdict
|
|
126
|
+
const gaReady = gaStatus?.gaReady === true;
|
|
127
|
+
const gaVerdict = gaReady ? 'GA-READY' : (gaStatus ? 'GA-BLOCKED' : 'UNKNOWN');
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
runId,
|
|
131
|
+
whatWeKnow: {
|
|
132
|
+
confident: confident,
|
|
133
|
+
notConfident: notConfident,
|
|
134
|
+
skips: skips.length > 0 ? {
|
|
135
|
+
total: skips.reduce((sum, s) => sum + s.count, 0),
|
|
136
|
+
reasons: skips
|
|
137
|
+
} : null
|
|
138
|
+
},
|
|
139
|
+
verdicts: {
|
|
140
|
+
determinism: {
|
|
141
|
+
verdict: determinismVerdict,
|
|
142
|
+
message: determinismVerdict === 'DETERMINISTIC'
|
|
143
|
+
? 'Run was reproducible (same inputs = same outputs)'
|
|
144
|
+
: determinismVerdict === 'NON_DETERMINISTIC'
|
|
145
|
+
? 'Run was not reproducible (adaptive events detected)'
|
|
146
|
+
: 'Determinism not evaluated'
|
|
147
|
+
},
|
|
148
|
+
performance: {
|
|
149
|
+
verdict: performanceVerdict,
|
|
150
|
+
ok: performanceOk,
|
|
151
|
+
message: performanceOk
|
|
152
|
+
? 'Performance within budget'
|
|
153
|
+
: performanceReport?.violations?.length > 0
|
|
154
|
+
? `${performanceReport.violations.length} BLOCKING performance violation(s)`
|
|
155
|
+
: 'Performance not evaluated'
|
|
156
|
+
},
|
|
157
|
+
security: {
|
|
158
|
+
ok: securityOk,
|
|
159
|
+
message: securityOk
|
|
160
|
+
? 'Security baseline passed'
|
|
161
|
+
: securitySecrets?.hasSecrets
|
|
162
|
+
? 'Secrets detected'
|
|
163
|
+
: securityVuln?.blocking
|
|
164
|
+
? 'Critical vulnerabilities detected'
|
|
165
|
+
: 'Security not evaluated'
|
|
166
|
+
},
|
|
167
|
+
ga: {
|
|
168
|
+
verdict: gaVerdict,
|
|
169
|
+
ready: gaReady,
|
|
170
|
+
message: gaReady
|
|
171
|
+
? 'GA-READY: All gates passed'
|
|
172
|
+
: gaStatus
|
|
173
|
+
? `GA-BLOCKED: ${gaStatus.blockers?.length || 0} blocker(s)`
|
|
174
|
+
: 'GA not evaluated'
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
generatedAt: new Date().toISOString()
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Format human summary for CLI display
|
|
183
|
+
*
|
|
184
|
+
* @param {Object} summary - Human summary
|
|
185
|
+
* @returns {string} Formatted string
|
|
186
|
+
*/
|
|
187
|
+
export function formatHumanSummary(summary) {
|
|
188
|
+
if (!summary) {
|
|
189
|
+
return 'Summary: Not available';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const lines = [];
|
|
193
|
+
lines.push('\n' + '='.repeat(80));
|
|
194
|
+
lines.push('HUMAN SUMMARY');
|
|
195
|
+
lines.push('='.repeat(80));
|
|
196
|
+
|
|
197
|
+
// What we know
|
|
198
|
+
lines.push('\nWhat VERAX is confident about:');
|
|
199
|
+
lines.push(` ${summary.whatWeKnow.confident.message}`);
|
|
200
|
+
|
|
201
|
+
lines.push('\nWhat VERAX is NOT confident about:');
|
|
202
|
+
lines.push(` ${summary.whatWeKnow.notConfident.message}`);
|
|
203
|
+
|
|
204
|
+
if (summary.whatWeKnow.skips) {
|
|
205
|
+
lines.push('\nWhy some things were skipped:');
|
|
206
|
+
for (const skip of summary.whatWeKnow.skips.reasons) {
|
|
207
|
+
lines.push(` - ${skip.message} (${skip.count}x)`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Verdicts
|
|
212
|
+
lines.push('\nVerdicts:');
|
|
213
|
+
lines.push(` Determinism: ${summary.verdicts.determinism.verdict} - ${summary.verdicts.determinism.message}`);
|
|
214
|
+
lines.push(` Performance: ${summary.verdicts.performance.verdict} - ${summary.verdicts.performance.message}`);
|
|
215
|
+
lines.push(` Security: ${summary.verdicts.security.ok ? 'OK' : 'BLOCKED'} - ${summary.verdicts.security.message}`);
|
|
216
|
+
lines.push(` GA: ${summary.verdicts.ga.verdict} - ${summary.verdicts.ga.message}`);
|
|
217
|
+
|
|
218
|
+
lines.push('='.repeat(80) + '\n');
|
|
219
|
+
|
|
220
|
+
return lines.join('\n');
|
|
221
|
+
}
|
|
222
|
+
|