@veraxhq/verax 0.2.1 → 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 +10 -6
- package/bin/verax.js +11 -11
- package/package.json +29 -8
- package/src/cli/commands/baseline.js +103 -0
- package/src/cli/commands/default.js +51 -6
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +246 -0
- package/src/cli/commands/gates.js +95 -0
- package/src/cli/commands/inspect.js +4 -2
- package/src/cli/commands/release-check.js +215 -0
- package/src/cli/commands/run.js +45 -6
- package/src/cli/commands/security-check.js +212 -0
- package/src/cli/commands/truth.js +113 -0
- package/src/cli/entry.js +30 -20
- 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 +544 -0
- package/src/cli/util/ast-network-detector.js +603 -0
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +602 -0
- package/src/cli/util/atomic-write.js +12 -1
- package/src/cli/util/bootstrap-guard.js +86 -0
- 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 +124 -0
- package/src/cli/util/determinism-writer.js +129 -0
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +151 -5
- package/src/cli/util/findings-writer.js +3 -0
- 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 -0
- 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 -0
- package/src/cli/util/project-discovery.js +284 -0
- package/src/cli/util/project-writer.js +2 -0
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-resolver.js +64 -0
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/source-requirement.js +55 -0
- package/src/cli/util/summary-writer.js +2 -0
- 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 +146 -0
- package/src/cli/util/svelte-state-detector.js +242 -0
- 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 +178 -0
- package/src/cli/util/vue-sfc-extractor.js +161 -0
- package/src/cli/util/vue-state-detector.js +215 -0
- 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/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +139 -0
- package/src/verax/core/artifacts/verifier.js +990 -0
- package/src/verax/core/baseline/baseline.enforcer.js +137 -0
- package/src/verax/core/baseline/baseline.snapshot.js +233 -0
- package/src/verax/core/capabilities/gates.js +505 -0
- package/src/verax/core/capabilities/registry.js +475 -0
- package/src/verax/core/confidence/confidence-compute.js +144 -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 +80 -0
- package/src/verax/core/confidence/confidence.schema.js +94 -0
- package/src/verax/core/confidence-engine-refactor.js +489 -0
- package/src/verax/core/confidence-engine.js +625 -0
- package/src/verax/core/contracts/index.js +29 -0
- package/src/verax/core/contracts/types.js +186 -0
- package/src/verax/core/contracts/validators.js +456 -0
- package/src/verax/core/decisions/decision.trace.js +278 -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 +405 -0
- package/src/verax/core/determinism/engine.js +222 -0
- package/src/verax/core/determinism/finding-identity.js +149 -0
- package/src/verax/core/determinism/normalize.js +466 -0
- package/src/verax/core/determinism/report-writer.js +93 -0
- package/src/verax/core/determinism/run-fingerprint.js +123 -0
- package/src/verax/core/dynamic-route-intelligence.js +529 -0
- package/src/verax/core/evidence/evidence-capture-service.js +308 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +166 -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 +192 -0
- package/src/verax/core/failures/exit-codes.js +88 -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 +133 -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 +435 -0
- package/src/verax/core/ga/ga.enforcer.js +87 -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 +84 -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 +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 +318 -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 +200 -0
- package/src/verax/core/pipeline-tracker.js +243 -0
- package/src/verax/core/product-definition.js +127 -0
- package/src/verax/core/release/provenance.builder.js +130 -0
- package/src/verax/core/release/release-report-writer.js +40 -0
- package/src/verax/core/release/release.enforcer.js +164 -0
- package/src/verax/core/release/reproducibility.check.js +222 -0
- package/src/verax/core/release/sbom.builder.js +292 -0
- 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 +195 -0
- package/src/verax/core/report/human-summary.js +362 -0
- package/src/verax/core/route-intelligence.js +420 -0
- 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 +329 -0
- package/src/verax/core/security/security-report.js +50 -0
- package/src/verax/core/security/security.enforcer.js +128 -0
- package/src/verax/core/security/supplychain.defaults.json +38 -0
- package/src/verax/core/security/supplychain.policy.js +334 -0
- package/src/verax/core/security/vuln.scan.js +265 -0
- package/src/verax/core/truth/truth.certificate.js +252 -0
- package/src/verax/core/ui-feedback-intelligence.js +481 -0
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +62 -34
- package/src/verax/detect/confidence-helper.js +34 -0
- package/src/verax/detect/dynamic-route-findings.js +338 -0
- package/src/verax/detect/expectation-chain-detector.js +417 -0
- package/src/verax/detect/expectation-model.js +2 -2
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +131 -35
- 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 +46 -5
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +558 -0
- 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 +219 -0
- 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 +207 -0
- package/src/verax/detect/view-switch-correlator.js +242 -0
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +4 -0
- 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 +3 -0
- 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/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 +51 -155
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -513
- 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 +205 -0
- package/src/verax/observe/observe-helpers.js +192 -0
- package/src/verax/observe/observe-runner.js +230 -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/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-feedback-detector.js +742 -0
- package/src/verax/scan-summary-writer.js +2 -0
- package/src/verax/shared/artifact-manager.js +25 -5
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/css-spinner-rules.js +204 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/view-switch-rules.js +208 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.6 — GA Readiness Contract
|
|
3
|
+
*
|
|
4
|
+
* Hard gate that determines if VERAX is Enterprise-GA ready.
|
|
5
|
+
* No human judgment, only code decides.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { evaluateAllCapabilityGates, buildGateContext } from '../capabilities/gates.js';
|
|
9
|
+
import { CAPABILITY_MATURITY as _CAPABILITY_MATURITY } from '../capabilities/gates.js';
|
|
10
|
+
import { verifyRun } from '../artifacts/verifier.js';
|
|
11
|
+
import { checkSecurityStatus } from '../security/security.enforcer.js';
|
|
12
|
+
import { readFileSync, existsSync } from 'fs';
|
|
13
|
+
import { resolve } from 'path';
|
|
14
|
+
import { isBaselineFrozen as _isBaselineFrozen, enforceBaseline as _enforceBaseline } from '../baseline/baseline.enforcer.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* GA Blocker Codes
|
|
18
|
+
*/
|
|
19
|
+
export const GA_BLOCKER_CODE = {
|
|
20
|
+
NO_RUNS_FOUND: 'GA_NO_RUNS_FOUND',
|
|
21
|
+
CAPABILITY_GATES_FAILED: 'GA_CAPABILITY_GATES_FAILED',
|
|
22
|
+
FRAMEWORK_WAVES_UNSTABLE: 'GA_FRAMEWORK_WAVES_UNSTABLE',
|
|
23
|
+
EVIDENCE_LAW_VIOLATION: 'GA_EVIDENCE_LAW_VIOLATION',
|
|
24
|
+
DETERMINISM_NOT_ACCEPTED: 'GA_DETERMINISM_NOT_ACCEPTED',
|
|
25
|
+
BLOCKING_FAILURES: 'GA_BLOCKING_FAILURES',
|
|
26
|
+
DEGRADED_FAILURES: 'GA_DEGRADED_FAILURES',
|
|
27
|
+
INTERNAL_FAILURES: 'GA_INTERNAL_FAILURES',
|
|
28
|
+
CONTRACT_FAILURES: 'GA_CONTRACT_FAILURES',
|
|
29
|
+
POLICY_INVALID: 'GA_POLICY_INVALID',
|
|
30
|
+
ARTIFACT_VERIFIER_FAILED: 'GA_ARTIFACT_VERIFIER_FAILED',
|
|
31
|
+
SECURITY_NOT_CHECKED: 'GA_SECURITY_NOT_CHECKED',
|
|
32
|
+
SECURITY_BLOCKED: 'GA_SECURITY_BLOCKED',
|
|
33
|
+
PERFORMANCE_BLOCKED: 'GA_PERFORMANCE_BLOCKED',
|
|
34
|
+
BASELINE_DRIFT: 'GA_BASELINE_DRIFT'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* GA Warning Codes
|
|
39
|
+
*/
|
|
40
|
+
export const GA_WARNING_CODE = {
|
|
41
|
+
WARNINGS_IN_LEDGER: 'GA_WARNINGS_IN_LEDGER',
|
|
42
|
+
NON_DETERMINISTIC_ACCEPTED: 'GA_NON_DETERMINISTIC_ACCEPTED',
|
|
43
|
+
SECURITY_NOT_CHECKED: 'GA_SECURITY_NOT_CHECKED'
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {Object} GA_BLOCKER
|
|
48
|
+
* @property {string} code - Blocker code
|
|
49
|
+
* @property {string} message - Human-readable message
|
|
50
|
+
* @property {Object} context - Additional context
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @typedef {Object} GA_WARNING
|
|
55
|
+
* @property {string} code - Warning code
|
|
56
|
+
* @property {string} message - Human-readable message
|
|
57
|
+
* @property {Object} context - Additional context
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {Object} GAReadinessResult
|
|
62
|
+
* @property {boolean} pass - Whether GA-ready
|
|
63
|
+
* @property {GA_BLOCKER[]} blockers - List of blockers
|
|
64
|
+
* @property {GA_WARNING[]} warnings - List of warnings
|
|
65
|
+
* @property {Object} summary - Summary of evaluation
|
|
66
|
+
* @property {Object} inputs - Inputs used for evaluation
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if determinism acceptance policy exists and is valid
|
|
71
|
+
*
|
|
72
|
+
* @param {string} projectDir - Project directory
|
|
73
|
+
* @returns {Object|null} Acceptance policy or null
|
|
74
|
+
*/
|
|
75
|
+
function loadDeterminismAcceptancePolicy(projectDir) {
|
|
76
|
+
const policyPath = resolve(projectDir, 'determinism.acceptance.json');
|
|
77
|
+
if (!existsSync(policyPath)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const content = readFileSync(policyPath, 'utf-8');
|
|
83
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
84
|
+
const policy = JSON.parse(content);
|
|
85
|
+
|
|
86
|
+
// Validate policy structure
|
|
87
|
+
if (!policy.allowedAdaptiveEvents || !Array.isArray(policy.allowedAdaptiveEvents)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!policy.justification || typeof policy.justification !== 'string') {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return policy;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Check if determinism verdict is accepted
|
|
103
|
+
*
|
|
104
|
+
* @param {string} determinismVerdict - Determinism verdict (DETERMINISTIC | NON_DETERMINISTIC)
|
|
105
|
+
* @param {Object|null} acceptancePolicy - Determinism acceptance policy
|
|
106
|
+
* @returns {boolean} Whether verdict is accepted
|
|
107
|
+
*/
|
|
108
|
+
function isDeterminismAccepted(determinismVerdict, acceptancePolicy) {
|
|
109
|
+
if (determinismVerdict === 'DETERMINISTIC') {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (determinismVerdict === 'NON_DETERMINISTIC' && acceptancePolicy) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if all framework waves are STABLE
|
|
122
|
+
*
|
|
123
|
+
* @param {Object} gateResult - Capability gates result
|
|
124
|
+
* @returns {Object} { allStable: boolean, unstable: string[] }
|
|
125
|
+
*/
|
|
126
|
+
function checkFrameworkWavesStable(gateResult) {
|
|
127
|
+
const unstable = [];
|
|
128
|
+
|
|
129
|
+
// Check all capabilities marked as STABLE actually pass gates
|
|
130
|
+
for (const [capabilityId, result] of Object.entries(gateResult.perCapability || {})) {
|
|
131
|
+
// This is a simplified check - in reality, we'd need to check the registry
|
|
132
|
+
// to see which capabilities are marked as STABLE
|
|
133
|
+
// For now, we check if any capability fails gates
|
|
134
|
+
if (!result.pass) {
|
|
135
|
+
unstable.push(capabilityId);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
allStable: unstable.length === 0,
|
|
141
|
+
unstable
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Evaluate GA Readiness
|
|
147
|
+
*
|
|
148
|
+
* @param {Object} context - Evaluation context
|
|
149
|
+
* @param {string} context.projectDir - Project directory
|
|
150
|
+
* @param {string} [context.runId] - Run ID (for artifact verification)
|
|
151
|
+
* @param {string} [context.determinismVerdict] - Determinism verdict
|
|
152
|
+
* @param {boolean} [context.evidenceLawViolated] - Whether Evidence Law was violated
|
|
153
|
+
* @param {Object} [context.failureLedger] - Failure ledger summary
|
|
154
|
+
* @returns {Promise<GAReadinessResult>} GA readiness result
|
|
155
|
+
*/
|
|
156
|
+
export async function evaluateGAReadiness(context) {
|
|
157
|
+
const {
|
|
158
|
+
projectDir,
|
|
159
|
+
runId = null,
|
|
160
|
+
determinismVerdict = null,
|
|
161
|
+
evidenceLawViolated = false,
|
|
162
|
+
failureLedger = null
|
|
163
|
+
} = context;
|
|
164
|
+
|
|
165
|
+
const blockers = [];
|
|
166
|
+
const warnings = [];
|
|
167
|
+
const inputs = {
|
|
168
|
+
gates: null,
|
|
169
|
+
determinism: determinismVerdict || 'UNKNOWN',
|
|
170
|
+
evidenceLaw: evidenceLawViolated ? 'VIOLATED' : 'ENFORCED',
|
|
171
|
+
failureLedger: failureLedger || { total: 0, bySeverity: {} },
|
|
172
|
+
artifactVerifier: null
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// 1. Phase 19: Capability Gates - 100% PASS required
|
|
176
|
+
let gateResult = null;
|
|
177
|
+
try {
|
|
178
|
+
const gateContext = await buildGateContext({ projectRoot: projectDir });
|
|
179
|
+
gateResult = evaluateAllCapabilityGates(gateContext);
|
|
180
|
+
inputs.gates = gateResult.pass ? 'PASS' : 'FAIL';
|
|
181
|
+
|
|
182
|
+
if (!gateResult.pass) {
|
|
183
|
+
blockers.push({
|
|
184
|
+
code: GA_BLOCKER_CODE.CAPABILITY_GATES_FAILED,
|
|
185
|
+
message: `Capability gates failed: ${gateResult.summary.fail} of ${gateResult.summary.total} capabilities failed`,
|
|
186
|
+
context: {
|
|
187
|
+
total: gateResult.summary.total,
|
|
188
|
+
pass: gateResult.summary.pass,
|
|
189
|
+
fail: gateResult.summary.fail,
|
|
190
|
+
failures: gateResult.summary.allFailures
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
} catch (error) {
|
|
195
|
+
blockers.push({
|
|
196
|
+
code: GA_BLOCKER_CODE.CAPABILITY_GATES_FAILED,
|
|
197
|
+
message: `Failed to evaluate capability gates: ${error.message}`,
|
|
198
|
+
context: { error: error.message }
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 2. Phase 20: Framework Waves - ALL STABLE required
|
|
203
|
+
if (gateResult) {
|
|
204
|
+
const wavesCheck = checkFrameworkWavesStable(gateResult);
|
|
205
|
+
inputs.frameworkWaves = wavesCheck.allStable ? 'ALL_STABLE' : 'UNSTABLE';
|
|
206
|
+
|
|
207
|
+
if (!wavesCheck.allStable) {
|
|
208
|
+
blockers.push({
|
|
209
|
+
code: GA_BLOCKER_CODE.FRAMEWORK_WAVES_UNSTABLE,
|
|
210
|
+
message: `Framework waves not stable: ${wavesCheck.unstable.length} capabilities unstable`,
|
|
211
|
+
context: {
|
|
212
|
+
unstable: wavesCheck.unstable
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 3. Evidence Law - No violations allowed
|
|
219
|
+
if (evidenceLawViolated) {
|
|
220
|
+
blockers.push({
|
|
221
|
+
code: GA_BLOCKER_CODE.EVIDENCE_LAW_VIOLATION,
|
|
222
|
+
message: 'Evidence Law violated: CONFIRMED findings with incomplete evidence',
|
|
223
|
+
context: {}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 4. Determinism - Either DETERMINISTIC or explicitly accepted
|
|
228
|
+
const acceptancePolicy = loadDeterminismAcceptancePolicy(projectDir);
|
|
229
|
+
if (determinismVerdict) {
|
|
230
|
+
if (!isDeterminismAccepted(determinismVerdict, acceptancePolicy)) {
|
|
231
|
+
blockers.push({
|
|
232
|
+
code: GA_BLOCKER_CODE.DETERMINISM_NOT_ACCEPTED,
|
|
233
|
+
message: `NON_DETERMINISTIC execution without acceptance policy`,
|
|
234
|
+
context: {
|
|
235
|
+
verdict: determinismVerdict,
|
|
236
|
+
hasPolicy: !!acceptancePolicy
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
} else if (determinismVerdict === 'NON_DETERMINISTIC' && acceptancePolicy) {
|
|
240
|
+
warnings.push({
|
|
241
|
+
code: GA_WARNING_CODE.NON_DETERMINISTIC_ACCEPTED,
|
|
242
|
+
message: `NON_DETERMINISTIC execution accepted via policy: ${acceptancePolicy.justification}`,
|
|
243
|
+
context: {
|
|
244
|
+
allowedEvents: acceptancePolicy.allowedAdaptiveEvents
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 5. Failure Ledger - BLOCKING = 0, DEGRADED = 0 required
|
|
251
|
+
if (failureLedger) {
|
|
252
|
+
const blockingCount = failureLedger.bySeverity?.BLOCKING || 0;
|
|
253
|
+
const degradedCount = failureLedger.bySeverity?.DEGRADED || 0;
|
|
254
|
+
const warningCount = failureLedger.bySeverity?.WARNING || 0;
|
|
255
|
+
|
|
256
|
+
if (blockingCount > 0) {
|
|
257
|
+
blockers.push({
|
|
258
|
+
code: GA_BLOCKER_CODE.BLOCKING_FAILURES,
|
|
259
|
+
message: `${blockingCount} BLOCKING failure(s) in failure ledger`,
|
|
260
|
+
context: {
|
|
261
|
+
count: blockingCount
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (degradedCount > 0) {
|
|
267
|
+
blockers.push({
|
|
268
|
+
code: GA_BLOCKER_CODE.DEGRADED_FAILURES,
|
|
269
|
+
message: `${degradedCount} DEGRADED failure(s) in failure ledger`,
|
|
270
|
+
context: {
|
|
271
|
+
count: degradedCount
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Check for INTERNAL or CONTRACT failures
|
|
277
|
+
const internalCount = failureLedger.byCategory?.INTERNAL || 0;
|
|
278
|
+
const contractCount = failureLedger.byCategory?.CONTRACT || 0;
|
|
279
|
+
|
|
280
|
+
if (internalCount > 0) {
|
|
281
|
+
blockers.push({
|
|
282
|
+
code: GA_BLOCKER_CODE.INTERNAL_FAILURES,
|
|
283
|
+
message: `${internalCount} INTERNAL failure(s) in failure ledger`,
|
|
284
|
+
context: {
|
|
285
|
+
count: internalCount
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (contractCount > 0) {
|
|
291
|
+
blockers.push({
|
|
292
|
+
code: GA_BLOCKER_CODE.CONTRACT_FAILURES,
|
|
293
|
+
message: `${contractCount} CONTRACT failure(s) in failure ledger`,
|
|
294
|
+
context: {
|
|
295
|
+
count: contractCount
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (warningCount > 0) {
|
|
301
|
+
warnings.push({
|
|
302
|
+
code: GA_WARNING_CODE.WARNINGS_IN_LEDGER,
|
|
303
|
+
message: `${warningCount} WARNING failure(s) in failure ledger`,
|
|
304
|
+
context: {
|
|
305
|
+
count: warningCount
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 6. Policies - All must be valid and loaded
|
|
312
|
+
try {
|
|
313
|
+
const { loadGuardrailsPolicy } = await import('../guardrails/policy.loader.js');
|
|
314
|
+
const { loadConfidencePolicy } = await import('../confidence/confidence.loader.js');
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
loadGuardrailsPolicy();
|
|
318
|
+
} catch (error) {
|
|
319
|
+
blockers.push({
|
|
320
|
+
code: GA_BLOCKER_CODE.POLICY_INVALID,
|
|
321
|
+
message: `Guardrails policy invalid: ${error.message}`,
|
|
322
|
+
context: { error: error.message }
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
loadConfidencePolicy();
|
|
328
|
+
} catch (error) {
|
|
329
|
+
blockers.push({
|
|
330
|
+
code: GA_BLOCKER_CODE.POLICY_INVALID,
|
|
331
|
+
message: `Confidence policy invalid: ${error.message}`,
|
|
332
|
+
context: { error: error.message }
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
} catch (error) {
|
|
336
|
+
blockers.push({
|
|
337
|
+
code: GA_BLOCKER_CODE.POLICY_INVALID,
|
|
338
|
+
message: `Failed to load policies: ${error.message}`,
|
|
339
|
+
context: { error: error.message }
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 7. Artifact Verifier - Must pass with no blocking errors
|
|
344
|
+
if (runId) {
|
|
345
|
+
try {
|
|
346
|
+
const runDir = resolve(projectDir, '.verax', 'runs', runId);
|
|
347
|
+
const verification = verifyRun(runDir);
|
|
348
|
+
inputs.artifactVerifier = verification.ok ? 'PASS' : 'FAIL';
|
|
349
|
+
|
|
350
|
+
if (!verification.ok) {
|
|
351
|
+
blockers.push({
|
|
352
|
+
code: GA_BLOCKER_CODE.ARTIFACT_VERIFIER_FAILED,
|
|
353
|
+
message: `Artifact verifier failed: ${verification.errors.length} error(s)`,
|
|
354
|
+
context: {
|
|
355
|
+
errors: verification.errors,
|
|
356
|
+
warnings: verification.warnings
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
} catch (error) {
|
|
361
|
+
blockers.push({
|
|
362
|
+
code: GA_BLOCKER_CODE.ARTIFACT_VERIFIER_FAILED,
|
|
363
|
+
message: `Failed to verify artifacts: ${error.message}`,
|
|
364
|
+
context: { error: error.message }
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 8. Security Baseline (PHASE 21.8) - SECURITY-OK required
|
|
370
|
+
try {
|
|
371
|
+
const securityCheck = checkSecurityStatus(projectDir);
|
|
372
|
+
inputs.security = securityCheck.ok ? 'OK' : 'BLOCKED';
|
|
373
|
+
|
|
374
|
+
if (!securityCheck.exists) {
|
|
375
|
+
blockers.push({
|
|
376
|
+
code: GA_BLOCKER_CODE.SECURITY_NOT_CHECKED,
|
|
377
|
+
message: 'Security reports not found. Run "verax security:check" first.',
|
|
378
|
+
context: {}
|
|
379
|
+
});
|
|
380
|
+
} else if (!securityCheck.ok) {
|
|
381
|
+
blockers.push({
|
|
382
|
+
code: GA_BLOCKER_CODE.SECURITY_BLOCKED,
|
|
383
|
+
message: `SECURITY-BLOCKED: ${securityCheck.blockers.join('; ')}`,
|
|
384
|
+
context: { blockers: securityCheck.blockers }
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
} catch (error) {
|
|
388
|
+
blockers.push({
|
|
389
|
+
code: GA_BLOCKER_CODE.SECURITY_NOT_CHECKED,
|
|
390
|
+
message: `Security check failed: ${error.message}`,
|
|
391
|
+
context: { error: error.message }
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// 9. Performance Budget (PHASE 21.9) - BLOCKING perf violations block GA
|
|
396
|
+
if (runId) {
|
|
397
|
+
try {
|
|
398
|
+
const { checkPerformanceStatus } = await import('../perf/perf.enforcer.js');
|
|
399
|
+
const perfCheck = checkPerformanceStatus(projectDir, runId);
|
|
400
|
+
inputs.performance = perfCheck.ok ? 'OK' : 'BLOCKED';
|
|
401
|
+
|
|
402
|
+
if (!perfCheck.exists) {
|
|
403
|
+
// Performance report missing is not a blocker (may be from old runs)
|
|
404
|
+
inputs.performance = 'MISSING';
|
|
405
|
+
} else if (!perfCheck.ok) {
|
|
406
|
+
blockers.push({
|
|
407
|
+
code: GA_BLOCKER_CODE.PERFORMANCE_BLOCKED,
|
|
408
|
+
message: `PERFORMANCE-BLOCKED: ${perfCheck.blockers.join('; ')}`,
|
|
409
|
+
context: { blockers: perfCheck.blockers, verdict: perfCheck.verdict }
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
} catch (error) {
|
|
413
|
+
// Performance check failure is not a blocker (may be from old runs)
|
|
414
|
+
inputs.performance = 'ERROR';
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const pass = blockers.length === 0;
|
|
419
|
+
|
|
420
|
+
const summary = {
|
|
421
|
+
pass,
|
|
422
|
+
blockersCount: blockers.length,
|
|
423
|
+
warningsCount: warnings.length,
|
|
424
|
+
checkedAt: new Date().toISOString()
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
pass,
|
|
429
|
+
blockers,
|
|
430
|
+
warnings,
|
|
431
|
+
summary,
|
|
432
|
+
inputs
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.6 — GA Enforcer
|
|
3
|
+
*
|
|
4
|
+
* Hard enforcement that blocks shipping without GA-READY status.
|
|
5
|
+
* This is not advisory. This is hard enforcement.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync } from 'fs';
|
|
9
|
+
import { resolve } from 'path';
|
|
10
|
+
import { createInternalFailure } from '../failures/failure.factory.js';
|
|
11
|
+
import { FAILURE_CODE } from '../failures/failure.types.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if GA status exists and is READY
|
|
15
|
+
*
|
|
16
|
+
* @param {string} projectDir - Project directory
|
|
17
|
+
* @param {string} runId - Run ID
|
|
18
|
+
* @returns {Object} { exists: boolean, ready: boolean, status: Object|null }
|
|
19
|
+
*/
|
|
20
|
+
export function checkGAStatus(projectDir, runId) {
|
|
21
|
+
const statusPath = resolve(projectDir, '.verax', 'runs', runId, 'ga.status.json');
|
|
22
|
+
|
|
23
|
+
if (!existsSync(statusPath)) {
|
|
24
|
+
return {
|
|
25
|
+
exists: false,
|
|
26
|
+
ready: false,
|
|
27
|
+
status: null
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const content = readFileSync(statusPath, 'utf-8');
|
|
33
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
34
|
+
const status = JSON.parse(content);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
exists: true,
|
|
38
|
+
ready: status.gaReady === true,
|
|
39
|
+
status
|
|
40
|
+
};
|
|
41
|
+
} catch (error) {
|
|
42
|
+
return {
|
|
43
|
+
exists: false,
|
|
44
|
+
ready: false,
|
|
45
|
+
status: null,
|
|
46
|
+
error: error.message
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Enforce GA readiness before release operations
|
|
53
|
+
*
|
|
54
|
+
* @param {string} projectDir - Project directory
|
|
55
|
+
* @param {string} runId - Run ID
|
|
56
|
+
* @param {string} operation - Operation name (publish, release, tag)
|
|
57
|
+
* @throws {Error} If GA not ready
|
|
58
|
+
*/
|
|
59
|
+
export function enforceGAReadiness(projectDir, runId, operation) {
|
|
60
|
+
const check = checkGAStatus(projectDir, runId);
|
|
61
|
+
|
|
62
|
+
if (!check.exists) {
|
|
63
|
+
const failure = createInternalFailure(
|
|
64
|
+
FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
|
|
65
|
+
`Cannot ${operation}: GA status not found. Run 'verax ga' first.`,
|
|
66
|
+
'ga.enforcer',
|
|
67
|
+
{ operation, runId },
|
|
68
|
+
null
|
|
69
|
+
);
|
|
70
|
+
throw failure;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!check.ready) {
|
|
74
|
+
const blockers = check.status?.blockers || [];
|
|
75
|
+
const blockerMessages = blockers.map(b => b.message).join('; ');
|
|
76
|
+
|
|
77
|
+
const failure = createInternalFailure(
|
|
78
|
+
FAILURE_CODE.INTERNAL_UNEXPECTED_ERROR,
|
|
79
|
+
`Cannot ${operation}: GA-BLOCKED. Blockers: ${blockerMessages}`,
|
|
80
|
+
'ga.enforcer',
|
|
81
|
+
{ operation, runId, blockers },
|
|
82
|
+
null
|
|
83
|
+
);
|
|
84
|
+
throw failure;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 23 — Guardrails Report Writer
|
|
3
|
+
*
|
|
4
|
+
* Writes guardrails.report.json artifact per run.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { writeFileSync } from 'fs';
|
|
8
|
+
import { resolve } from 'path';
|
|
9
|
+
import { ARTIFACT_REGISTRY } from '../artifacts/registry.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Write guardrails report to disk.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} runDir - Absolute run directory path
|
|
15
|
+
* @param {Array} findings - Array of findings with guardrails data
|
|
16
|
+
* @param {Object} truthDecisions - Map of findingIdentity -> truthDecision
|
|
17
|
+
* @returns {string} Path to written report
|
|
18
|
+
*/
|
|
19
|
+
export function writeGuardrailsReport(runDir, findings, truthDecisions = {}) {
|
|
20
|
+
const reportPath = resolve(runDir, ARTIFACT_REGISTRY.guardrailsReport.filename);
|
|
21
|
+
|
|
22
|
+
// Build per-finding entries (deterministic ordering by findingIdentity)
|
|
23
|
+
const perFinding = {};
|
|
24
|
+
const summary = {
|
|
25
|
+
totalFindings: findings.length,
|
|
26
|
+
byFinalDecision: {
|
|
27
|
+
CONFIRMED: 0,
|
|
28
|
+
SUSPECTED: 0,
|
|
29
|
+
INFORMATIONAL: 0,
|
|
30
|
+
IGNORED: 0
|
|
31
|
+
},
|
|
32
|
+
topRules: {},
|
|
33
|
+
contradictionCount: 0,
|
|
34
|
+
reconciliationCount: 0
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
for (const finding of findings) {
|
|
38
|
+
const findingIdentity = finding.findingId || finding.id || `finding-${findings.indexOf(finding)}`;
|
|
39
|
+
const guardrails = finding.guardrails || {};
|
|
40
|
+
const truthDecision = truthDecisions[findingIdentity] || null;
|
|
41
|
+
|
|
42
|
+
const appliedRules = guardrails.appliedRules || [];
|
|
43
|
+
const contradictions = guardrails.contradictions || [];
|
|
44
|
+
const finalDecision = truthDecision?.finalStatus || guardrails.finalDecision || finding.severity || 'SUSPECTED';
|
|
45
|
+
|
|
46
|
+
// Track top rules
|
|
47
|
+
for (const rule of appliedRules) {
|
|
48
|
+
const ruleCode = rule.code || rule.ruleId || 'unknown';
|
|
49
|
+
summary.topRules[ruleCode] = (summary.topRules[ruleCode] || 0) + 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Track contradictions
|
|
53
|
+
if (contradictions.length > 0) {
|
|
54
|
+
summary.contradictionCount += contradictions.length;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Track reconciliation
|
|
58
|
+
if (truthDecision && truthDecision.reconciliationReasons.length > 0) {
|
|
59
|
+
summary.reconciliationCount++;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Track by final decision
|
|
63
|
+
if (summary.byFinalDecision[finalDecision] !== undefined) {
|
|
64
|
+
summary.byFinalDecision[finalDecision]++;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Build per-finding entry
|
|
68
|
+
perFinding[findingIdentity] = {
|
|
69
|
+
appliedRules: appliedRules.map(r => ({
|
|
70
|
+
code: r.code || r.ruleId,
|
|
71
|
+
severity: r.severity,
|
|
72
|
+
category: r.category
|
|
73
|
+
})),
|
|
74
|
+
contradictions: contradictions.map(c => ({
|
|
75
|
+
code: c.code,
|
|
76
|
+
message: c.message
|
|
77
|
+
})),
|
|
78
|
+
finalDecision,
|
|
79
|
+
confidenceDelta: truthDecision?.confidenceDelta || guardrails.confidenceDelta || 0,
|
|
80
|
+
confidenceBefore: truthDecision?.confidenceBefore || finding.confidence || 0,
|
|
81
|
+
confidenceAfter: truthDecision?.confidenceAfter || finding.confidence || 0,
|
|
82
|
+
reconciliationReasons: truthDecision?.reconciliationReasons || [],
|
|
83
|
+
contradictionsResolved: truthDecision?.contradictionsResolved || []
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Sort top rules by count (descending)
|
|
88
|
+
const topRulesSorted = Object.entries(summary.topRules)
|
|
89
|
+
.sort((a, b) => b[1] - a[1])
|
|
90
|
+
.slice(0, 10)
|
|
91
|
+
.map(([code, count]) => ({ code, count }));
|
|
92
|
+
|
|
93
|
+
// Build report
|
|
94
|
+
const report = {
|
|
95
|
+
version: 1,
|
|
96
|
+
generatedAt: new Date().toISOString(),
|
|
97
|
+
summary: {
|
|
98
|
+
...summary,
|
|
99
|
+
topRules: topRulesSorted
|
|
100
|
+
},
|
|
101
|
+
perFinding
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Write to disk
|
|
105
|
+
writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
|
|
106
|
+
|
|
107
|
+
return reportPath;
|
|
108
|
+
}
|
|
109
|
+
|