@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,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Guardrails Policy Defaults
|
|
3
|
+
*
|
|
4
|
+
* Default guardrails policy extracted from hardcoded rules.
|
|
5
|
+
* All rules are mandatory and cannot be disabled.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* PHASE 17: Guardrails Rule Codes
|
|
10
|
+
*/
|
|
11
|
+
export const GUARDRAILS_RULE = {
|
|
12
|
+
NET_SUCCESS_NO_UI: 'GUARD_NET_SUCCESS_NO_UI',
|
|
13
|
+
ANALYTICS_ONLY: 'GUARD_ANALYTICS_ONLY',
|
|
14
|
+
SHALLOW_ROUTING: 'GUARD_SHALLOW_ROUTING',
|
|
15
|
+
UI_FEEDBACK_PRESENT: 'GUARD_UI_FEEDBACK_PRESENT',
|
|
16
|
+
INTERACTION_BLOCKED: 'GUARD_INTERACTION_BLOCKED',
|
|
17
|
+
VALIDATION_PRESENT: 'GUARD_VALIDATION_PRESENT',
|
|
18
|
+
CONTRADICT_EVIDENCE: 'GUARD_CONTRADICT_EVIDENCE',
|
|
19
|
+
VIEW_SWITCH_MINOR_CHANGE: 'GUARD_VIEW_SWITCH_MINOR_CHANGE',
|
|
20
|
+
VIEW_SWITCH_ANALYTICS_ONLY: 'GUARD_VIEW_SWITCH_ANALYTICS_ONLY',
|
|
21
|
+
VIEW_SWITCH_AMBIGUOUS: 'GUARD_VIEW_SWITCH_AMBIGUOUS',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Default guardrails policy
|
|
26
|
+
*
|
|
27
|
+
* This policy matches the current hardcoded behavior exactly.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_GUARDRAILS_POLICY = {
|
|
30
|
+
version: '21.4.0',
|
|
31
|
+
source: 'default',
|
|
32
|
+
rules: [
|
|
33
|
+
{
|
|
34
|
+
id: GUARDRAILS_RULE.NET_SUCCESS_NO_UI,
|
|
35
|
+
category: 'network',
|
|
36
|
+
trigger: 'Network request succeeded but no UI change observed',
|
|
37
|
+
action: 'BLOCK',
|
|
38
|
+
confidenceDelta: -0.3,
|
|
39
|
+
appliesTo: ['silent_failure', 'network'],
|
|
40
|
+
mandatory: true,
|
|
41
|
+
evaluation: {
|
|
42
|
+
type: 'network_success_no_ui',
|
|
43
|
+
conditions: {
|
|
44
|
+
networkSuccess: true,
|
|
45
|
+
noUiChange: true,
|
|
46
|
+
noErrors: true,
|
|
47
|
+
isSilentFailure: true,
|
|
48
|
+
isConfirmed: true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: GUARDRAILS_RULE.ANALYTICS_ONLY,
|
|
54
|
+
category: 'network',
|
|
55
|
+
trigger: 'Only analytics/beacon requests detected',
|
|
56
|
+
action: 'BLOCK',
|
|
57
|
+
confidenceDelta: -0.5,
|
|
58
|
+
appliesTo: ['network', 'silent_failure'],
|
|
59
|
+
mandatory: true,
|
|
60
|
+
evaluation: {
|
|
61
|
+
type: 'analytics_only',
|
|
62
|
+
conditions: {
|
|
63
|
+
isAnalyticsOnly: true,
|
|
64
|
+
isNetworkFinding: true,
|
|
65
|
+
isConfirmed: true,
|
|
66
|
+
singleRequest: true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: GUARDRAILS_RULE.SHALLOW_ROUTING,
|
|
72
|
+
category: 'navigation',
|
|
73
|
+
trigger: 'Hash-only or shallow routing detected',
|
|
74
|
+
action: 'BLOCK',
|
|
75
|
+
confidenceDelta: -0.2,
|
|
76
|
+
appliesTo: ['navigation', 'route'],
|
|
77
|
+
mandatory: true,
|
|
78
|
+
evaluation: {
|
|
79
|
+
type: 'shallow_routing',
|
|
80
|
+
conditions: {
|
|
81
|
+
isHashOnly: true,
|
|
82
|
+
isShallowRouting: true,
|
|
83
|
+
isNavigationFinding: true,
|
|
84
|
+
isConfirmed: true
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: GUARDRAILS_RULE.UI_FEEDBACK_PRESENT,
|
|
90
|
+
category: 'ui-feedback',
|
|
91
|
+
trigger: 'UI feedback is present, contradicting silent failure claim',
|
|
92
|
+
action: 'BLOCK',
|
|
93
|
+
confidenceDelta: -0.4,
|
|
94
|
+
appliesTo: ['silent_failure', 'feedback_missing'],
|
|
95
|
+
mandatory: true,
|
|
96
|
+
evaluation: {
|
|
97
|
+
type: 'ui_feedback_present',
|
|
98
|
+
conditions: {
|
|
99
|
+
hasFeedback: true,
|
|
100
|
+
isSilentFailure: true,
|
|
101
|
+
isConfirmed: true
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: GUARDRAILS_RULE.INTERACTION_BLOCKED,
|
|
107
|
+
category: 'state',
|
|
108
|
+
trigger: 'Interaction was disabled/blocked',
|
|
109
|
+
action: 'INFO',
|
|
110
|
+
confidenceDelta: -0.5,
|
|
111
|
+
appliesTo: ['silent_failure'],
|
|
112
|
+
mandatory: true,
|
|
113
|
+
evaluation: {
|
|
114
|
+
type: 'interaction_blocked',
|
|
115
|
+
conditions: {
|
|
116
|
+
isDisabled: true,
|
|
117
|
+
isSilentFailure: true,
|
|
118
|
+
isConfirmed: true
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: GUARDRAILS_RULE.VALIDATION_PRESENT,
|
|
124
|
+
category: 'validation',
|
|
125
|
+
trigger: 'Validation feedback is present, contradicting validation failure claim',
|
|
126
|
+
action: 'BLOCK',
|
|
127
|
+
confidenceDelta: -0.3,
|
|
128
|
+
appliesTo: ['validation', 'form'],
|
|
129
|
+
mandatory: true,
|
|
130
|
+
evaluation: {
|
|
131
|
+
type: 'validation_present',
|
|
132
|
+
conditions: {
|
|
133
|
+
hasValidationFeedback: true,
|
|
134
|
+
isValidationFailure: true,
|
|
135
|
+
isConfirmed: true
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: GUARDRAILS_RULE.CONTRADICT_EVIDENCE,
|
|
141
|
+
category: 'state',
|
|
142
|
+
trigger: 'Evidence package is incomplete',
|
|
143
|
+
action: 'BLOCK',
|
|
144
|
+
confidenceDelta: -0.2,
|
|
145
|
+
appliesTo: ['*'], // Applies to all findings
|
|
146
|
+
mandatory: true,
|
|
147
|
+
evaluation: {
|
|
148
|
+
type: 'contradict_evidence',
|
|
149
|
+
conditions: {
|
|
150
|
+
isConfirmed: true,
|
|
151
|
+
evidenceIncomplete: true
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: GUARDRAILS_RULE.VIEW_SWITCH_MINOR_CHANGE,
|
|
157
|
+
category: 'view-switch',
|
|
158
|
+
trigger: 'URL unchanged and change is minor (e.g. button text only)',
|
|
159
|
+
action: 'BLOCK',
|
|
160
|
+
confidenceDelta: -0.4,
|
|
161
|
+
appliesTo: ['view_switch', 'state_action'],
|
|
162
|
+
mandatory: true,
|
|
163
|
+
evaluation: {
|
|
164
|
+
type: 'view_switch_minor_change',
|
|
165
|
+
conditions: {
|
|
166
|
+
isViewSwitch: true,
|
|
167
|
+
urlUnchanged: true,
|
|
168
|
+
isMinorChange: true,
|
|
169
|
+
isConfirmed: true
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: GUARDRAILS_RULE.VIEW_SWITCH_ANALYTICS_ONLY,
|
|
175
|
+
category: 'view-switch',
|
|
176
|
+
trigger: 'Only analytics fired, no UI change',
|
|
177
|
+
action: 'BLOCK',
|
|
178
|
+
confidenceDelta: -0.5,
|
|
179
|
+
appliesTo: ['view_switch', 'state_action'],
|
|
180
|
+
mandatory: true,
|
|
181
|
+
evaluation: {
|
|
182
|
+
type: 'view_switch_analytics_only',
|
|
183
|
+
conditions: {
|
|
184
|
+
isViewSwitch: true,
|
|
185
|
+
analyticsOnly: true,
|
|
186
|
+
isConfirmed: true
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: GUARDRAILS_RULE.VIEW_SWITCH_AMBIGUOUS,
|
|
192
|
+
category: 'view-switch',
|
|
193
|
+
trigger: 'State change promise exists but UI outcome ambiguous (one signal only)',
|
|
194
|
+
action: 'DOWNGRADE',
|
|
195
|
+
confidenceDelta: -0.3,
|
|
196
|
+
appliesTo: ['view_switch', 'state_action'],
|
|
197
|
+
mandatory: true,
|
|
198
|
+
evaluation: {
|
|
199
|
+
type: 'view_switch_ambiguous',
|
|
200
|
+
conditions: {
|
|
201
|
+
isViewSwitch: true,
|
|
202
|
+
hasPromise: true,
|
|
203
|
+
ambiguousOutcome: true,
|
|
204
|
+
isConfirmed: true
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
};
|
|
210
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Guardrails Policy Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads guardrails policies from files or uses defaults.
|
|
5
|
+
* Validates policies and ensures all rules are mandatory.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, existsSync } from 'fs';
|
|
9
|
+
import { resolve } from 'path';
|
|
10
|
+
import { validateGuardrailsPolicy } from './policy.schema.js';
|
|
11
|
+
import { DEFAULT_GUARDRAILS_POLICY } from './policy.defaults.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Load guardrails policy
|
|
15
|
+
*
|
|
16
|
+
* @param {string|null} policyPath - Path to custom policy file (optional)
|
|
17
|
+
* @param {string} projectDir - Project directory
|
|
18
|
+
* @returns {Object} Guardrails policy
|
|
19
|
+
* @throws {Error} If policy is invalid
|
|
20
|
+
*/
|
|
21
|
+
export function loadGuardrailsPolicy(policyPath = null, projectDir = null) {
|
|
22
|
+
// If no custom policy path, use defaults
|
|
23
|
+
if (!policyPath) {
|
|
24
|
+
return DEFAULT_GUARDRAILS_POLICY;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Resolve policy path
|
|
28
|
+
const resolvedPath = projectDir ? resolve(projectDir, policyPath) : resolve(policyPath);
|
|
29
|
+
|
|
30
|
+
// Check if file exists
|
|
31
|
+
if (!existsSync(resolvedPath)) {
|
|
32
|
+
throw new Error(`Guardrails policy file not found: ${resolvedPath}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Read and parse policy
|
|
36
|
+
let policy;
|
|
37
|
+
try {
|
|
38
|
+
const policyContent = readFileSync(resolvedPath, 'utf-8');
|
|
39
|
+
// @ts-expect-error - readFileSync with encoding returns string
|
|
40
|
+
policy = JSON.parse(policyContent);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw new Error(`Failed to load guardrails policy: ${error.message}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Validate policy
|
|
46
|
+
try {
|
|
47
|
+
validateGuardrailsPolicy(policy);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new Error(`Invalid guardrails policy: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Mark as custom
|
|
53
|
+
policy.source = 'custom';
|
|
54
|
+
|
|
55
|
+
// HARD LOCK: Ensure all rules are mandatory
|
|
56
|
+
for (const rule of policy.rules) {
|
|
57
|
+
if (rule.mandatory !== true) {
|
|
58
|
+
throw new Error(`Guardrails rule ${rule.id} cannot be disabled (mandatory must be true)`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return policy;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get policy report metadata
|
|
67
|
+
*
|
|
68
|
+
* @param {Object} policy - Guardrails policy
|
|
69
|
+
* @returns {Object} Policy report metadata
|
|
70
|
+
*/
|
|
71
|
+
export function getPolicyReport(policy) {
|
|
72
|
+
return {
|
|
73
|
+
version: policy.version,
|
|
74
|
+
source: policy.source,
|
|
75
|
+
ruleCount: policy.rules.length,
|
|
76
|
+
rules: policy.rules.map(rule => ({
|
|
77
|
+
id: rule.id,
|
|
78
|
+
category: rule.category,
|
|
79
|
+
action: rule.action,
|
|
80
|
+
mandatory: rule.mandatory
|
|
81
|
+
}))
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 21.4 — Guardrails Policy Schema
|
|
3
|
+
*
|
|
4
|
+
* Defines the structure for guardrails policies.
|
|
5
|
+
* All rules are mandatory and cannot be disabled.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Guardrails Policy Schema
|
|
10
|
+
*
|
|
11
|
+
* @typedef {Object} GuardrailsPolicy
|
|
12
|
+
* @property {string} version - Policy version
|
|
13
|
+
* @property {string} source - 'default' | 'custom'
|
|
14
|
+
* @property {Array<GuardrailsRule>} rules - Array of guardrails rules
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Guardrails Rule
|
|
19
|
+
*
|
|
20
|
+
* @typedef {Object} GuardrailsRule
|
|
21
|
+
* @property {string} id - Stable rule identifier
|
|
22
|
+
* @property {string} category - Rule category (network, navigation, ui-feedback, validation, state)
|
|
23
|
+
* @property {string} trigger - Trigger condition description
|
|
24
|
+
* @property {string} action - Action type (BLOCK / DOWNGRADE / INFO)
|
|
25
|
+
* @property {number} confidenceDelta - Confidence adjustment (must be ≤ 0)
|
|
26
|
+
* @property {Array<string>} appliesTo - Capabilities list this rule applies to
|
|
27
|
+
* @property {boolean} mandatory - Always true (cannot be disabled)
|
|
28
|
+
* @property {Object} evaluation - Evaluation function parameters
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Validate guardrails policy
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} policy - Policy to validate
|
|
35
|
+
* @throws {Error} If policy is invalid
|
|
36
|
+
*/
|
|
37
|
+
export function validateGuardrailsPolicy(policy) {
|
|
38
|
+
if (!policy) {
|
|
39
|
+
throw new Error('Guardrails policy is required');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!policy.version || typeof policy.version !== 'string') {
|
|
43
|
+
throw new Error('Guardrails policy must have a version string');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!policy.rules || !Array.isArray(policy.rules)) {
|
|
47
|
+
throw new Error('Guardrails policy must have a rules array');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const rule of policy.rules) {
|
|
51
|
+
validateGuardrailsRule(rule);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Validate a guardrails rule
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} rule - Rule to validate
|
|
59
|
+
* @throws {Error} If rule is invalid
|
|
60
|
+
*/
|
|
61
|
+
export function validateGuardrailsRule(rule) {
|
|
62
|
+
if (!rule.id || typeof rule.id !== 'string') {
|
|
63
|
+
throw new Error('Guardrails rule must have a stable id string');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!rule.category || typeof rule.category !== 'string') {
|
|
67
|
+
throw new Error('Guardrails rule must have a category string');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const validCategories = ['network', 'navigation', 'ui-feedback', 'validation', 'state'];
|
|
71
|
+
if (!validCategories.includes(rule.category)) {
|
|
72
|
+
throw new Error(`Guardrails rule category must be one of: ${validCategories.join(', ')}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!rule.action || typeof rule.action !== 'string') {
|
|
76
|
+
throw new Error('Guardrails rule must have an action string');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const validActions = ['BLOCK', 'DOWNGRADE', 'INFO'];
|
|
80
|
+
if (!validActions.includes(rule.action)) {
|
|
81
|
+
throw new Error(`Guardrails rule action must be one of: ${validActions.join(', ')}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof rule.confidenceDelta !== 'number') {
|
|
85
|
+
throw new Error('Guardrails rule must have a confidenceDelta number');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// HARD LOCK: Confidence delta must be ≤ 0 (can only decrease confidence)
|
|
89
|
+
if (rule.confidenceDelta > 0) {
|
|
90
|
+
throw new Error('Guardrails rule confidenceDelta must be ≤ 0 (cannot increase confidence)');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!Array.isArray(rule.appliesTo)) {
|
|
94
|
+
throw new Error('Guardrails rule appliesTo must be an array');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// HARD LOCK: All rules are mandatory
|
|
98
|
+
if (rule.mandatory !== true) {
|
|
99
|
+
throw new Error('Guardrails rule must have mandatory: true (cannot be disabled)');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!rule.trigger || typeof rule.trigger !== 'string') {
|
|
103
|
+
throw new Error('Guardrails rule must have a trigger description');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!rule.evaluation || typeof rule.evaluation !== 'object') {
|
|
107
|
+
throw new Error('Guardrails rule must have an evaluation object');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PHASE 23 — Guardrails Truth Reconciliation
|
|
3
|
+
*
|
|
4
|
+
* Reconciles confidence with guardrails outcome to ensure consistency.
|
|
5
|
+
* Guardrails outcome is the authoritative "final claim boundary".
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { CONFIDENCE_LEVEL as _CONFIDENCE_LEVEL } from '../confidence-engine.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reconciliation reason codes
|
|
12
|
+
*/
|
|
13
|
+
export const RECONCILIATION_REASON = {
|
|
14
|
+
GUARDRAILS_DOWNGRADE_CONFIRMED: 'RECON_GUARDRAILS_DOWNGRADE_CONFIRMED',
|
|
15
|
+
GUARDRAILS_DOWNGRADE_SUSPECTED: 'RECON_GUARDRAILS_DOWNGRADE_SUSPECTED',
|
|
16
|
+
GUARDRAILS_INFORMATIONAL: 'RECON_GUARDRAILS_INFORMATIONAL',
|
|
17
|
+
GUARDRAILS_IGNORED: 'RECON_GUARDRAILS_IGNORED',
|
|
18
|
+
CONFIDENCE_CAP_GUARDRAILS_DOWNGRADE: 'RECON_CONF_CAP_GUARDRAILS_DOWNGRADE',
|
|
19
|
+
CONFIDENCE_CAP_INFORMATIONAL: 'RECON_CONF_CAP_INFORMATIONAL',
|
|
20
|
+
CONFIDENCE_CAP_IGNORED: 'RECON_CONF_CAP_IGNORED',
|
|
21
|
+
NO_RECONCILIATION_NEEDED: 'RECON_NO_RECONCILIATION_NEEDED',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Finalize finding truth by reconciling confidence with guardrails outcome.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} finding - Finding object (may have been modified by guardrails)
|
|
28
|
+
* @param {Object} guardrailsResult - Result from applyGuardrails
|
|
29
|
+
* @param {Object} context - Context { initialConfidence, initialConfidenceLevel }
|
|
30
|
+
* @returns {Object} { finalFinding, truthDecision }
|
|
31
|
+
*/
|
|
32
|
+
export function finalizeFindingTruth(finding, guardrailsResult, context = {}) {
|
|
33
|
+
const guardrails = guardrailsResult.guardrails || finding.guardrails || {};
|
|
34
|
+
const finalDecision = guardrails.finalDecision || guardrails.recommendedStatus || finding.severity || 'SUSPECTED';
|
|
35
|
+
|
|
36
|
+
// Capture initial confidence before guardrails
|
|
37
|
+
const confidenceBefore = context.initialConfidence !== undefined
|
|
38
|
+
? context.initialConfidence
|
|
39
|
+
: (finding.confidence || 0);
|
|
40
|
+
const confidenceLevelBefore = context.initialConfidenceLevel
|
|
41
|
+
|| finding.confidenceLevel
|
|
42
|
+
|| (confidenceBefore >= 0.8 ? 'HIGH' : confidenceBefore >= 0.5 ? 'MEDIUM' : confidenceBefore >= 0.2 ? 'LOW' : 'UNPROVEN');
|
|
43
|
+
|
|
44
|
+
// Start with guardrails-adjusted confidence
|
|
45
|
+
let confidenceAfter = finding.confidence !== undefined ? finding.confidence : confidenceBefore;
|
|
46
|
+
let confidenceLevelAfter = finding.confidenceLevel || confidenceLevelBefore;
|
|
47
|
+
|
|
48
|
+
const reconciliationReasons = [];
|
|
49
|
+
const contradictionsResolved = [];
|
|
50
|
+
|
|
51
|
+
// Enforce truth boundaries based on final decision
|
|
52
|
+
if (finalDecision === 'CONFIRMED') {
|
|
53
|
+
// CONFIRMED must have guardrails finalDecision == CONFIRMED
|
|
54
|
+
if (guardrails.finalDecision !== 'CONFIRMED' && guardrails.recommendedStatus !== 'CONFIRMED') {
|
|
55
|
+
// This should not happen if guardrails are applied correctly, but enforce it
|
|
56
|
+
contradictionsResolved.push({
|
|
57
|
+
code: 'CONTRADICTION_CONFIRMED_WITHOUT_GUARDRAILS',
|
|
58
|
+
message: 'Finding marked CONFIRMED but guardrails did not approve CONFIRMED status'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// CONFIRMED can have any confidence level (no cap)
|
|
62
|
+
} else if (finalDecision === 'SUSPECTED') {
|
|
63
|
+
// SUSPECTED due to guardrails downgrade -> cap confidence at 0.69 (MEDIUM)
|
|
64
|
+
const wasDowngraded = guardrails.contradictions && guardrails.contradictions.length > 0;
|
|
65
|
+
const hasEvidenceIntentFailure = guardrails.appliedRules?.some(r =>
|
|
66
|
+
r.code?.includes('EVIDENCE') || r.message?.includes('evidence')
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (wasDowngraded || hasEvidenceIntentFailure) {
|
|
70
|
+
if (confidenceAfter > 0.69) {
|
|
71
|
+
confidenceAfter = 0.69;
|
|
72
|
+
confidenceLevelAfter = 'MEDIUM';
|
|
73
|
+
reconciliationReasons.push(RECONCILIATION_REASON.CONFIDENCE_CAP_GUARDRAILS_DOWNGRADE);
|
|
74
|
+
}
|
|
75
|
+
reconciliationReasons.push(RECONCILIATION_REASON.GUARDRAILS_DOWNGRADE_SUSPECTED);
|
|
76
|
+
}
|
|
77
|
+
} else if (finalDecision === 'INFORMATIONAL') {
|
|
78
|
+
// INFORMATIONAL -> confidence must be LOW or UNPROVEN
|
|
79
|
+
if (confidenceAfter > 0.2) {
|
|
80
|
+
confidenceAfter = 0.2;
|
|
81
|
+
confidenceLevelAfter = 'LOW';
|
|
82
|
+
reconciliationReasons.push(RECONCILIATION_REASON.CONFIDENCE_CAP_INFORMATIONAL);
|
|
83
|
+
}
|
|
84
|
+
reconciliationReasons.push(RECONCILIATION_REASON.GUARDRAILS_INFORMATIONAL);
|
|
85
|
+
} else if (finalDecision === 'IGNORED') {
|
|
86
|
+
// IGNORED -> confidence must be UNPROVEN
|
|
87
|
+
confidenceAfter = 0;
|
|
88
|
+
confidenceLevelAfter = 'UNPROVEN';
|
|
89
|
+
reconciliationReasons.push(RECONCILIATION_REASON.CONFIDENCE_CAP_IGNORED);
|
|
90
|
+
reconciliationReasons.push(RECONCILIATION_REASON.GUARDRAILS_IGNORED);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// If no reconciliation was needed, record it
|
|
94
|
+
if (reconciliationReasons.length === 0) {
|
|
95
|
+
reconciliationReasons.push(RECONCILIATION_REASON.NO_RECONCILIATION_NEEDED);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Build final finding with reconciled confidence
|
|
99
|
+
const finalFinding = {
|
|
100
|
+
...finding,
|
|
101
|
+
severity: finalDecision,
|
|
102
|
+
status: finalDecision,
|
|
103
|
+
confidence: confidenceAfter,
|
|
104
|
+
confidenceLevel: confidenceLevelAfter,
|
|
105
|
+
guardrails: {
|
|
106
|
+
...guardrails,
|
|
107
|
+
reconciliation: {
|
|
108
|
+
confidenceBefore,
|
|
109
|
+
confidenceAfter,
|
|
110
|
+
confidenceLevelBefore,
|
|
111
|
+
confidenceLevelAfter,
|
|
112
|
+
reconciliationReasons,
|
|
113
|
+
contradictionsResolved
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Build truth decision
|
|
119
|
+
const truthDecision = {
|
|
120
|
+
finalStatus: finalDecision,
|
|
121
|
+
appliedGuardrails: guardrails.appliedRules?.map(r => r.code) || [],
|
|
122
|
+
confidenceBefore,
|
|
123
|
+
confidenceAfter,
|
|
124
|
+
confidenceLevelBefore,
|
|
125
|
+
confidenceLevelAfter,
|
|
126
|
+
reconciliationReasons,
|
|
127
|
+
contradictionsResolved,
|
|
128
|
+
confidenceDelta: confidenceAfter - confidenceBefore
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
finalFinding,
|
|
133
|
+
truthDecision
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|