eval-quality 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -67
- package/corpus/dev/README.md +20 -13
- package/corpus/dev/compile-seal-example/brief.json +1 -1
- package/corpus/dev/compile-seal-example/contract.json +1 -1
- package/corpus/dev/contracts/absent-collection-locations.json +1 -1
- package/corpus/dev/contracts/absent-sibling-groups.json +1 -1
- package/corpus/dev/contracts/absent-success-indicator.json +1 -1
- package/corpus/dev/contracts/empty-channel-roles.json +1 -1
- package/corpus/dev/contracts/empty-collection-locations.json +1 -1
- package/corpus/dev/contracts/empty-request-shapes.json +1 -1
- package/corpus/dev/contracts/empty-sibling-groups.json +1 -1
- package/corpus/dev/contracts/fragment-selection.json +1 -0
- package/corpus/dev/contracts/no-collection-quantifier.json +1 -1
- package/corpus/dev/contracts/no-operation-inventory.json +1 -1
- package/corpus/dev/contracts/no-read-back-relation.json +1 -1
- package/corpus/dev/contracts/no-state-change-marker.json +1 -1
- package/corpus/dev/contracts/no-type-violating-step.json +1 -1
- package/corpus/dev/contracts/per-key-split-oracles.json +1 -1
- package/corpus/dev/contracts/review-corpus.json +1 -0
- package/corpus/dev/contracts/satisfied-declarations.json +1 -1
- package/corpus/dev/contracts/single-required-response-key.json +1 -1
- package/corpus/dev/contracts/split-indicator-oracle.json +1 -1
- package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -1
- package/corpus/dev/contracts/unnamed-reference-set.json +1 -1
- package/corpus/dev/contracts/wrong-cardinality-form.json +1 -1
- package/corpus/dev/index.json +1 -1
- package/dist/application/index.d.ts +2 -0
- package/dist/application/index.js +1 -0
- package/dist/application/score.d.ts +48 -0
- package/dist/application/score.js +186 -0
- package/dist/cli/arguments.d.ts +7 -3
- package/dist/cli/arguments.js +73 -5
- package/dist/cli/exit-codes.d.ts +6 -2
- package/dist/cli/exit-codes.js +8 -9
- package/dist/cli/main.js +9 -0
- package/dist/cli/render.d.ts +3 -6
- package/dist/cli/render.js +57 -5
- package/dist/cli/run.d.ts +13 -3
- package/dist/cli/run.js +136 -16
- package/dist/core/canonical/canonicalize.d.ts +12 -0
- package/dist/core/canonical/canonicalize.js +18 -4
- package/dist/core/compile/bindings.d.ts +89 -0
- package/dist/core/compile/bindings.js +334 -0
- package/dist/core/compile/compile.d.ts +17 -0
- package/dist/core/compile/compile.js +37 -1
- package/dist/core/compile/excluded-content.d.ts +11 -0
- package/dist/core/compile/excluded-content.js +42 -0
- package/dist/core/compile/expression-legality.d.ts +49 -0
- package/dist/core/compile/expression-legality.js +158 -38
- package/dist/core/compile/forbidden-inputs.d.ts +8 -1
- package/dist/core/compile/forbidden-inputs.js +16 -3
- package/dist/core/compile/interface-inventory.d.ts +57 -2
- package/dist/core/compile/interface-inventory.js +119 -13
- package/dist/core/compile/reachability.d.ts +28 -1
- package/dist/core/compile/reachability.js +167 -35
- package/dist/core/compile/schema-version.d.ts +2 -0
- package/dist/core/compile/schema-version.js +25 -0
- package/dist/core/compile/sensitivity-witness.d.ts +31 -12
- package/dist/core/compile/sensitivity-witness.js +110 -23
- package/dist/core/compile/step-reference.d.ts +2 -0
- package/dist/core/compile/step-reference.js +49 -0
- package/dist/core/coverage/operations.d.ts +62 -0
- package/dist/core/coverage/operations.js +57 -0
- package/dist/core/coverage/relevance.d.ts +4 -2
- package/dist/core/coverage/relevance.js +22 -23
- package/dist/core/coverage/satisfaction.d.ts +2 -2
- package/dist/core/coverage/satisfaction.js +73 -48
- package/dist/core/declared-inputs.d.ts +83 -4
- package/dist/core/declared-inputs.js +105 -8
- package/dist/core/emit/emit.d.ts +9 -0
- package/dist/core/emit/emit.js +214 -0
- package/dist/core/emit/private-artifact-digest.d.ts +11 -0
- package/dist/core/emit/private-artifact-digest.js +31 -0
- package/dist/core/evaluate/evidence-resolution.d.ts +10 -3
- package/dist/core/evaluate/evidence-resolution.js +74 -11
- package/dist/core/evaluate/operators.d.ts +22 -0
- package/dist/core/evaluate/operators.js +17 -1
- package/dist/core/evaluate/resolution.d.ts +14 -3
- package/dist/core/evaluate/resolution.js +63 -3
- package/dist/core/excluded-content.d.ts +65 -0
- package/dist/core/excluded-content.js +113 -0
- package/dist/core/failure-codes.d.ts +2 -2
- package/dist/core/failure-codes.js +7 -2
- package/dist/core/ingest/conditions.d.ts +201 -0
- package/dist/core/ingest/conditions.js +48 -0
- package/dist/core/ingest/index.d.ts +13 -0
- package/dist/core/ingest/index.js +11 -0
- package/dist/core/ingest/ingest.d.ts +68 -0
- package/dist/core/ingest/ingest.js +318 -0
- package/dist/core/lineage/stage-table.d.ts +21 -4
- package/dist/core/lineage/stage-table.js +35 -3
- package/dist/core/preflight/plan.d.ts +7 -5
- package/dist/core/preflight/plan.js +75 -32
- package/dist/core/preflight/projection.d.ts +6 -3
- package/dist/core/preflight/projection.js +22 -2
- package/dist/core/preflight/reduce.js +47 -7
- package/dist/core/preflight/witness-evidence.d.ts +5 -5
- package/dist/core/preflight/witness-evidence.js +73 -20
- package/dist/core/schemas/artifact.d.ts +1049 -30
- package/dist/core/schemas/constraint-ledger.js +51 -0
- package/dist/core/schemas/defect-signature.d.ts +695 -0
- package/dist/core/schemas/defect-signature.js +175 -0
- package/dist/core/schemas/eval-contract.d.ts +550 -12
- package/dist/core/schemas/eval-contract.js +32 -2
- package/dist/core/schemas/evidence-artifact.d.ts +109 -19
- package/dist/core/schemas/evidence-artifact.js +64 -8
- package/dist/core/schemas/interface.d.ts +741 -13
- package/dist/core/schemas/interface.js +120 -7
- package/dist/core/schemas/isolation-manifest.js +16 -9
- package/dist/core/schemas/plan.d.ts +329 -3
- package/dist/core/schemas/plan.js +89 -3
- package/dist/core/schemas/pointer.d.ts +47 -1
- package/dist/core/schemas/pointer.js +89 -8
- package/dist/core/schemas/port-messages.d.ts +194 -10
- package/dist/core/schemas/port-messages.js +73 -6
- package/dist/core/schemas/probe-body.d.ts +18 -0
- package/dist/core/schemas/probe-body.js +13 -0
- package/dist/core/schemas/probe-qualification.d.ts +168 -0
- package/dist/core/schemas/probe-qualification.js +106 -0
- package/dist/core/schemas/probe.d.ts +431 -0
- package/dist/core/schemas/probe.js +6 -2
- package/dist/core/schemas/scoring-policy.d.ts +1 -0
- package/dist/core/schemas/scoring-policy.js +6 -1
- package/dist/core/schemas/sealed-evaluator-brief.d.ts +1 -0
- package/dist/core/schemas/sealed-evaluator-brief.js +4 -1
- package/dist/core/schemas/sealed-run-record.d.ts +161 -12
- package/dist/core/schemas/sealed-run-record.js +92 -15
- package/dist/core/schemas/sensitivity-witness.d.ts +108 -6
- package/dist/core/schemas/sensitivity-witness.js +61 -5
- package/dist/core/score/binding-order.d.ts +31 -0
- package/dist/core/score/binding-order.js +88 -0
- package/dist/core/score/bindings.d.ts +93 -0
- package/dist/core/score/bindings.js +309 -0
- package/dist/core/score/ladder-table.d.ts +23 -0
- package/dist/core/score/ladder-table.js +109 -0
- package/dist/core/score/ladder.d.ts +229 -0
- package/dist/core/score/ladder.js +464 -0
- package/dist/core/score/mode-agreement.d.ts +30 -0
- package/dist/core/score/mode-agreement.js +16 -0
- package/dist/core/score/outcome-table.d.ts +17 -0
- package/dist/core/score/outcome-table.js +172 -0
- package/dist/core/score/outcome.d.ts +466 -0
- package/dist/core/score/outcome.js +562 -0
- package/dist/core/score/qualification.d.ts +83 -0
- package/dist/core/score/qualification.js +645 -0
- package/dist/core/score/quotation.d.ts +56 -0
- package/dist/core/score/quotation.js +226 -0
- package/dist/core/score/reduce-trials.d.ts +80 -0
- package/dist/core/score/reduce-trials.js +90 -0
- package/dist/core/score/score.d.ts +72 -0
- package/dist/core/score/score.js +607 -0
- package/dist/core/score/selection.d.ts +80 -0
- package/dist/core/score/selection.js +98 -0
- package/dist/core/score/strength.d.ts +58 -0
- package/dist/core/score/strength.js +227 -0
- package/dist/core/score/witness.d.ts +138 -0
- package/dist/core/score/witness.js +320 -0
- package/dist/core/seal/derived-reference.d.ts +2 -9
- package/dist/core/seal/derived-reference.js +293 -46
- package/dist/core/seal/plan-index.d.ts +18 -3
- package/dist/core/seal/plan-index.js +44 -8
- package/dist/core/seal/seal.js +8 -3
- package/dist/core/stage-contracts.d.ts +62 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/ports/environment-probe-port.d.ts +60 -4
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/probe-conformance.d.ts +29 -0
- package/dist/testing/probe-conformance.js +34 -5
- package/package.json +12 -3
- package/schemas/eval-contract.schema.json +1787 -797
- package/schemas/evidence-artifact.schema.json +126 -9
- package/schemas/isolation-manifest.schema.json +17 -10
- package/schemas/probe.schema.json +636 -5
- package/schemas/rubric.schema.json +1 -1
- package/schemas/scoring-policy.schema.json +8 -1
- package/schemas/sealed-evaluator-brief.schema.json +11 -1
- package/schemas/sealed-run-record.schema.json +314 -40
|
@@ -3,11 +3,18 @@
|
|
|
3
3
|
* reference-set resolution. Each check reports the first structural failure.
|
|
4
4
|
*/
|
|
5
5
|
import { digestArtifact } from '../canonical/digest.js';
|
|
6
|
+
import { targetsDescribedChannel } from '../declared-inputs.js';
|
|
6
7
|
import { StructuralFailure } from '../failure-codes.js';
|
|
8
|
+
import { operationsOf } from '../schemas/interface.js';
|
|
7
9
|
import { JsonTypeName } from '../schemas/primitives.js';
|
|
8
|
-
import { buildPlanIndex, parseEvidenceTarget, } from '../seal/plan-index.js';
|
|
10
|
+
import { anyOperationOf, buildPlanIndex, parseEvidenceTarget, } from '../seal/plan-index.js';
|
|
9
11
|
import { substitutePointer } from './oracle-alignment.js';
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The one expression walker in this package. Contract-free and a superset of
|
|
14
|
+
* the narrower walks the checks below need, so a probe-side legality pass
|
|
15
|
+
* reuses it rather than adding a fifth traversal that can drift from it.
|
|
16
|
+
*/
|
|
17
|
+
export function walkExpression(expr, quantifierDepth, path, visitor) {
|
|
11
18
|
switch (expr.op) {
|
|
12
19
|
case 'not':
|
|
13
20
|
walkExpression(expr.operands[0], quantifierDepth, `${path}.operands[0]`, visitor);
|
|
@@ -63,7 +70,7 @@ function forEachContractExpression(contract, visit) {
|
|
|
63
70
|
});
|
|
64
71
|
});
|
|
65
72
|
contract.permittedInterfaces.forEach((iface, interfaceIndex) => {
|
|
66
|
-
iface.
|
|
73
|
+
operationsOf(iface).forEach((operation, operationIndex) => {
|
|
67
74
|
const witness = operation.sensitivityWitness;
|
|
68
75
|
if (witness === null)
|
|
69
76
|
return;
|
|
@@ -116,41 +123,129 @@ const OPERAND_LEGALITY = {
|
|
|
116
123
|
const artifactKey = (key) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)
|
|
117
124
|
? `.${key}`
|
|
118
125
|
: `[${JSON.stringify(key)}]`;
|
|
126
|
+
/**
|
|
127
|
+
* One operand's two position rules: the `OPERAND_LEGALITY` table, and the
|
|
128
|
+
* `ordering`-over-`call-inputs` rule that sits beside it. Both are decidable
|
|
129
|
+
* from the operand alone, so both cross over to a bare `Expression`.
|
|
130
|
+
*/
|
|
131
|
+
function checkOperandAtPosition(operand, op, position, artifactPath) {
|
|
132
|
+
const legal = OPERAND_LEGALITY[op]?.[String(position)];
|
|
133
|
+
if (legal === undefined)
|
|
134
|
+
return;
|
|
135
|
+
const kind = kindOf(operand);
|
|
136
|
+
if (!legal.has(kind)) {
|
|
137
|
+
throw new StructuralFailure('malformed-operator-expression', artifactPath, `"${op}" does not accept a ${kind} operand at position ${position} (AD-4, AD-26)`);
|
|
138
|
+
}
|
|
139
|
+
if (op === 'ordering' &&
|
|
140
|
+
'pointer' in operand &&
|
|
141
|
+
!operand.pointer.startsWith('@') &&
|
|
142
|
+
parseEvidenceTarget(operand.pointer).channel === 'call-inputs') {
|
|
143
|
+
throw new StructuralFailure('malformed-operator-expression', artifactPath, '"ordering" accepts observed output only, never call-inputs (AD-4)');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* `checkOperandLegality` over one bare `Expression`, minus the `covers-by-key`
|
|
148
|
+
* `expectedKey` uniqueness rule, which reads the contract's declared reference
|
|
149
|
+
* sets and has no probe-side form: a probe-side condition may carry no
|
|
150
|
+
* `{ referenceSet }` operand at all.
|
|
151
|
+
*/
|
|
152
|
+
export function checkExpressionOperandLegality(expression, artifactPath) {
|
|
153
|
+
walkExpression(expression, 0, '', {
|
|
154
|
+
onOperand: (operand, op, position, path) => {
|
|
155
|
+
checkOperandAtPosition(operand, op, position, `${artifactPath}${path}`);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/** `checkRegexConstructs` over one bare `Expression`. */
|
|
160
|
+
export function checkExpressionRegexConstructs(expression, artifactPath) {
|
|
161
|
+
walkExpression(expression, 0, '', {
|
|
162
|
+
onRegex: (pattern, path) => {
|
|
163
|
+
const rejection = regexRejection(pattern);
|
|
164
|
+
if (rejection !== null) {
|
|
165
|
+
throw new StructuralFailure('malformed-operator-expression', `${artifactPath}${path}.pattern`, `regex pattern "${pattern}" ${rejection}, a rejected construct (AD-4)`);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/** `checkQuantifierNesting` over one bare `Expression`. */
|
|
171
|
+
export function checkExpressionQuantifierNesting(expression, artifactPath) {
|
|
172
|
+
walkExpression(expression, 0, '', {
|
|
173
|
+
onQuantifier: (_expr, path, quantifierDepth) => {
|
|
174
|
+
if (quantifierDepth >= 1) {
|
|
175
|
+
throw new StructuralFailure('quantifier-nesting-exceeded', `${artifactPath}${path}`, "a quantifier appears inside another quantifier's predicate; quantifiers may not nest more than one level (AD-4)");
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
onCoversByKey: (_expr, path, quantifierDepth) => {
|
|
179
|
+
if (quantifierDepth >= 1) {
|
|
180
|
+
throw new StructuralFailure('quantifier-nesting-exceeded', `${artifactPath}${path}`, "covers-by-key appears inside a quantifier's predicate, where it may never nest (AD-4)");
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The declaration a reference-set operand names, and `undefined` when the
|
|
187
|
+
* contract declares none by that identifier. An undeclared identifier is
|
|
188
|
+
* `checkReferenceSetResolution`'s `unresolved-reference-set`, so the
|
|
189
|
+
* shape-aware checks below stay quiet about it.
|
|
190
|
+
*/
|
|
191
|
+
function declaredReferenceSetOf(contract, referenceSetId) {
|
|
192
|
+
const declarations = contract.referenceSets;
|
|
193
|
+
if (declarations === null || !Object.hasOwn(declarations, referenceSetId)) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
return declarations[referenceSetId];
|
|
197
|
+
}
|
|
119
198
|
/** Checks each operator's operands against its position-specific constraints. */
|
|
120
199
|
export function checkOperandLegality(contract) {
|
|
121
200
|
forEachContractExpression(contract, (site) => {
|
|
122
201
|
walkExpression(site.expression, 0, '', {
|
|
123
202
|
onOperand: (operand, op, position, path) => {
|
|
124
|
-
|
|
125
|
-
|
|
203
|
+
checkOperandAtPosition(operand, op, position, `${site.artifactPath}${path}`);
|
|
204
|
+
},
|
|
205
|
+
// Fires only for `set-membership`'s set position, which is the one
|
|
206
|
+
// position that reads a reference set by its single declared key
|
|
207
|
+
// (`reference-set.ts`). `keys` is `.min(1)` with no maximum, so a
|
|
208
|
+
// two-key set names no one key to read there, and a member missing
|
|
209
|
+
// the declared key has nothing to read at all. AD-26 assigns
|
|
210
|
+
// `malformed-operator-expression` to an operand type the operator
|
|
211
|
+
// does not accept, which is what each of those is. Rejecting them
|
|
212
|
+
// here is what makes the resolver's projection total.
|
|
213
|
+
onSetOperand: (setOperand, path) => {
|
|
214
|
+
if (!('referenceSet' in setOperand))
|
|
215
|
+
return;
|
|
216
|
+
const { referenceSet } = setOperand;
|
|
217
|
+
const declaration = declaredReferenceSetOf(contract, referenceSet);
|
|
218
|
+
if (declaration === undefined)
|
|
126
219
|
return;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
throw new StructuralFailure('malformed-operator-expression', `${site.artifactPath}${path}`, `"${op}" does not accept a ${kind} operand at position ${position} (AD-4, AD-26)`);
|
|
220
|
+
if (declaration.keys.length !== 1) {
|
|
221
|
+
throw new StructuralFailure('malformed-operator-expression', `${site.artifactPath}${path}`, `referenceSet "${referenceSet}" declares ${declaration.keys.length} keys, and set-membership reads exactly one, so only a single-key set is legal in its set position (AD-4, AD-26)`);
|
|
130
222
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
throw new StructuralFailure('malformed-operator-expression',
|
|
223
|
+
const key = declaration.keys[0];
|
|
224
|
+
for (const [index, member] of declaration.members.entries()) {
|
|
225
|
+
if (Object.hasOwn(member, key))
|
|
226
|
+
continue;
|
|
227
|
+
throw new StructuralFailure('malformed-operator-expression', `EvalContract.referenceSets[id=${referenceSet}].members[${index}]${artifactKey(key)}`, `referenceSet "${referenceSet}" has a member carrying no key "${key}", which it declares and which set-membership reads (AD-4, AD-26)`);
|
|
136
228
|
}
|
|
137
229
|
},
|
|
138
230
|
onCoversByKey: (expr) => {
|
|
139
231
|
const expected = expr.operands[0];
|
|
140
232
|
if (!('referenceSet' in expected))
|
|
141
233
|
return;
|
|
142
|
-
const
|
|
143
|
-
if (declarations === null ||
|
|
144
|
-
!Object.hasOwn(declarations, expected.referenceSet))
|
|
145
|
-
return;
|
|
146
|
-
const declaration = declarations[expected.referenceSet];
|
|
234
|
+
const declaration = declaredReferenceSetOf(contract, expected.referenceSet);
|
|
147
235
|
if (declaration === undefined)
|
|
148
236
|
return;
|
|
149
237
|
const seen = new Set();
|
|
150
238
|
for (const [index, member] of declaration.members.entries()) {
|
|
151
|
-
if (!Object.hasOwn(member, expr.expectedKey))
|
|
152
|
-
continue;
|
|
153
239
|
const memberPath = `EvalContract.referenceSets[id=${expected.referenceSet}].members[${index}]${artifactKey(expr.expectedKey)}`;
|
|
240
|
+
// `coversByKey` returns false for the whole collection when one
|
|
241
|
+
// declared member lacks `expectedKey`, which reads as a detected
|
|
242
|
+
// defect in the system under test, when it is an authoring
|
|
243
|
+
// mistake. This check used to walk past that member to keep the
|
|
244
|
+
// duplicate-detection loop total, which left the compiler silent
|
|
245
|
+
// about the one shape that makes the operator answer wrongly.
|
|
246
|
+
if (!Object.hasOwn(member, expr.expectedKey)) {
|
|
247
|
+
throw new StructuralFailure('malformed-operator-expression', memberPath, `referenceSet "${expected.referenceSet}" has a member carrying no expectedKey "${expr.expectedKey}", which covers-by-key reads on every member (AD-4)`);
|
|
248
|
+
}
|
|
154
249
|
const digest = digestArtifact(member[expr.expectedKey], memberPath);
|
|
155
250
|
if (seen.has(digest)) {
|
|
156
251
|
throw new StructuralFailure('malformed-operator-expression', memberPath, `referenceSet "${expected.referenceSet}" repeats expectedKey "${expr.expectedKey}" for covers-by-key (AD-4)`);
|
|
@@ -280,6 +375,47 @@ function forEachQuantifierCollection(expr, boundElementRoot, path, visit) {
|
|
|
280
375
|
return;
|
|
281
376
|
}
|
|
282
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* The check itself, against whatever resolves a step identifier to the
|
|
380
|
+
* operation that answers it. The contract path resolves through the plan index
|
|
381
|
+
* or the witness scope; a probe-side condition resolves the one reserved step
|
|
382
|
+
* identifier to the signature's home operation.
|
|
383
|
+
*/
|
|
384
|
+
function checkQuantifiersAgainst(expression, artifactPath, operationFor) {
|
|
385
|
+
forEachQuantifierCollection(expression, null, '', (pointer, path) => {
|
|
386
|
+
const target = parseEvidenceTarget(pointer);
|
|
387
|
+
const operation = operationFor(target.stepId);
|
|
388
|
+
if (operation === undefined)
|
|
389
|
+
return;
|
|
390
|
+
// The operation is resolved before the target is tested, because which
|
|
391
|
+
// channel carries the declared structure is the operation's own answer,
|
|
392
|
+
// and on the artifact channel so is which file.
|
|
393
|
+
if (!targetsDescribedChannel(operation, target))
|
|
394
|
+
return;
|
|
395
|
+
const firstToken = target.tail.length === 1 ? target.tail[0] : undefined;
|
|
396
|
+
const declaredType = firstToken === undefined
|
|
397
|
+
? undefined
|
|
398
|
+
: operation.responseDescriptor.types[firstToken];
|
|
399
|
+
if (declaredType !== undefined &&
|
|
400
|
+
declaredType !== null &&
|
|
401
|
+
NON_COLLECTION_TYPES.has(declaredType)) {
|
|
402
|
+
throw new StructuralFailure('quantifier-over-non-collection', `${artifactPath}${path}`, `"${pointer}" is declared "${declaredType}" by operation "${operation.operationId}", not a collection (AD-4)`);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* `checkQuantifierOverNonCollection` over one bare `Expression` rooted at a
|
|
408
|
+
* known set of step identifiers, all of which resolve to one operation. The
|
|
409
|
+
* `legIds` argument is load-bearing: omit it and the check silently no-ops on
|
|
410
|
+
* every expression, which is the trap the witness branch below already warns
|
|
411
|
+
* about. It reads the operation's declared response types, never its
|
|
412
|
+
* `collectionLocations`; a declared non-array type beats a contradictory
|
|
413
|
+
* collection location, and a re-derivation that read the other field would
|
|
414
|
+
* disagree with the compiler on a committed fixture.
|
|
415
|
+
*/
|
|
416
|
+
export function checkExpressionQuantifierOverNonCollection(expression, artifactPath, scope) {
|
|
417
|
+
checkQuantifiersAgainst(expression, artifactPath, (stepId) => scope.legIds.includes(stepId) ? scope.operation : undefined);
|
|
418
|
+
}
|
|
283
419
|
/** Checks response-body collection pointers, after bound-element substitution. */
|
|
284
420
|
export function checkQuantifierOverNonCollection(contract) {
|
|
285
421
|
const index = buildPlanIndex(contract.interactionPlan, contract.permittedInterfaces, { duplicateIds: 'unresolved' });
|
|
@@ -295,26 +431,10 @@ export function checkQuantifierOverNonCollection(contract) {
|
|
|
295
431
|
const step = index.stepOf(stepId);
|
|
296
432
|
if (step === undefined)
|
|
297
433
|
return undefined;
|
|
298
|
-
return index
|
|
434
|
+
return anyOperationOf(index, step.operationId);
|
|
299
435
|
};
|
|
300
436
|
forEachContractExpression(contract, (site) => {
|
|
301
|
-
|
|
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
|
-
});
|
|
437
|
+
checkQuantifiersAgainst(site.expression, site.artifactPath, (stepId) => operationFor(site, stepId));
|
|
318
438
|
});
|
|
319
439
|
}
|
|
320
440
|
// Reference-set resolution.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
2
|
/** `forbidden-input-floor-incomplete`: `forbiddenInputs` omits a floor member. */
|
|
3
3
|
export declare function checkForbiddenInputFloor(contract: EvalContract): void;
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* `scoped-reference-resolves-forbidden`: any scoped reference is forbidden,
|
|
6
|
+
* wherever the contract writes it down. `scopedResources` is read first and
|
|
7
|
+
* `testData.resources` second, each with its own message and artifact path, so
|
|
8
|
+
* a contract carrying both reports the field AD-16 names by that word. The
|
|
9
|
+
* second address uses the caller-keyed form `interface-inventory.ts` already
|
|
10
|
+
* emits, since that list is keyed by name rather than indexed.
|
|
11
|
+
*/
|
|
5
12
|
export declare function checkScopedResourceReferences(contract: EvalContract): void;
|
|
@@ -10,10 +10,23 @@ export function checkForbiddenInputFloor(contract) {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* `scoped-reference-resolves-forbidden`: any scoped reference is forbidden,
|
|
15
|
+
* wherever the contract writes it down. `scopedResources` is read first and
|
|
16
|
+
* `testData.resources` second, each with its own message and artifact path, so
|
|
17
|
+
* a contract carrying both reports the field AD-16 names by that word. The
|
|
18
|
+
* second address uses the caller-keyed form `interface-inventory.ts` already
|
|
19
|
+
* emits, since that list is keyed by name rather than indexed.
|
|
20
|
+
*/
|
|
14
21
|
export function checkScopedResourceReferences(contract) {
|
|
15
22
|
const resource = contract.scopedResources?.[0];
|
|
16
|
-
if (resource
|
|
23
|
+
if (resource !== undefined) {
|
|
24
|
+
throw new StructuralFailure('scoped-reference-resolves-forbidden', 'EvalContract.scopedResources[0].reference', `scoped resource reference "${resource.reference}" is forbidden (AD-16)`);
|
|
25
|
+
}
|
|
26
|
+
// Sorted, so which of several declared resources is reported never depends
|
|
27
|
+
// on the authored key order.
|
|
28
|
+
const declared = Object.keys(contract.testData.resources ?? {}).sort()[0];
|
|
29
|
+
if (declared === undefined)
|
|
17
30
|
return;
|
|
18
|
-
throw new StructuralFailure('scoped-reference-resolves-forbidden',
|
|
31
|
+
throw new StructuralFailure('scoped-reference-resolves-forbidden', `EvalContract.testData.resources[${JSON.stringify(declared)}]`, `declared test-data resource "${declared}" is a scoped resource reference and is forbidden (AD-16)`);
|
|
19
32
|
}
|
|
@@ -1,10 +1,65 @@
|
|
|
1
1
|
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
-
|
|
2
|
+
import type { AnyOperation } from '../schemas/interface.ts';
|
|
3
3
|
export declare function checkInterfaceKind(contract: EvalContract): void;
|
|
4
|
+
/**
|
|
5
|
+
* The transport identity AD-40 resolves a defect signature against: the method
|
|
6
|
+
* and the path template with parameter names erased, so `/notes/{id}` and
|
|
7
|
+
* `/notes/{noteId}` share one signature. Takes the two fields rather than an
|
|
8
|
+
* `Operation`, since AD-40's corpus-side signature declares the same pair and
|
|
9
|
+
* must produce the same string from it or the comparison is not a comparison.
|
|
10
|
+
*/
|
|
11
|
+
export declare function operationSignature(operation: {
|
|
12
|
+
readonly method: string;
|
|
13
|
+
readonly pathTemplate: string;
|
|
14
|
+
}): string;
|
|
15
|
+
/**
|
|
16
|
+
* The separator between a command's executable and each subcommand segment,
|
|
17
|
+
* declared once so the contract side and AD-40's corpus side cannot disagree
|
|
18
|
+
* about it. A space, matching the way the identity is written on a terminal.
|
|
19
|
+
*/
|
|
20
|
+
export declare const COMMAND_SIGNATURE_SEPARATOR = " ";
|
|
21
|
+
/**
|
|
22
|
+
* The command counterpart of `operationSignature`, compared literally.
|
|
23
|
+
*
|
|
24
|
+
* There is no erasure step. A subcommand path carries no parameters: a
|
|
25
|
+
* command's variable inputs are its arguments and options, which live in the
|
|
26
|
+
* request shape. Erasing a subcommand segment would make `tool review` and
|
|
27
|
+
* `tool report` one signature, which is the opposite of what erasure is for.
|
|
28
|
+
*/
|
|
29
|
+
export declare function commandSignature(operation: {
|
|
30
|
+
readonly invocation: {
|
|
31
|
+
readonly executable: string;
|
|
32
|
+
readonly subcommandPath: readonly string[];
|
|
33
|
+
};
|
|
34
|
+
}): string;
|
|
35
|
+
/** The transport identity of an operation of either kind. */
|
|
36
|
+
export declare const anyOperationSignature: (operation: AnyOperation) => string;
|
|
4
37
|
/** Finds duplicate method and path signatures across the full inventory. */
|
|
5
38
|
export declare function checkDuplicateOperationSignature(contract: EvalContract): void;
|
|
6
39
|
/**
|
|
7
|
-
*
|
|
40
|
+
* `unresolved-artifact-reference`: an artifact identifier nothing declares.
|
|
41
|
+
*
|
|
42
|
+
* Two sites name one: an evidence pointer's identifier segment, and a command
|
|
43
|
+
* operation's own `descriptorChannel` when it nominates an artifact. Both are
|
|
44
|
+
* authoring faults the compiler can see, and both take a code rather than
|
|
45
|
+
* resolving `absent`, on AD-26's own precedent for a dangling reference-set
|
|
46
|
+
* identifier: `absent` is defined over pointers that do not resolve against
|
|
47
|
+
* observed evidence, and a dangling declaration is neither.
|
|
48
|
+
*/
|
|
49
|
+
export declare function checkArtifactReferences(contract: EvalContract): void;
|
|
50
|
+
/**
|
|
51
|
+
* Checks each binding key against its operation's request shape, and each
|
|
52
|
+
* `{ principal }` value against the contract's declared principals.
|
|
8
53
|
* Steps with unresolved operation IDs belong to a separate cross-field rule.
|
|
54
|
+
*
|
|
55
|
+
* The two conditions share one code and are not the same predicate: the key
|
|
56
|
+
* case is an input the contract did not declare, the principal case has a
|
|
57
|
+
* declared key whose referenced name the contract did not declare. AD-5's row
|
|
58
|
+
* is widened to say so. Placing the principal case here rather than in a root
|
|
59
|
+
* Zod refinement is deliberate: a constraint reaching from
|
|
60
|
+
* `interactionPlan[].inputBinding` into `testData.principals` cannot survive
|
|
61
|
+
* the export, and the published-schema differential sweep synthesises a
|
|
62
|
+
* `{ principal }` union-branch witness naming no declared principal, which a
|
|
63
|
+
* refinement would reject and ajv would accept.
|
|
9
64
|
*/
|
|
10
65
|
export declare function checkUndeclaredMandatoryInput(contract: EvalContract): void;
|
|
@@ -2,26 +2,70 @@
|
|
|
2
2
|
* Checks interface kinds, inventory-wide operation signatures, and step input
|
|
3
3
|
* bindings against each operation's request shape.
|
|
4
4
|
*/
|
|
5
|
+
import { boundChannelsOf, declaredArtifactsOf, descriptorArtifactOf, isCommandOperation, requestShapeOf, } from '../declared-inputs.js';
|
|
5
6
|
import { StructuralFailure } from '../failure-codes.js';
|
|
6
|
-
import {
|
|
7
|
-
import { buildPlanIndex } from '../seal/plan-index.js';
|
|
8
|
-
|
|
7
|
+
import { operationsOf } from '../schemas/interface.js';
|
|
8
|
+
import { anyOperationOf, buildPlanIndex, parseEvidenceTarget, } from '../seal/plan-index.js';
|
|
9
|
+
import { forEachArtifactPointer } from './reachability.js';
|
|
10
|
+
/**
|
|
11
|
+
* Rejects permitted interface kinds whose probe semantics are undeclared.
|
|
12
|
+
*
|
|
13
|
+
* AD-10 closed all three non-api kinds and named the condition for opening
|
|
14
|
+
* one: the semantics have to be declared. They are declared for `cli`, so it
|
|
15
|
+
* runs; `web` and `mcp` are still undeclared and still fail here, which is
|
|
16
|
+
* what keeps this code fireable and keeps AD-10's sentence true of them.
|
|
17
|
+
*/
|
|
18
|
+
const SUPPORTED_INTERFACE_KINDS = ['api', 'cli'];
|
|
9
19
|
export function checkInterfaceKind(contract) {
|
|
10
20
|
for (const iface of contract.permittedInterfaces) {
|
|
11
|
-
if (iface.kind
|
|
12
|
-
throw new StructuralFailure('unsupported-interface-kind', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].kind`, `"${iface.kind}" is not supported
|
|
21
|
+
if (!SUPPORTED_INTERFACE_KINDS.includes(iface.kind)) {
|
|
22
|
+
throw new StructuralFailure('unsupported-interface-kind', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].kind`, `"${iface.kind}" is not supported; "api" and "cli" are (AD-10)`);
|
|
13
23
|
}
|
|
14
24
|
}
|
|
15
25
|
}
|
|
16
26
|
/** Erases parameter names so equivalent path templates share a signature. */
|
|
17
27
|
const PARAMETER_SEGMENT_PATTERN = /\{[A-Za-z0-9_-]+\}/g;
|
|
18
28
|
const erase = (pathTemplate) => pathTemplate.replace(PARAMETER_SEGMENT_PATTERN, '{}');
|
|
29
|
+
/**
|
|
30
|
+
* The transport identity AD-40 resolves a defect signature against: the method
|
|
31
|
+
* and the path template with parameter names erased, so `/notes/{id}` and
|
|
32
|
+
* `/notes/{noteId}` share one signature. Takes the two fields rather than an
|
|
33
|
+
* `Operation`, since AD-40's corpus-side signature declares the same pair and
|
|
34
|
+
* must produce the same string from it or the comparison is not a comparison.
|
|
35
|
+
*/
|
|
36
|
+
export function operationSignature(operation) {
|
|
37
|
+
return `${operation.method} ${erase(operation.pathTemplate)}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The separator between a command's executable and each subcommand segment,
|
|
41
|
+
* declared once so the contract side and AD-40's corpus side cannot disagree
|
|
42
|
+
* about it. A space, matching the way the identity is written on a terminal.
|
|
43
|
+
*/
|
|
44
|
+
export const COMMAND_SIGNATURE_SEPARATOR = ' ';
|
|
45
|
+
/**
|
|
46
|
+
* The command counterpart of `operationSignature`, compared literally.
|
|
47
|
+
*
|
|
48
|
+
* There is no erasure step. A subcommand path carries no parameters: a
|
|
49
|
+
* command's variable inputs are its arguments and options, which live in the
|
|
50
|
+
* request shape. Erasing a subcommand segment would make `tool review` and
|
|
51
|
+
* `tool report` one signature, which is the opposite of what erasure is for.
|
|
52
|
+
*/
|
|
53
|
+
export function commandSignature(operation) {
|
|
54
|
+
return [
|
|
55
|
+
operation.invocation.executable,
|
|
56
|
+
...operation.invocation.subcommandPath,
|
|
57
|
+
].join(COMMAND_SIGNATURE_SEPARATOR);
|
|
58
|
+
}
|
|
59
|
+
/** The transport identity of an operation of either kind. */
|
|
60
|
+
export const anyOperationSignature = (operation) => isCommandOperation(operation)
|
|
61
|
+
? commandSignature(operation)
|
|
62
|
+
: operationSignature(operation);
|
|
19
63
|
/** Finds duplicate method and path signatures across the full inventory. */
|
|
20
64
|
export function checkDuplicateOperationSignature(contract) {
|
|
21
65
|
const seen = new Map();
|
|
22
66
|
for (const iface of contract.permittedInterfaces) {
|
|
23
|
-
for (const operation of iface
|
|
24
|
-
const signature =
|
|
67
|
+
for (const operation of operationsOf(iface)) {
|
|
68
|
+
const signature = anyOperationSignature(operation);
|
|
25
69
|
const collision = seen.get(signature);
|
|
26
70
|
if (collision !== undefined) {
|
|
27
71
|
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)`);
|
|
@@ -31,23 +75,85 @@ export function checkDuplicateOperationSignature(contract) {
|
|
|
31
75
|
}
|
|
32
76
|
}
|
|
33
77
|
/**
|
|
34
|
-
*
|
|
78
|
+
* `unresolved-artifact-reference`: an artifact identifier nothing declares.
|
|
79
|
+
*
|
|
80
|
+
* Two sites name one: an evidence pointer's identifier segment, and a command
|
|
81
|
+
* operation's own `descriptorChannel` when it nominates an artifact. Both are
|
|
82
|
+
* authoring faults the compiler can see, and both take a code rather than
|
|
83
|
+
* resolving `absent`, on AD-26's own precedent for a dangling reference-set
|
|
84
|
+
* identifier: `absent` is defined over pointers that do not resolve against
|
|
85
|
+
* observed evidence, and a dangling declaration is neither.
|
|
86
|
+
*/
|
|
87
|
+
export function checkArtifactReferences(contract) {
|
|
88
|
+
for (const iface of contract.permittedInterfaces) {
|
|
89
|
+
for (const operation of operationsOf(iface)) {
|
|
90
|
+
const declared = declaredArtifactsOf(operation);
|
|
91
|
+
const nominated = descriptorArtifactOf(operation);
|
|
92
|
+
if (nominated !== null && !declared.includes(nominated)) {
|
|
93
|
+
throw new StructuralFailure('unresolved-artifact-reference', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].operations[operationId=${operation.operationId}].descriptorChannel.artifactId`, `nominates "${nominated}", which this operation does not declare it writes (AD-19, AD-26)`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const index = buildPlanIndex(contract.interactionPlan, contract.permittedInterfaces, { duplicateIds: 'unresolved' });
|
|
98
|
+
forEachArtifactPointer(contract, (pointer, path) => {
|
|
99
|
+
const target = parseEvidenceTarget(pointer);
|
|
100
|
+
if (target.artifactId === null)
|
|
101
|
+
return;
|
|
102
|
+
const step = index.stepOf(target.stepId);
|
|
103
|
+
if (step === undefined)
|
|
104
|
+
return;
|
|
105
|
+
const operation = anyOperationOf(index, step.operationId);
|
|
106
|
+
// An unresolvable step or operation is `unreachable-check-evidence`'s,
|
|
107
|
+
// at a higher rung; this check has nothing to compare against.
|
|
108
|
+
if (operation === undefined)
|
|
109
|
+
return;
|
|
110
|
+
if (declaredArtifactsOf(operation).includes(target.artifactId))
|
|
111
|
+
return;
|
|
112
|
+
throw new StructuralFailure('unresolved-artifact-reference', path, `"${pointer}" names the "${target.artifactId}" artifact, which operation "${operation.operationId}" does not declare it writes (AD-26)`);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Checks each binding key against its operation's request shape, and each
|
|
117
|
+
* `{ principal }` value against the contract's declared principals.
|
|
35
118
|
* Steps with unresolved operation IDs belong to a separate cross-field rule.
|
|
119
|
+
*
|
|
120
|
+
* The two conditions share one code and are not the same predicate: the key
|
|
121
|
+
* case is an input the contract did not declare, the principal case has a
|
|
122
|
+
* declared key whose referenced name the contract did not declare. AD-5's row
|
|
123
|
+
* is widened to say so. Placing the principal case here rather than in a root
|
|
124
|
+
* Zod refinement is deliberate: a constraint reaching from
|
|
125
|
+
* `interactionPlan[].inputBinding` into `testData.principals` cannot survive
|
|
126
|
+
* the export, and the published-schema differential sweep synthesises a
|
|
127
|
+
* `{ principal }` union-branch witness naming no declared principal, which a
|
|
128
|
+
* refinement would reject and ajv would accept.
|
|
36
129
|
*/
|
|
37
130
|
export function checkUndeclaredMandatoryInput(contract) {
|
|
38
131
|
const index = buildPlanIndex(contract.interactionPlan, contract.permittedInterfaces, { duplicateIds: 'unresolved' });
|
|
132
|
+
const principals = new Set(Object.keys(contract.testData.principals ?? {}));
|
|
39
133
|
for (const step of contract.interactionPlan) {
|
|
40
|
-
const operation = index
|
|
134
|
+
const operation = anyOperationOf(index, step.operationId);
|
|
41
135
|
if (operation === undefined)
|
|
42
136
|
continue;
|
|
43
|
-
for (const channel of
|
|
44
|
-
const binding = step.inputBinding[channel];
|
|
137
|
+
for (const { channel, bound: binding } of boundChannelsOf(step.inputBinding)) {
|
|
45
138
|
if (binding === null)
|
|
46
139
|
continue;
|
|
47
|
-
const
|
|
140
|
+
const shape = requestShapeOf(operation, channel);
|
|
141
|
+
// A step binding a channel of the other kind has no declared shape
|
|
142
|
+
// to answer to. Reporting it as an undeclared input is true as far
|
|
143
|
+
// as it goes: the operation declares no such channel, and so
|
|
144
|
+
// declares no such key on it.
|
|
145
|
+
const requiredKeys = shape?.requiredKeys ?? [];
|
|
146
|
+
const permittedKeys = shape?.permittedKeys ?? [];
|
|
48
147
|
for (const key of Object.keys(binding)) {
|
|
148
|
+
const path = `EvalContract.interactionPlan[stepId=${step.stepId}].inputBinding.${channel}[${JSON.stringify(key)}]`;
|
|
49
149
|
if (!requiredKeys.includes(key) && !permittedKeys.includes(key)) {
|
|
50
|
-
throw new StructuralFailure('undeclared-mandatory-input',
|
|
150
|
+
throw new StructuralFailure('undeclared-mandatory-input', path, `operation "${operation.operationId}" declares "${key}" in neither requiredKeys nor permittedKeys of its ${channel} channel (AD-4)`);
|
|
151
|
+
}
|
|
152
|
+
const value = binding[key];
|
|
153
|
+
if (value !== undefined &&
|
|
154
|
+
'principal' in value &&
|
|
155
|
+
!principals.has(value.principal)) {
|
|
156
|
+
throw new StructuralFailure('undeclared-mandatory-input', path, `binds the principal "${value.principal}", which testData.principals does not declare (AD-4, AD-19)`);
|
|
51
157
|
}
|
|
52
158
|
}
|
|
53
159
|
}
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
+
import type { Expression } from '../schemas/expression.ts';
|
|
3
|
+
import type { AnyOperation } from '../schemas/interface.ts';
|
|
2
4
|
import { type PlanIndex } from '../seal/plan-index.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Every interaction-rooted pointer the contract writes down, wherever it sits:
|
|
7
|
+
* an oracle's check and its direction's evidence targets, a rubric criterion's
|
|
8
|
+
* evidence, and each operation's sensitivity-witness relation.
|
|
9
|
+
*
|
|
10
|
+
* Broader than `forEachCheckPointer`, which walks oracle checks alone, because
|
|
11
|
+
* an artifact identifier is an authoring fault at every site that names one and
|
|
12
|
+
* a check that walked only the checks would report half of them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function forEachArtifactPointer(contract: EvalContract, visit: (pointer: string, artifactPath: string) => void): void;
|
|
3
15
|
export declare function checkBoundElementScope(contract: EvalContract): void;
|
|
16
|
+
/** `checkBoundElementScope` over one bare `Expression`. */
|
|
17
|
+
export declare function checkExpressionBoundElementScope(expression: Expression, artifactPath: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Visits every `{ pointer }` operand of one bare `Expression`, which a
|
|
20
|
+
* probe-side legality pass needs for the rules a contract has no equivalent of:
|
|
21
|
+
* that every pointer roots at the reserved step identifier, and which evidence
|
|
22
|
+
* channels the condition actually names.
|
|
23
|
+
*/
|
|
24
|
+
export declare function forEachExpressionPointer(expression: Expression, visit: (pointer: string, path: string) => void): void;
|
|
25
|
+
/** `checkEvidenceReachability` over one bare `Expression` and one operation. */
|
|
26
|
+
export declare function checkExpressionEvidenceReachability(expression: Expression, artifactPath: string, operation: AnyOperation): void;
|
|
4
27
|
type ReachabilityResult = {
|
|
5
28
|
readonly reachable: true;
|
|
6
29
|
} | {
|
|
@@ -9,7 +32,11 @@ type ReachabilityResult = {
|
|
|
9
32
|
};
|
|
10
33
|
/**
|
|
11
34
|
* Non-throwing core that `checkEvidenceReachability` wraps; also called
|
|
12
|
-
* directly by tests.
|
|
35
|
+
* directly by tests. The two lines below are the whole of what ties this to a
|
|
36
|
+
* declared interaction plan; everything past them reads the operation alone,
|
|
37
|
+
* which is what `evaluateReachabilityAgainstOperation` exposes for a probe-side
|
|
38
|
+
* condition, whose one step identifier is reserved and resolves to the
|
|
39
|
+
* signature's home operation with no plan in sight.
|
|
13
40
|
*/
|
|
14
41
|
export declare function evaluatePointerReachability(pointer: string, index: PlanIndex): ReachabilityResult;
|
|
15
42
|
/** `unreachable-check-evidence`: an interaction-rooted pointer the declared interfaces cannot produce. */
|