eval-quality 0.1.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/LICENSE +190 -0
- package/README.md +355 -0
- package/corpus/dev/README.md +36 -0
- package/corpus/dev/compile-seal-example/brief.json +1 -0
- package/corpus/dev/compile-seal-example/contract.json +1 -0
- package/corpus/dev/contracts/absent-collection-locations.json +1 -0
- package/corpus/dev/contracts/absent-sibling-groups.json +1 -0
- package/corpus/dev/contracts/absent-success-indicator.json +1 -0
- package/corpus/dev/contracts/empty-channel-roles.json +1 -0
- package/corpus/dev/contracts/empty-collection-locations.json +1 -0
- package/corpus/dev/contracts/empty-request-shapes.json +1 -0
- package/corpus/dev/contracts/empty-sibling-groups.json +1 -0
- package/corpus/dev/contracts/no-collection-quantifier.json +1 -0
- package/corpus/dev/contracts/no-operation-inventory.json +1 -0
- package/corpus/dev/contracts/no-read-back-relation.json +1 -0
- package/corpus/dev/contracts/no-state-change-marker.json +1 -0
- package/corpus/dev/contracts/no-type-violating-step.json +1 -0
- package/corpus/dev/contracts/per-key-split-oracles.json +1 -0
- package/corpus/dev/contracts/satisfied-declarations.json +1 -0
- package/corpus/dev/contracts/single-required-response-key.json +1 -0
- package/corpus/dev/contracts/split-indicator-oracle.json +1 -0
- package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -0
- package/corpus/dev/contracts/unnamed-reference-set.json +1 -0
- package/corpus/dev/contracts/wrong-cardinality-form.json +1 -0
- package/corpus/dev/index.json +1 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/local-corpus-adapter.d.ts +7 -0
- package/dist/adapters/local-corpus-adapter.js +78 -0
- package/dist/adapters/node-file-system-adapter.d.ts +7 -0
- package/dist/adapters/node-file-system-adapter.js +39 -0
- package/dist/adapters/port-boundary.d.ts +18 -0
- package/dist/adapters/port-boundary.js +83 -0
- package/dist/adapters/system-clock-adapter.d.ts +10 -0
- package/dist/adapters/system-clock-adapter.js +18 -0
- package/dist/application/compile.d.ts +4 -0
- package/dist/application/compile.js +24 -0
- package/dist/application/diagnostics.d.ts +22 -0
- package/dist/application/diagnostics.js +18 -0
- package/dist/application/index.d.ts +23 -0
- package/dist/application/index.js +17 -0
- package/dist/application/invoke-port.d.ts +2 -0
- package/dist/application/invoke-port.js +45 -0
- package/dist/application/preflight.d.ts +27 -0
- package/dist/application/preflight.js +131 -0
- package/dist/application/seal.d.ts +4 -0
- package/dist/application/seal.js +28 -0
- package/dist/application/serialize.d.ts +6 -0
- package/dist/application/serialize.js +9 -0
- package/dist/cli/arguments.d.ts +28 -0
- package/dist/cli/arguments.js +167 -0
- package/dist/cli/exit-codes.d.ts +36 -0
- package/dist/cli/exit-codes.js +39 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +143 -0
- package/dist/cli/render.d.ts +26 -0
- package/dist/cli/render.js +53 -0
- package/dist/cli/run.d.ts +41 -0
- package/dist/cli/run.js +203 -0
- package/dist/core/canonical/canonicalize.d.ts +1 -0
- package/dist/core/canonical/canonicalize.js +113 -0
- package/dist/core/canonical/digest.d.ts +7 -0
- package/dist/core/canonical/digest.js +81 -0
- package/dist/core/canonical/scan-json.d.ts +1 -0
- package/dist/core/canonical/scan-json.js +298 -0
- package/dist/core/canonical/value-domain.d.ts +4 -0
- package/dist/core/canonical/value-domain.js +113 -0
- package/dist/core/compile/compile.d.ts +24 -0
- package/dist/core/compile/compile.js +67 -0
- package/dist/core/compile/declarations.d.ts +5 -0
- package/dist/core/compile/declarations.js +22 -0
- package/dist/core/compile/expression-legality.d.ts +14 -0
- package/dist/core/compile/expression-legality.js +346 -0
- package/dist/core/compile/forbidden-inputs.d.ts +5 -0
- package/dist/core/compile/forbidden-inputs.js +19 -0
- package/dist/core/compile/interface-inventory.d.ts +10 -0
- package/dist/core/compile/interface-inventory.js +55 -0
- package/dist/core/compile/oracle-alignment.d.ts +14 -0
- package/dist/core/compile/oracle-alignment.js +93 -0
- package/dist/core/compile/reachability.d.ts +17 -0
- package/dist/core/compile/reachability.js +177 -0
- package/dist/core/compile/rubrics.d.ts +55 -0
- package/dist/core/compile/rubrics.js +198 -0
- package/dist/core/compile/scripting-bound.d.ts +5 -0
- package/dist/core/compile/scripting-bound.js +151 -0
- package/dist/core/compile/sensitivity-witness.d.ts +73 -0
- package/dist/core/compile/sensitivity-witness.js +232 -0
- package/dist/core/compile/waivers.d.ts +3 -0
- package/dist/core/compile/waivers.js +21 -0
- package/dist/core/coverage/coverage.d.ts +18 -0
- package/dist/core/coverage/coverage.js +47 -0
- package/dist/core/coverage/relevance.d.ts +75 -0
- package/dist/core/coverage/relevance.js +186 -0
- package/dist/core/coverage/rules.d.ts +7 -0
- package/dist/core/coverage/rules.js +18 -0
- package/dist/core/coverage/satisfaction.d.ts +107 -0
- package/dist/core/coverage/satisfaction.js +415 -0
- package/dist/core/coverage/table.d.ts +26 -0
- package/dist/core/coverage/table.js +222 -0
- package/dist/core/declared-inputs.d.ts +16 -0
- package/dist/core/declared-inputs.js +18 -0
- package/dist/core/evaluate/evidence-resolution.d.ts +54 -0
- package/dist/core/evaluate/evidence-resolution.js +153 -0
- package/dist/core/evaluate/operators.d.ts +87 -0
- package/dist/core/evaluate/operators.js +350 -0
- package/dist/core/evaluate/resolution.d.ts +40 -0
- package/dist/core/evaluate/resolution.js +336 -0
- package/dist/core/evaluate/resolved-value.d.ts +9 -0
- package/dist/core/evaluate/resolved-value.js +6 -0
- package/dist/core/failure-codes.d.ts +18 -0
- package/dist/core/failure-codes.js +50 -0
- package/dist/core/lineage/chain.d.ts +49 -0
- package/dist/core/lineage/chain.js +210 -0
- package/dist/core/lineage/freeze.d.ts +12 -0
- package/dist/core/lineage/freeze.js +35 -0
- package/dist/core/lineage/stage-table.d.ts +43 -0
- package/dist/core/lineage/stage-table.js +106 -0
- package/dist/core/preflight/plan.d.ts +67 -0
- package/dist/core/preflight/plan.js +313 -0
- package/dist/core/preflight/projection.d.ts +40 -0
- package/dist/core/preflight/projection.js +96 -0
- package/dist/core/preflight/reduce.d.ts +8 -0
- package/dist/core/preflight/reduce.js +180 -0
- package/dist/core/preflight/witness-evidence.d.ts +42 -0
- package/dist/core/preflight/witness-evidence.js +88 -0
- package/dist/core/probe/target-policy.d.ts +63 -0
- package/dist/core/probe/target-policy.js +328 -0
- package/dist/core/schemas/artifact-reference.d.ts +19 -0
- package/dist/core/schemas/artifact-reference.js +30 -0
- package/dist/core/schemas/artifact.d.ts +1153 -0
- package/dist/core/schemas/artifact.js +84 -0
- package/dist/core/schemas/constraint-ledger.d.ts +57 -0
- package/dist/core/schemas/constraint-ledger.js +143 -0
- package/dist/core/schemas/eval-contract.d.ts +402 -0
- package/dist/core/schemas/eval-contract.js +147 -0
- package/dist/core/schemas/evaluator-configuration.d.ts +37 -0
- package/dist/core/schemas/evaluator-configuration.js +43 -0
- package/dist/core/schemas/evidence-artifact.d.ts +471 -0
- package/dist/core/schemas/evidence-artifact.js +232 -0
- package/dist/core/schemas/expression.d.ts +197 -0
- package/dist/core/schemas/expression.js +284 -0
- package/dist/core/schemas/faults.d.ts +9 -0
- package/dist/core/schemas/faults.js +32 -0
- package/dist/core/schemas/interface.d.ts +417 -0
- package/dist/core/schemas/interface.js +115 -0
- package/dist/core/schemas/isolation-manifest.d.ts +136 -0
- package/dist/core/schemas/isolation-manifest.js +92 -0
- package/dist/core/schemas/lineage.d.ts +21 -0
- package/dist/core/schemas/lineage.js +28 -0
- package/dist/core/schemas/oracle.d.ts +72 -0
- package/dist/core/schemas/oracle.js +35 -0
- package/dist/core/schemas/plan.d.ts +115 -0
- package/dist/core/schemas/plan.js +58 -0
- package/dist/core/schemas/pointer.d.ts +63 -0
- package/dist/core/schemas/pointer.js +94 -0
- package/dist/core/schemas/port-messages.d.ts +103 -0
- package/dist/core/schemas/port-messages.js +90 -0
- package/dist/core/schemas/preflight-verdict.d.ts +60 -0
- package/dist/core/schemas/preflight-verdict.js +38 -0
- package/dist/core/schemas/primitives.d.ts +78 -0
- package/dist/core/schemas/primitives.js +121 -0
- package/dist/core/schemas/private-artifact-manifest.d.ts +56 -0
- package/dist/core/schemas/private-artifact-manifest.js +46 -0
- package/dist/core/schemas/probe-body.d.ts +25 -0
- package/dist/core/schemas/probe-body.js +23 -0
- package/dist/core/schemas/probe-policy.d.ts +76 -0
- package/dist/core/schemas/probe-policy.js +33 -0
- package/dist/core/schemas/probe.d.ts +189 -0
- package/dist/core/schemas/probe.js +82 -0
- package/dist/core/schemas/publish.d.ts +30 -0
- package/dist/core/schemas/publish.js +135 -0
- package/dist/core/schemas/reference-set.d.ts +18 -0
- package/dist/core/schemas/reference-set.js +27 -0
- package/dist/core/schemas/rubric.d.ts +62 -0
- package/dist/core/schemas/rubric.js +68 -0
- package/dist/core/schemas/scoring-policy.d.ts +28 -0
- package/dist/core/schemas/scoring-policy.js +51 -0
- package/dist/core/schemas/sealed-evaluator-brief.d.ts +80 -0
- package/dist/core/schemas/sealed-evaluator-brief.js +59 -0
- package/dist/core/schemas/sealed-run-record.d.ts +382 -0
- package/dist/core/schemas/sealed-run-record.js +215 -0
- package/dist/core/schemas/sensitivity-witness.d.ts +138 -0
- package/dist/core/schemas/sensitivity-witness.js +86 -0
- package/dist/core/schemas/verdict.d.ts +25 -0
- package/dist/core/schemas/verdict.js +20 -0
- package/dist/core/schemas/waiver.d.ts +17 -0
- package/dist/core/schemas/waiver.js +24 -0
- package/dist/core/seal/derived-reference.d.ts +36 -0
- package/dist/core/seal/derived-reference.js +383 -0
- package/dist/core/seal/direction-prose.d.ts +13 -0
- package/dist/core/seal/direction-prose.js +120 -0
- package/dist/core/seal/plan-index.d.ts +63 -0
- package/dist/core/seal/plan-index.js +155 -0
- package/dist/core/seal/scripting-audit.d.ts +15 -0
- package/dist/core/seal/scripting-audit.js +51 -0
- package/dist/core/seal/seal.d.ts +18 -0
- package/dist/core/seal/seal.js +155 -0
- package/dist/core/stage-contracts.d.ts +30 -0
- package/dist/core/stage-contracts.js +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +22 -0
- package/dist/ports/clock-port.d.ts +13 -0
- package/dist/ports/clock-port.js +7 -0
- package/dist/ports/corpus-port.d.ts +16 -0
- package/dist/ports/corpus-port.js +7 -0
- package/dist/ports/environment-probe-port.d.ts +76 -0
- package/dist/ports/environment-probe-port.js +32 -0
- package/dist/ports/file-system-port.d.ts +27 -0
- package/dist/ports/file-system-port.js +11 -0
- package/dist/ports/port.d.ts +33 -0
- package/dist/ports/port.js +14 -0
- package/dist/testing/conformance.d.ts +88 -0
- package/dist/testing/conformance.js +281 -0
- package/dist/testing/index.d.ts +26 -0
- package/dist/testing/index.js +18 -0
- package/dist/testing/probe-conformance.d.ts +45 -0
- package/dist/testing/probe-conformance.js +186 -0
- package/package.json +130 -0
- package/schemas/artifact-reference.schema.json +64 -0
- package/schemas/eval-contract.schema.json +2145 -0
- package/schemas/evaluator-configuration.schema.json +199 -0
- package/schemas/evidence-artifact.schema.json +1229 -0
- package/schemas/isolation-manifest.schema.json +394 -0
- package/schemas/preflight-verdict.schema.json +114 -0
- package/schemas/private-artifact-manifest.schema.json +103 -0
- package/schemas/probe.schema.json +1151 -0
- package/schemas/rubric.schema.json +148 -0
- package/schemas/scoring-policy.schema.json +90 -0
- package/schemas/sealed-evaluator-brief.schema.json +268 -0
- package/schemas/sealed-run-record.schema.json +875 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks expression operands, regex constructs, quantifier use, and
|
|
3
|
+
* reference-set resolution. Each check reports the first structural failure.
|
|
4
|
+
*/
|
|
5
|
+
import { digestArtifact } from '../canonical/digest.js';
|
|
6
|
+
import { StructuralFailure } from '../failure-codes.js';
|
|
7
|
+
import { JsonTypeName } from '../schemas/primitives.js';
|
|
8
|
+
import { buildPlanIndex, parseEvidenceTarget, } from '../seal/plan-index.js';
|
|
9
|
+
import { substitutePointer } from './oracle-alignment.js';
|
|
10
|
+
function walkExpression(expr, quantifierDepth, path, visitor) {
|
|
11
|
+
switch (expr.op) {
|
|
12
|
+
case 'not':
|
|
13
|
+
walkExpression(expr.operands[0], quantifierDepth, `${path}.operands[0]`, visitor);
|
|
14
|
+
return;
|
|
15
|
+
case 'all':
|
|
16
|
+
case 'any':
|
|
17
|
+
expr.operands.forEach((child, index) => {
|
|
18
|
+
walkExpression(child, quantifierDepth, `${path}.operands[${index}]`, visitor);
|
|
19
|
+
});
|
|
20
|
+
return;
|
|
21
|
+
case 'for-all':
|
|
22
|
+
case 'for-any':
|
|
23
|
+
visitor.onOperand?.(expr.collection, expr.op, 'collection', `${path}.collection`, quantifierDepth);
|
|
24
|
+
visitor.onQuantifier?.(expr, path, quantifierDepth);
|
|
25
|
+
walkExpression(expr.predicate, quantifierDepth + 1, `${path}.predicate`, visitor);
|
|
26
|
+
return;
|
|
27
|
+
case 'set-membership':
|
|
28
|
+
visitor.onOperand?.(expr.operands[0], expr.op, 0, `${path}.operands[0]`, quantifierDepth);
|
|
29
|
+
visitor.onSetOperand?.(expr.operands[1], `${path}.operands[1]`);
|
|
30
|
+
return;
|
|
31
|
+
case 'covers-by-key':
|
|
32
|
+
visitor.onCoversByKey?.(expr, path, quantifierDepth);
|
|
33
|
+
expr.operands.forEach((operand, index) => {
|
|
34
|
+
visitor.onOperand?.(operand, expr.op, index, `${path}.operands[${index}]`, quantifierDepth);
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
case 'regex':
|
|
38
|
+
visitor.onRegex?.(expr.pattern, path);
|
|
39
|
+
expr.operands.forEach((operand, index) => {
|
|
40
|
+
visitor.onOperand?.(operand, expr.op, index, `${path}.operands[${index}]`, quantifierDepth);
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
default:
|
|
44
|
+
expr.operands.forEach((operand, index) => {
|
|
45
|
+
visitor.onOperand?.(operand, expr.op, index, `${path}.operands[${index}]`, quantifierDepth);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Every expression the contract declares, oracle checks first and then each
|
|
51
|
+
* operation's sensitivity witness. Generalized from an oracle-only enumerator:
|
|
52
|
+
* a witness relation that escaped these five checks would be a declaration that
|
|
53
|
+
* looks checked and is not, which is the defect class AD-10 exists to catch.
|
|
54
|
+
*/
|
|
55
|
+
function forEachContractExpression(contract, visit) {
|
|
56
|
+
contract.oracles.forEach((oracle) => {
|
|
57
|
+
if (oracle.check === null)
|
|
58
|
+
return;
|
|
59
|
+
visit({
|
|
60
|
+
expression: oracle.check,
|
|
61
|
+
artifactPath: `EvalContract.oracles[id=${oracle.id}].check`,
|
|
62
|
+
witnessScope: null,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
contract.permittedInterfaces.forEach((iface, interfaceIndex) => {
|
|
66
|
+
iface.operations.forEach((operation, operationIndex) => {
|
|
67
|
+
const witness = operation.sensitivityWitness;
|
|
68
|
+
if (witness === null)
|
|
69
|
+
return;
|
|
70
|
+
visit({
|
|
71
|
+
expression: witness.relation,
|
|
72
|
+
artifactPath: `EvalContract.permittedInterfaces[${interfaceIndex}].operations[${operationIndex}].sensitivityWitness.relation`,
|
|
73
|
+
witnessScope: {
|
|
74
|
+
operation,
|
|
75
|
+
legIds: witness.legs.map((leg) => leg.legId),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function kindOf(operand) {
|
|
82
|
+
if ('pointer' in operand)
|
|
83
|
+
return 'pointer';
|
|
84
|
+
if ('literal' in operand)
|
|
85
|
+
return 'literal';
|
|
86
|
+
return 'referenceSet';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The schema accepts a common operand union, so position constraints live here.
|
|
90
|
+
* Set membership narrows its second operand in the schema.
|
|
91
|
+
*/
|
|
92
|
+
const OPERAND_LEGALITY = {
|
|
93
|
+
equality: {
|
|
94
|
+
0: new Set(['pointer', 'literal']),
|
|
95
|
+
1: new Set(['pointer', 'literal']),
|
|
96
|
+
},
|
|
97
|
+
'deep-equality': {
|
|
98
|
+
0: new Set(['pointer', 'literal']),
|
|
99
|
+
1: new Set(['pointer', 'literal']),
|
|
100
|
+
},
|
|
101
|
+
containment: {
|
|
102
|
+
0: new Set(['pointer']),
|
|
103
|
+
1: new Set(['pointer', 'literal', 'referenceSet']),
|
|
104
|
+
},
|
|
105
|
+
existence: { 0: new Set(['pointer']) },
|
|
106
|
+
absence: { 0: new Set(['pointer']) },
|
|
107
|
+
regex: { 0: new Set(['pointer']) },
|
|
108
|
+
'set-membership': { 0: new Set(['pointer']) },
|
|
109
|
+
ordering: { 0: new Set(['pointer']) },
|
|
110
|
+
'count-tolerance': { 0: new Set(['pointer']) },
|
|
111
|
+
shape: { 0: new Set(['pointer']) },
|
|
112
|
+
'covers-by-key': { 0: new Set(['referenceSet']), 1: new Set(['pointer']) },
|
|
113
|
+
'for-all': { collection: new Set(['pointer']) },
|
|
114
|
+
'for-any': { collection: new Set(['pointer']) },
|
|
115
|
+
};
|
|
116
|
+
const artifactKey = (key) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)
|
|
117
|
+
? `.${key}`
|
|
118
|
+
: `[${JSON.stringify(key)}]`;
|
|
119
|
+
/** Checks each operator's operands against its position-specific constraints. */
|
|
120
|
+
export function checkOperandLegality(contract) {
|
|
121
|
+
forEachContractExpression(contract, (site) => {
|
|
122
|
+
walkExpression(site.expression, 0, '', {
|
|
123
|
+
onOperand: (operand, op, position, path) => {
|
|
124
|
+
const legal = OPERAND_LEGALITY[op]?.[String(position)];
|
|
125
|
+
if (legal === undefined)
|
|
126
|
+
return;
|
|
127
|
+
const kind = kindOf(operand);
|
|
128
|
+
if (!legal.has(kind)) {
|
|
129
|
+
throw new StructuralFailure('malformed-operator-expression', `${site.artifactPath}${path}`, `"${op}" does not accept a ${kind} operand at position ${position} (AD-4, AD-26)`);
|
|
130
|
+
}
|
|
131
|
+
if (op === 'ordering' &&
|
|
132
|
+
'pointer' in operand &&
|
|
133
|
+
!operand.pointer.startsWith('@') &&
|
|
134
|
+
parseEvidenceTarget(operand.pointer).channel === 'call-inputs') {
|
|
135
|
+
throw new StructuralFailure('malformed-operator-expression', `${site.artifactPath}${path}`, '"ordering" accepts observed output only, never call-inputs (AD-4)');
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
onCoversByKey: (expr) => {
|
|
139
|
+
const expected = expr.operands[0];
|
|
140
|
+
if (!('referenceSet' in expected))
|
|
141
|
+
return;
|
|
142
|
+
const declarations = contract.referenceSets;
|
|
143
|
+
if (declarations === null ||
|
|
144
|
+
!Object.hasOwn(declarations, expected.referenceSet))
|
|
145
|
+
return;
|
|
146
|
+
const declaration = declarations[expected.referenceSet];
|
|
147
|
+
if (declaration === undefined)
|
|
148
|
+
return;
|
|
149
|
+
const seen = new Set();
|
|
150
|
+
for (const [index, member] of declaration.members.entries()) {
|
|
151
|
+
if (!Object.hasOwn(member, expr.expectedKey))
|
|
152
|
+
continue;
|
|
153
|
+
const memberPath = `EvalContract.referenceSets[id=${expected.referenceSet}].members[${index}]${artifactKey(expr.expectedKey)}`;
|
|
154
|
+
const digest = digestArtifact(member[expr.expectedKey], memberPath);
|
|
155
|
+
if (seen.has(digest)) {
|
|
156
|
+
throw new StructuralFailure('malformed-operator-expression', memberPath, `referenceSet "${expected.referenceSet}" repeats expectedKey "${expr.expectedKey}" for covers-by-key (AD-4)`);
|
|
157
|
+
}
|
|
158
|
+
seen.add(digest);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// Rejected regex constructs.
|
|
165
|
+
const BACKREFERENCE_PATTERN = /\\(?:[1-9][0-9]*|k<[^>]+>)/;
|
|
166
|
+
const LOOKBEHIND_PATTERN = /\(\?<[=!]/;
|
|
167
|
+
function isEscaped(pattern, index) {
|
|
168
|
+
let backslashes = 0;
|
|
169
|
+
for (let cursor = index - 1; cursor >= 0 && pattern[cursor] === '\\'; cursor--)
|
|
170
|
+
backslashes++;
|
|
171
|
+
return backslashes % 2 === 1;
|
|
172
|
+
}
|
|
173
|
+
function hasTopLevelAlternation(pattern) {
|
|
174
|
+
let depth = 0;
|
|
175
|
+
let inCharacterClass = false;
|
|
176
|
+
for (let index = 0; index < pattern.length; index++) {
|
|
177
|
+
const character = pattern[index];
|
|
178
|
+
if (character === undefined || isEscaped(pattern, index))
|
|
179
|
+
continue;
|
|
180
|
+
if (character === '[') {
|
|
181
|
+
inCharacterClass = true;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (character === ']') {
|
|
185
|
+
inCharacterClass = false;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (inCharacterClass)
|
|
189
|
+
continue;
|
|
190
|
+
if (character === '(')
|
|
191
|
+
depth++;
|
|
192
|
+
else if (character === ')')
|
|
193
|
+
depth--;
|
|
194
|
+
else if (character === '|' && depth === 0)
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
function regexRejection(pattern) {
|
|
200
|
+
try {
|
|
201
|
+
new RegExp(pattern);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return 'is not a syntactically valid ECMA-262 pattern';
|
|
205
|
+
}
|
|
206
|
+
if (pattern[0] !== '^' ||
|
|
207
|
+
pattern.at(-1) !== '$' ||
|
|
208
|
+
isEscaped(pattern, pattern.length - 1) ||
|
|
209
|
+
hasTopLevelAlternation(pattern)) {
|
|
210
|
+
return 'is not anchored over the whole expression';
|
|
211
|
+
}
|
|
212
|
+
if (BACKREFERENCE_PATTERN.test(pattern))
|
|
213
|
+
return 'carries a backreference';
|
|
214
|
+
if (LOOKBEHIND_PATTERN.test(pattern))
|
|
215
|
+
return 'carries a lookbehind';
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
/** Rejects invalid regexes, partial anchors, backreferences, and lookbehind. */
|
|
219
|
+
export function checkRegexConstructs(contract) {
|
|
220
|
+
forEachContractExpression(contract, (site) => {
|
|
221
|
+
walkExpression(site.expression, 0, '', {
|
|
222
|
+
onRegex: (pattern, path) => {
|
|
223
|
+
const rejection = regexRejection(pattern);
|
|
224
|
+
if (rejection !== null) {
|
|
225
|
+
throw new StructuralFailure('malformed-operator-expression', `${site.artifactPath}${path}.pattern`, `regex pattern "${pattern}" ${rejection}, a rejected construct (AD-4)`);
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
// Quantifier nesting.
|
|
232
|
+
/** Rejects nested quantifiers and covers-by-key inside a quantifier. */
|
|
233
|
+
export function checkQuantifierNesting(contract) {
|
|
234
|
+
forEachContractExpression(contract, (site) => {
|
|
235
|
+
walkExpression(site.expression, 0, '', {
|
|
236
|
+
onQuantifier: (_expr, path, quantifierDepth) => {
|
|
237
|
+
if (quantifierDepth >= 1) {
|
|
238
|
+
throw new StructuralFailure('quantifier-nesting-exceeded', `${site.artifactPath}${path}`, "a quantifier appears inside another quantifier's predicate; quantifiers may not nest more than one level (AD-4)");
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
onCoversByKey: (_expr, path, quantifierDepth) => {
|
|
242
|
+
if (quantifierDepth >= 1) {
|
|
243
|
+
throw new StructuralFailure('quantifier-nesting-exceeded', `${site.artifactPath}${path}`, "covers-by-key appears inside a quantifier's predicate, where it may never nest (AD-4)");
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// Quantifiers over non-collections.
|
|
250
|
+
const NON_COLLECTION_TYPES = new Set(JsonTypeName.options.filter((name) => name !== 'array'));
|
|
251
|
+
/**
|
|
252
|
+
* Substitutes a quantifier's `@`-prefixed `collection` pointer against the
|
|
253
|
+
* bound element its enclosing quantifier already opened, so a nested
|
|
254
|
+
* quantifier's own collection resolves to an absolute pointer rather than
|
|
255
|
+
* being skipped. Mirrors `oracle-alignment.ts`'s `collectTargets`.
|
|
256
|
+
*/
|
|
257
|
+
function forEachQuantifierCollection(expr, boundElementRoot, path, visit) {
|
|
258
|
+
switch (expr.op) {
|
|
259
|
+
case 'not':
|
|
260
|
+
forEachQuantifierCollection(expr.operands[0], boundElementRoot, `${path}.operands[0]`, visit);
|
|
261
|
+
return;
|
|
262
|
+
case 'all':
|
|
263
|
+
case 'any':
|
|
264
|
+
expr.operands.forEach((child, index) => {
|
|
265
|
+
forEachQuantifierCollection(child, boundElementRoot, `${path}.operands[${index}]`, visit);
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
case 'for-all':
|
|
269
|
+
case 'for-any': {
|
|
270
|
+
const { collection } = expr;
|
|
271
|
+
const collectionPointer = 'pointer' in collection
|
|
272
|
+
? substitutePointer(collection.pointer, boundElementRoot)
|
|
273
|
+
: null;
|
|
274
|
+
if (collectionPointer !== null && !collectionPointer.startsWith('@'))
|
|
275
|
+
visit(collectionPointer, `${path}.collection`);
|
|
276
|
+
forEachQuantifierCollection(expr.predicate, collectionPointer, `${path}.predicate`, visit);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
default:
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/** Checks response-body collection pointers, after bound-element substitution. */
|
|
284
|
+
export function checkQuantifierOverNonCollection(contract) {
|
|
285
|
+
const index = buildPlanIndex(contract.interactionPlan, contract.permittedInterfaces, { duplicateIds: 'unresolved' });
|
|
286
|
+
// A leg-rooted pointer cannot resolve through the plan index: a leg id
|
|
287
|
+
// colliding with a step id is itself a compile failure. Without the
|
|
288
|
+
// witness-scoped lookup below, this check silently no-ops on every legal
|
|
289
|
+
// witness, and the generalized enumerator buys four checks out of five.
|
|
290
|
+
const operationFor = (site, stepId) => {
|
|
291
|
+
const scope = site.witnessScope;
|
|
292
|
+
if (scope !== null) {
|
|
293
|
+
return scope.legIds.includes(stepId) ? scope.operation : undefined;
|
|
294
|
+
}
|
|
295
|
+
const step = index.stepOf(stepId);
|
|
296
|
+
if (step === undefined)
|
|
297
|
+
return undefined;
|
|
298
|
+
return index.operationOf(step.operationId);
|
|
299
|
+
};
|
|
300
|
+
forEachContractExpression(contract, (site) => {
|
|
301
|
+
forEachQuantifierCollection(site.expression, null, '', (pointer, path) => {
|
|
302
|
+
const target = parseEvidenceTarget(pointer);
|
|
303
|
+
if (target.channel !== 'response-body')
|
|
304
|
+
return;
|
|
305
|
+
const operation = operationFor(site, target.stepId);
|
|
306
|
+
if (operation === undefined)
|
|
307
|
+
return;
|
|
308
|
+
const firstToken = target.tail.length === 1 ? target.tail[0] : undefined;
|
|
309
|
+
const declaredType = firstToken === undefined
|
|
310
|
+
? undefined
|
|
311
|
+
: operation.responseDescriptor.types[firstToken];
|
|
312
|
+
if (declaredType !== undefined &&
|
|
313
|
+
declaredType !== null &&
|
|
314
|
+
NON_COLLECTION_TYPES.has(declaredType)) {
|
|
315
|
+
throw new StructuralFailure('quantifier-over-non-collection', `${site.artifactPath}${path}`, `"${pointer}" is declared "${declaredType}" by operation "${operation.operationId}", not a collection (AD-4)`);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
// Reference-set resolution.
|
|
321
|
+
/**
|
|
322
|
+
* Checks every reference-set operand with an own-property lookup.
|
|
323
|
+
* This preserves legal identifiers such as `constructor`.
|
|
324
|
+
*/
|
|
325
|
+
export function checkReferenceSetResolution(contract) {
|
|
326
|
+
const declared = contract.referenceSets ?? {};
|
|
327
|
+
const isDeclared = (id) => Object.hasOwn(declared, id);
|
|
328
|
+
forEachContractExpression(contract, (site) => {
|
|
329
|
+
const reject = (id, path) => {
|
|
330
|
+
throw new StructuralFailure('unresolved-reference-set', `${site.artifactPath}${path}`, `referenceSet "${id}" is not declared on the contract (AD-26)`);
|
|
331
|
+
};
|
|
332
|
+
walkExpression(site.expression, 0, '', {
|
|
333
|
+
onOperand: (operand, _op, _position, path) => {
|
|
334
|
+
if ('referenceSet' in operand && !isDeclared(operand.referenceSet)) {
|
|
335
|
+
reject(operand.referenceSet, path);
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
onSetOperand: (setOperand, path) => {
|
|
339
|
+
if ('referenceSet' in setOperand &&
|
|
340
|
+
!isDeclared(setOperand.referenceSet)) {
|
|
341
|
+
reject(setOperand.referenceSet, path);
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
+
/** `forbidden-input-floor-incomplete`: `forbiddenInputs` omits a floor member. */
|
|
3
|
+
export declare function checkForbiddenInputFloor(contract: EvalContract): void;
|
|
4
|
+
/** `scoped-reference-resolves-forbidden`: any scoped reference is forbidden. */
|
|
5
|
+
export declare function checkScopedResourceReferences(contract: EvalContract): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** AD-16 checks for forbidden inputs and scoped resource references. */
|
|
2
|
+
import { StructuralFailure } from '../failure-codes.js';
|
|
3
|
+
import { FORBIDDEN_INPUT_FLOOR } from '../schemas/eval-contract.js';
|
|
4
|
+
/** `forbidden-input-floor-incomplete`: `forbiddenInputs` omits a floor member. */
|
|
5
|
+
export function checkForbiddenInputFloor(contract) {
|
|
6
|
+
const declared = new Set(contract.forbiddenInputs);
|
|
7
|
+
for (const member of FORBIDDEN_INPUT_FLOOR) {
|
|
8
|
+
if (!declared.has(member)) {
|
|
9
|
+
throw new StructuralFailure('forbidden-input-floor-incomplete', 'EvalContract.forbiddenInputs', `omits mandatory floor member "${member}" (AD-16)`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** `scoped-reference-resolves-forbidden`: any scoped reference is forbidden. */
|
|
14
|
+
export function checkScopedResourceReferences(contract) {
|
|
15
|
+
const resource = contract.scopedResources?.[0];
|
|
16
|
+
if (resource === undefined)
|
|
17
|
+
return;
|
|
18
|
+
throw new StructuralFailure('scoped-reference-resolves-forbidden', 'EvalContract.scopedResources[0].reference', `scoped resource reference "${resource.reference}" is forbidden (AD-16)`);
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
+
/** Rejects permitted interface kinds that this contract version cannot run. */
|
|
3
|
+
export declare function checkInterfaceKind(contract: EvalContract): void;
|
|
4
|
+
/** Finds duplicate method and path signatures across the full inventory. */
|
|
5
|
+
export declare function checkDuplicateOperationSignature(contract: EvalContract): void;
|
|
6
|
+
/**
|
|
7
|
+
* Checks each binding key against its operation's request shape.
|
|
8
|
+
* Steps with unresolved operation IDs belong to a separate cross-field rule.
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkUndeclaredMandatoryInput(contract: EvalContract): void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks interface kinds, inventory-wide operation signatures, and step input
|
|
3
|
+
* bindings against each operation's request shape.
|
|
4
|
+
*/
|
|
5
|
+
import { StructuralFailure } from '../failure-codes.js';
|
|
6
|
+
import { TRANSPORT_CHANNELS } from '../schemas/pointer.js';
|
|
7
|
+
import { buildPlanIndex } from '../seal/plan-index.js';
|
|
8
|
+
/** Rejects permitted interface kinds that this contract version cannot run. */
|
|
9
|
+
export function checkInterfaceKind(contract) {
|
|
10
|
+
for (const iface of contract.permittedInterfaces) {
|
|
11
|
+
if (iface.kind !== 'api') {
|
|
12
|
+
throw new StructuralFailure('unsupported-interface-kind', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].kind`, `"${iface.kind}" is not supported in v0; only "api" is (AD-10)`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Erases parameter names so equivalent path templates share a signature. */
|
|
17
|
+
const PARAMETER_SEGMENT_PATTERN = /\{[A-Za-z0-9_-]+\}/g;
|
|
18
|
+
const erase = (pathTemplate) => pathTemplate.replace(PARAMETER_SEGMENT_PATTERN, '{}');
|
|
19
|
+
/** Finds duplicate method and path signatures across the full inventory. */
|
|
20
|
+
export function checkDuplicateOperationSignature(contract) {
|
|
21
|
+
const seen = new Map();
|
|
22
|
+
for (const iface of contract.permittedInterfaces) {
|
|
23
|
+
for (const operation of iface.operations) {
|
|
24
|
+
const signature = `${operation.method} ${erase(operation.pathTemplate)}`;
|
|
25
|
+
const collision = seen.get(signature);
|
|
26
|
+
if (collision !== undefined) {
|
|
27
|
+
throw new StructuralFailure('duplicate-operation-signature', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].operations[operationId=${operation.operationId}]`, `collides with permittedInterfaces[logicalId=${collision.logicalId}].operations[operationId=${collision.operation.operationId}] after parameter-name erasure ("${signature}") (AD-19, AD-40)`);
|
|
28
|
+
}
|
|
29
|
+
seen.set(signature, { logicalId: iface.logicalId, operation });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Checks each binding key against its operation's request shape.
|
|
35
|
+
* Steps with unresolved operation IDs belong to a separate cross-field rule.
|
|
36
|
+
*/
|
|
37
|
+
export function checkUndeclaredMandatoryInput(contract) {
|
|
38
|
+
const index = buildPlanIndex(contract.interactionPlan, contract.permittedInterfaces, { duplicateIds: 'unresolved' });
|
|
39
|
+
for (const step of contract.interactionPlan) {
|
|
40
|
+
const operation = index.operationOf(step.operationId);
|
|
41
|
+
if (operation === undefined)
|
|
42
|
+
continue;
|
|
43
|
+
for (const channel of TRANSPORT_CHANNELS) {
|
|
44
|
+
const binding = step.inputBinding[channel];
|
|
45
|
+
if (binding === null)
|
|
46
|
+
continue;
|
|
47
|
+
const { requiredKeys, permittedKeys } = operation.requestShape[channel];
|
|
48
|
+
for (const key of Object.keys(binding)) {
|
|
49
|
+
if (!requiredKeys.includes(key) && !permittedKeys.includes(key)) {
|
|
50
|
+
throw new StructuralFailure('undeclared-mandatory-input', `EvalContract.interactionPlan[stepId=${step.stepId}].inputBinding.${channel}[${JSON.stringify(key)}]`, `operation "${operation.operationId}" declares "${key}" in neither requiredKeys nor permittedKeys of its ${channel} channel (AD-4)`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
+
/** Rejects the first oracle missing its direction or check channel. */
|
|
3
|
+
export declare function checkOracleChannel(contract: EvalContract): void;
|
|
4
|
+
/**
|
|
5
|
+
* Bare `@/` refers to the bound element; the RFC 6901 tail stays encoded.
|
|
6
|
+
* Exported for `checkQuantifierOverNonCollection` in expression-legality.ts,
|
|
7
|
+
* which reuses it for a nested quantifier's own substitution.
|
|
8
|
+
*/
|
|
9
|
+
export declare function substitutePointer(pointer: string, boundElementRoot: string | null): string;
|
|
10
|
+
/**
|
|
11
|
+
* Checks direction targets and relation against the check, then compares
|
|
12
|
+
* direction polarity with the oracle.
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkOracleAlignment(contract: EvalContract): void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks AD-3 oracle channels and structural alignment. Alignment covers
|
|
3
|
+
* evidence targets, relation, and polarity after bound-element resolution.
|
|
4
|
+
*/
|
|
5
|
+
import { StructuralFailure } from '../failure-codes.js';
|
|
6
|
+
/** Rejects the first oracle missing its direction or check channel. */
|
|
7
|
+
export function checkOracleChannel(contract) {
|
|
8
|
+
for (const oracle of contract.oracles) {
|
|
9
|
+
if (oracle.direction === null || oracle.check === null) {
|
|
10
|
+
const missingField = oracle.direction === null ? 'direction' : 'check';
|
|
11
|
+
throw new StructuralFailure('oracle-missing-channel', `EvalContract.oracles[id=${oracle.id}].${missingField}`, `omits its ${missingField} (AD-3)`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Bare `@/` refers to the bound element; the RFC 6901 tail stays encoded.
|
|
17
|
+
* Exported for `checkQuantifierOverNonCollection` in expression-legality.ts,
|
|
18
|
+
* which reuses it for a nested quantifier's own substitution.
|
|
19
|
+
*/
|
|
20
|
+
export function substitutePointer(pointer, boundElementRoot) {
|
|
21
|
+
if (!pointer.startsWith('@'))
|
|
22
|
+
return pointer;
|
|
23
|
+
if (boundElementRoot === null)
|
|
24
|
+
return pointer;
|
|
25
|
+
const tailSource = pointer.slice(1);
|
|
26
|
+
return tailSource === '/'
|
|
27
|
+
? boundElementRoot
|
|
28
|
+
: `${boundElementRoot}${tailSource}`;
|
|
29
|
+
}
|
|
30
|
+
function operandPointer(operand, boundElementRoot) {
|
|
31
|
+
if (!('pointer' in operand))
|
|
32
|
+
return null;
|
|
33
|
+
return substitutePointer(operand.pointer, boundElementRoot);
|
|
34
|
+
}
|
|
35
|
+
/** Collects operators and resolved evidence targets across nested quantifiers. */
|
|
36
|
+
function collectTargets(expr, boundElementRoot, targets, ops) {
|
|
37
|
+
ops.add(expr.op);
|
|
38
|
+
switch (expr.op) {
|
|
39
|
+
case 'not':
|
|
40
|
+
collectTargets(expr.operands[0], boundElementRoot, targets, ops);
|
|
41
|
+
return;
|
|
42
|
+
case 'all':
|
|
43
|
+
case 'any':
|
|
44
|
+
for (const child of expr.operands)
|
|
45
|
+
collectTargets(child, boundElementRoot, targets, ops);
|
|
46
|
+
return;
|
|
47
|
+
case 'for-all':
|
|
48
|
+
case 'for-any': {
|
|
49
|
+
const collectionPointer = operandPointer(expr.collection, boundElementRoot);
|
|
50
|
+
if (collectionPointer !== null)
|
|
51
|
+
targets.add(collectionPointer);
|
|
52
|
+
collectTargets(expr.predicate, collectionPointer, targets, ops);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
case 'set-membership': {
|
|
56
|
+
const value = operandPointer(expr.operands[0], boundElementRoot);
|
|
57
|
+
if (value !== null)
|
|
58
|
+
targets.add(value);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
for (const operand of expr.operands) {
|
|
63
|
+
const pointer = operandPointer(operand, boundElementRoot);
|
|
64
|
+
if (pointer !== null)
|
|
65
|
+
targets.add(pointer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks direction targets and relation against the check, then compares
|
|
71
|
+
* direction polarity with the oracle.
|
|
72
|
+
*/
|
|
73
|
+
export function checkOracleAlignment(contract) {
|
|
74
|
+
for (const oracle of contract.oracles) {
|
|
75
|
+
const { direction, check } = oracle;
|
|
76
|
+
if (direction === null || check === null)
|
|
77
|
+
continue;
|
|
78
|
+
const targets = new Set();
|
|
79
|
+
const ops = new Set();
|
|
80
|
+
collectTargets(check, null, targets, ops);
|
|
81
|
+
for (const target of direction.evidenceTargets) {
|
|
82
|
+
if (!targets.has(target)) {
|
|
83
|
+
throw new StructuralFailure('direction-check-misaligned', `EvalContract.oracles[id=${oracle.id}].direction.evidenceTargets`, `"${target}" is not contained in check, even after quantifier substitution (AD-3)`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!ops.has(direction.relation)) {
|
|
87
|
+
throw new StructuralFailure('direction-check-misaligned', `EvalContract.oracles[id=${oracle.id}].direction.relation`, `"${direction.relation}" does not appear anywhere in check (AD-3)`);
|
|
88
|
+
}
|
|
89
|
+
if (direction.polarity !== oracle.polarity) {
|
|
90
|
+
throw new StructuralFailure('direction-check-misaligned', `EvalContract.oracles[id=${oracle.id}].direction.polarity`, `"${direction.polarity}" disagrees with the oracle's own polarity "${oracle.polarity}" (AD-3, AD-33)`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
+
import { type PlanIndex } from '../seal/plan-index.ts';
|
|
3
|
+
export declare function checkBoundElementScope(contract: EvalContract): void;
|
|
4
|
+
type ReachabilityResult = {
|
|
5
|
+
readonly reachable: true;
|
|
6
|
+
} | {
|
|
7
|
+
readonly reachable: false;
|
|
8
|
+
readonly reason: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Non-throwing core that `checkEvidenceReachability` wraps; also called
|
|
12
|
+
* directly by tests.
|
|
13
|
+
*/
|
|
14
|
+
export declare function evaluatePointerReachability(pointer: string, index: PlanIndex): ReachabilityResult;
|
|
15
|
+
/** `unreachable-check-evidence`: an interaction-rooted pointer the declared interfaces cannot produce. */
|
|
16
|
+
export declare function checkEvidenceReachability(contract: EvalContract): void;
|
|
17
|
+
export {};
|