eval-quality 0.2.0 → 0.5.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 +17 -12
- package/corpus/dev/README.md +3 -2
- 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/adapters/command-line-adapter.d.ts +44 -0
- package/dist/adapters/command-line-adapter.js +284 -0
- package/dist/adapters/command-target-policy.d.ts +36 -0
- package/dist/adapters/command-target-policy.js +33 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.js +1 -0
- package/dist/cli/render.d.ts +2 -5
- package/dist/cli/render.js +51 -1
- package/dist/core/compile/bindings.d.ts +26 -7
- package/dist/core/compile/bindings.js +49 -32
- package/dist/core/compile/compile.d.ts +12 -0
- package/dist/core/compile/compile.js +28 -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 +2 -2
- package/dist/core/compile/expression-legality.js +58 -12
- package/dist/core/compile/interface-inventory.d.ts +34 -1
- package/dist/core/compile/interface-inventory.js +88 -11
- package/dist/core/compile/reachability.d.ts +12 -2
- package/dist/core/compile/reachability.js +123 -36
- 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/evaluate/evidence-resolution.d.ts +9 -12
- package/dist/core/evaluate/evidence-resolution.js +70 -10
- 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 +5 -2
- package/dist/core/ingest/conditions.d.ts +1 -1
- package/dist/core/ingest/ingest.js +8 -0
- 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 +63 -20
- package/dist/core/schemas/artifact.d.ts +683 -35
- package/dist/core/schemas/constraint-ledger.js +11 -0
- package/dist/core/schemas/defect-signature.d.ts +438 -16
- package/dist/core/schemas/defect-signature.js +58 -10
- package/dist/core/schemas/eval-contract.d.ts +517 -12
- package/dist/core/schemas/eval-contract.js +18 -2
- package/dist/core/schemas/evidence-artifact.d.ts +14 -4
- package/dist/core/schemas/evidence-artifact.js +1 -1
- 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 +217 -3
- package/dist/core/schemas/plan.js +22 -1
- 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-policy.d.ts +36 -0
- package/dist/core/schemas/probe-policy.js +44 -0
- package/dist/core/schemas/probe.d.ts +122 -3
- package/dist/core/schemas/probe.js +1 -1
- package/dist/core/schemas/sealed-run-record.d.ts +131 -9
- package/dist/core/schemas/sealed-run-record.js +56 -11
- package/dist/core/schemas/sensitivity-witness.d.ts +108 -6
- package/dist/core/schemas/sensitivity-witness.js +61 -5
- package/dist/core/score/bindings.d.ts +2 -2
- package/dist/core/score/bindings.js +25 -13
- package/dist/core/score/qualification.d.ts +5 -5
- package/dist/core/score/qualification.js +67 -37
- package/dist/core/score/quotation.d.ts +1 -24
- package/dist/core/score/quotation.js +29 -4
- package/dist/core/score/score.js +28 -2
- package/dist/core/score/strength.d.ts +9 -0
- package/dist/core/score/strength.js +35 -1
- package/dist/core/score/witness.d.ts +21 -0
- package/dist/core/score/witness.js +9 -4
- package/dist/core/seal/derived-reference.d.ts +2 -9
- package/dist/core/seal/derived-reference.js +62 -23
- package/dist/core/seal/plan-index.d.ts +18 -3
- package/dist/core/seal/plan-index.js +44 -8
- 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/conformance.d.ts +2 -1
- package/dist/testing/conformance.js +1 -0
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +1 -1
- package/dist/testing/probe-conformance.d.ts +56 -5
- package/dist/testing/probe-conformance.js +196 -5
- package/package.json +1 -1
- package/schemas/eval-contract.schema.json +1356 -464
- package/schemas/evidence-artifact.schema.json +59 -29
- package/schemas/isolation-manifest.schema.json +17 -10
- package/schemas/probe.schema.json +197 -71
- package/schemas/rubric.schema.json +1 -1
- package/schemas/sealed-run-record.schema.json +296 -39
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AD-18's excluded categories, as patterns that read a value rather than a name.
|
|
3
|
+
*
|
|
4
|
+
* AD-18 excludes "credentials, tokens, real names, email addresses, account
|
|
5
|
+
* identifiers, and transaction content" from every artifact this package
|
|
6
|
+
* produces or publishes, and binds "published examples and test fixtures as
|
|
7
|
+
* strictly as real runs". Until this module the whole prohibition was carried by
|
|
8
|
+
* one test that scans `corpus/dev`, so a contract carrying a live-shaped token
|
|
9
|
+
* compiled clean and the token travelled into the sealed brief.
|
|
10
|
+
*
|
|
11
|
+
* Only the value-shaped half of that scan ships here, and the split is the point
|
|
12
|
+
* rather than an economy. AD-18's own reading of the rule for the header channel
|
|
13
|
+
* is that a declaration "names the header and its type and never carries a
|
|
14
|
+
* credential value", so a name is what an author is supposed to write: an
|
|
15
|
+
* operation declaring a `password` body key or an `Authorization` header is a
|
|
16
|
+
* contract for an authentication API, and a gate matching `\bpassword\b` would
|
|
17
|
+
* reject exactly the systems this package exists to evaluate. The patterns below
|
|
18
|
+
* therefore match only strings whose shape is decidable without knowing what
|
|
19
|
+
* field they sit in: a PEM header, a token with an issuer prefix, an address, a
|
|
20
|
+
* checkable account number, a card-shaped digit run. The name-shaped patterns
|
|
21
|
+
* stay in `tests/architecture/dev-corpus.test.ts`, where review rather than a
|
|
22
|
+
* compiler decides.
|
|
23
|
+
*
|
|
24
|
+
* Each pattern carries a string it must fire on, and a test asserts every one
|
|
25
|
+
* still does. A pattern that has rotted into a regex matching nothing is worse
|
|
26
|
+
* than no pattern: it reports clean forever.
|
|
27
|
+
*/
|
|
28
|
+
/** AD-18's six categories, in the rule's own order. */
|
|
29
|
+
export const EXCLUDED_CATEGORIES = [
|
|
30
|
+
'credentials',
|
|
31
|
+
'tokens',
|
|
32
|
+
'real names',
|
|
33
|
+
'email addresses',
|
|
34
|
+
'account identifiers',
|
|
35
|
+
'transaction content',
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* `real names` has no member here and never will: a personal name has no surface
|
|
39
|
+
* form, so every pattern that reaches one reads the field that carries it, which
|
|
40
|
+
* is a name-shaped test. The category stays in the tuple above because AD-18
|
|
41
|
+
* names six and dropping one from the vocabulary would make the gate look total.
|
|
42
|
+
*/
|
|
43
|
+
export const EXCLUDED_VALUE_PATTERNS = [
|
|
44
|
+
{
|
|
45
|
+
category: 'credentials',
|
|
46
|
+
regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
47
|
+
fires: '-----BEGIN RSA PRIVATE KEY-----',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
category: 'tokens',
|
|
51
|
+
regex: /(?<![A-Za-z])(?:[Bb]earer\s+[\w.~+/-]{16,}|eyJ[\w-]{8,}\.[\w-]{8,}|sk-[A-Za-z0-9]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|AKIA[0-9A-Z]{16})/,
|
|
52
|
+
fires: 'Authorization: Bearer abcdefghijklmnopqrstuv',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
category: 'email addresses',
|
|
56
|
+
regex: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/,
|
|
57
|
+
fires: '{"contact":"ada@example.com"}',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
// Case-sensitive: an IBAN is upper case, and a case-insensitive form
|
|
61
|
+
// matches a run inside a lower-case hex digest.
|
|
62
|
+
category: 'account identifiers',
|
|
63
|
+
regex: /\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b|\b\d{3}-\d{2}-\d{4}\b/,
|
|
64
|
+
fires: 'GB29NWBK60161331926819',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
category: 'transaction content',
|
|
68
|
+
regex: /(?<![0-9A-Za-z])\d{4}(?:[ -]\d{4}){3}(?![0-9A-Za-z])/,
|
|
69
|
+
fires: 'charged 4111 1111 1111 1111',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
const step = (path, key) => typeof key === 'number' ? `${path}[${key}]` : `${path}.${key}`;
|
|
73
|
+
/**
|
|
74
|
+
* Every string anywhere inside one value, against every value-shaped pattern.
|
|
75
|
+
*
|
|
76
|
+
* Object keys are walked as paths and never scanned as content: a key is a name
|
|
77
|
+
* by construction, which is the same line the pattern set is drawn on. The walk
|
|
78
|
+
* is total over JSON and stops at nothing, so a token nested under a body
|
|
79
|
+
* example twelve levels down is found; the first matching category per string
|
|
80
|
+
* wins, since one string reported six times says nothing more than once.
|
|
81
|
+
*
|
|
82
|
+
* Order is the walk's order, which for an object is its own key order. A caller
|
|
83
|
+
* that needs a stable report over two spellings of the same object sorts what
|
|
84
|
+
* comes back; the compile gate below reads only the first hit and never the
|
|
85
|
+
* order.
|
|
86
|
+
*/
|
|
87
|
+
export function scanExcludedContent(value, path) {
|
|
88
|
+
const hits = [];
|
|
89
|
+
const visit = (node, at) => {
|
|
90
|
+
if (typeof node === 'string') {
|
|
91
|
+
for (const { category, regex } of EXCLUDED_VALUE_PATTERNS) {
|
|
92
|
+
const match = regex.exec(node);
|
|
93
|
+
if (match === null)
|
|
94
|
+
continue;
|
|
95
|
+
hits.push({ category, path: at, match: match[0] });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (Array.isArray(node)) {
|
|
101
|
+
node.forEach((element, index) => {
|
|
102
|
+
visit(element, step(at, index));
|
|
103
|
+
});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (node === null || typeof node !== 'object')
|
|
107
|
+
return;
|
|
108
|
+
for (const [key, child] of Object.entries(node))
|
|
109
|
+
visit(child, step(at, key));
|
|
110
|
+
};
|
|
111
|
+
visit(value, path);
|
|
112
|
+
return hits;
|
|
113
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** AD-5's twenty-
|
|
2
|
-
export declare const FAILURE_CODES: readonly ['missing-requirement-linkage', 'no-observable-success-criterion', 'unreachable-check-evidence', 'malformed-operator-expression', 'quantifier-over-non-collection', 'quantifier-nesting-exceeded', 'unresolved-reference-set', 'duplicate-operation-signature', 'undeclared-mandatory-input', 'oracle-missing-channel', 'direction-check-misaligned', 'unsupported-interface-kind', 'nested-temporal-clause', 'plan-exceeds-scripting-bound', 'binding-cycle', 'captured-channel-undeclared', 'rubric-scores-reasoning-prose', 'rubric-unanchored', 'rubric-evidence-unreachable', 'forbidden-input-floor-incomplete', 'scoped-reference-resolves-forbidden', 'waiver-incomplete', 'brief-exceeds-scripting-bound'];
|
|
1
|
+
/** AD-5's twenty-six compile-time failure codes, as data, in the table's order. */
|
|
2
|
+
export declare const FAILURE_CODES: readonly ['missing-requirement-linkage', 'no-observable-success-criterion', 'unreachable-check-evidence', 'malformed-operator-expression', 'quantifier-over-non-collection', 'quantifier-nesting-exceeded', 'unresolved-reference-set', 'duplicate-operation-signature', 'undeclared-mandatory-input', 'oracle-missing-channel', 'direction-check-misaligned', 'unsupported-interface-kind', 'nested-temporal-clause', 'plan-exceeds-scripting-bound', 'binding-cycle', 'captured-channel-undeclared', 'rubric-scores-reasoning-prose', 'rubric-unanchored', 'rubric-evidence-unreachable', 'forbidden-input-floor-incomplete', 'scoped-reference-resolves-forbidden', 'waiver-incomplete', 'brief-exceeds-scripting-bound', 'unresolved-artifact-reference', 'irreducible-step-reference', 'excluded-content-in-declaration'];
|
|
3
3
|
export type FailureCode = (typeof FAILURE_CODES)[number];
|
|
4
4
|
/**
|
|
5
5
|
* AD-5's compile-time failure registry: thrown when a structural error fails
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/** AD-5's twenty-
|
|
1
|
+
/** AD-5's twenty-six compile-time failure codes, as data, in the table's order. */
|
|
2
2
|
// This lives in `core/`, since it's a plain data tuple and `core/schemas/`
|
|
3
3
|
// is reserved for Zod definitions. The compiler that emits these codes lives
|
|
4
4
|
// in `core/compile/`, one directory over.
|
|
5
5
|
//
|
|
6
6
|
// `scripts/check-ad5-registry.ts` checks this tuple against AD-5's own
|
|
7
7
|
// registry table under `npm run validate`; the tuple's own invariants
|
|
8
|
-
// (twenty-
|
|
8
|
+
// (twenty-six members, unique, kebab-case) are locked in
|
|
9
9
|
// tests/schemas/failure-codes.test.ts.
|
|
10
10
|
export const FAILURE_CODES = [
|
|
11
11
|
'missing-requirement-linkage',
|
|
@@ -31,6 +31,9 @@ export const FAILURE_CODES = [
|
|
|
31
31
|
'scoped-reference-resolves-forbidden',
|
|
32
32
|
'waiver-incomplete',
|
|
33
33
|
'brief-exceeds-scripting-bound',
|
|
34
|
+
'unresolved-artifact-reference',
|
|
35
|
+
'irreducible-step-reference',
|
|
36
|
+
'excluded-content-in-declaration',
|
|
34
37
|
];
|
|
35
38
|
/**
|
|
36
39
|
* AD-5's compile-time failure registry: thrown when a structural error fails
|
|
@@ -67,7 +67,7 @@ export type AgreementField = (typeof AGREEMENT_FIELDS)[number];
|
|
|
67
67
|
*/
|
|
68
68
|
export type DuplicateRecordIdentifier = {
|
|
69
69
|
readonly kind: Extract<IngestConditionKind, 'duplicate-record-identifier'>;
|
|
70
|
-
readonly subject: 'observation' | 'finding' | 'oracle-disposition';
|
|
70
|
+
readonly subject: 'observation' | 'finding' | 'oracle-disposition' | 'judge-result';
|
|
71
71
|
readonly identifier: string;
|
|
72
72
|
readonly occurrences: number;
|
|
73
73
|
};
|
|
@@ -106,6 +106,14 @@ export const ingest = (record, manifest, configuration) => {
|
|
|
106
106
|
'oracle-disposition',
|
|
107
107
|
record.oracleDispositions.map((disposition) => disposition.oracleId),
|
|
108
108
|
],
|
|
109
|
+
// AD-17's "one judge call scoring all named criteria", read as far as
|
|
110
|
+
// one record can be read: a criterion scored twice is not one call's
|
|
111
|
+
// product whatever the rest of the record says. Keyed by the pair,
|
|
112
|
+
// since two rubrics may each declare a criterion of the same name.
|
|
113
|
+
[
|
|
114
|
+
'judge-result',
|
|
115
|
+
record.judgeResults.map((result) => `${result.rubricId}/${result.criterionId}`),
|
|
116
|
+
],
|
|
109
117
|
]) {
|
|
110
118
|
const counts = new Map();
|
|
111
119
|
for (const identifier of identifiers) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { ReferenceSetKeys } from '../evaluate/resolution.ts';
|
|
1
2
|
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
-
import type {
|
|
3
|
+
import type { AnyOperation } from '../schemas/interface.ts';
|
|
3
4
|
import type { ProbeRequest } from '../schemas/port-messages.ts';
|
|
4
5
|
import type { JsonValue } from '../schemas/primitives.ts';
|
|
5
6
|
import type { Probe } from '../schemas/probe.ts';
|
|
@@ -15,7 +16,7 @@ export type PlannedLeg = {
|
|
|
15
16
|
readonly legId: string;
|
|
16
17
|
readonly purpose: PlannedLegPurpose;
|
|
17
18
|
readonly request: ProbeRequest;
|
|
18
|
-
readonly operation:
|
|
19
|
+
readonly operation: AnyOperation;
|
|
19
20
|
readonly inputs: WitnessInputs;
|
|
20
21
|
};
|
|
21
22
|
export type PlannedCheck = {
|
|
@@ -28,7 +29,7 @@ export type PlannedCheck = {
|
|
|
28
29
|
readonly interfaceId: string;
|
|
29
30
|
readonly operationId: string;
|
|
30
31
|
readonly witness: SensitivityWitness | null;
|
|
31
|
-
readonly operation:
|
|
32
|
+
readonly operation: AnyOperation;
|
|
32
33
|
} | {
|
|
33
34
|
readonly kind: 'state-reset';
|
|
34
35
|
readonly legIds: readonly [string, string];
|
|
@@ -39,19 +40,20 @@ export type PlannedCheck = {
|
|
|
39
40
|
readonly kind: 'seeded-faults-scoped';
|
|
40
41
|
readonly defectId: string;
|
|
41
42
|
readonly witness: ManifestationWitness;
|
|
42
|
-
readonly operation:
|
|
43
|
+
readonly operation: AnyOperation;
|
|
43
44
|
readonly cleanLegIds: readonly string[];
|
|
44
45
|
} | {
|
|
45
46
|
readonly kind: 'seeded-fault-fired';
|
|
46
47
|
readonly defectId: string;
|
|
47
48
|
readonly witness: ManifestationWitness | null;
|
|
48
|
-
readonly operation:
|
|
49
|
+
readonly operation: AnyOperation | null;
|
|
49
50
|
};
|
|
50
51
|
export type PreflightPlan = {
|
|
51
52
|
readonly runId: string;
|
|
52
53
|
readonly legs: readonly PlannedLeg[];
|
|
53
54
|
readonly checks: readonly PlannedCheck[];
|
|
54
55
|
readonly referenceSets: Readonly<Record<string, JsonValue[]>>;
|
|
56
|
+
readonly referenceSetKeys: ReferenceSetKeys;
|
|
55
57
|
};
|
|
56
58
|
/**
|
|
57
59
|
* AD-10's plan, derived from the interfaces the contract's probes exercise.
|
|
@@ -8,25 +8,53 @@
|
|
|
8
8
|
* the operation and the witness themselves: there is nothing to look an
|
|
9
9
|
* identifier up in at reduce time.
|
|
10
10
|
*/
|
|
11
|
-
import { checkInputsAgainstShape } from '../compile/sensitivity-witness.js';
|
|
12
|
-
import { declaresNoRequiredKeys } from '../declared-inputs.js';
|
|
11
|
+
import { checkInputsAgainstShape, isApiWitnessInputs, } from '../compile/sensitivity-witness.js';
|
|
12
|
+
import { declaresNoRequiredKeys, isCommandOperation, } from '../declared-inputs.js';
|
|
13
|
+
import { referenceSetKeysOf } from '../evaluate/evidence-resolution.js';
|
|
13
14
|
import { StructuralFailure } from '../failure-codes.js';
|
|
15
|
+
import { operationsOf } from '../schemas/interface.js';
|
|
14
16
|
import { referenceSetMembers } from './witness-evidence.js';
|
|
15
|
-
const requestOf = (legId, interfaceId, operation, inputs) =>
|
|
16
|
-
// NFR9's correlation by identifier: the port echoes
|
|
17
|
-
// the only thing that tells two legs of one operation apart.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
const requestOf = (legId, interfaceId, operation, inputs) => {
|
|
18
|
+
// NFR9's correlation by identifier: the port echoes these back, and they
|
|
19
|
+
// are the only thing that tells two legs of one operation apart.
|
|
20
|
+
const correlation = {
|
|
21
|
+
probeId: legId,
|
|
22
|
+
interfaceId,
|
|
23
|
+
operationId: operation.operationId,
|
|
24
|
+
};
|
|
25
|
+
if (isCommandOperation(operation)) {
|
|
26
|
+
if (isApiWitnessInputs(inputs)) {
|
|
27
|
+
throw new StructuralFailure('undeclared-mandatory-input', `EvalContract.permittedInterfaces[logicalId=${interfaceId}].operations[operationId=${operation.operationId}]`, `leg "${legId}" supplies transport channels to an operation that runs behind a command (AD-10, AD-19)`);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
...correlation,
|
|
31
|
+
kind: 'cli',
|
|
32
|
+
executable: operation.invocation.executable,
|
|
33
|
+
subcommandPath: operation.invocation.subcommandPath,
|
|
34
|
+
channels: {
|
|
35
|
+
argument: inputs.argument,
|
|
36
|
+
option: inputs.option,
|
|
37
|
+
environment: inputs.environment,
|
|
38
|
+
stdin: inputs.stdin,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (!isApiWitnessInputs(inputs)) {
|
|
43
|
+
throw new StructuralFailure('undeclared-mandatory-input', `EvalContract.permittedInterfaces[logicalId=${interfaceId}].operations[operationId=${operation.operationId}]`, `leg "${legId}" supplies command channels to an operation that speaks HTTP (AD-10, AD-19)`);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
...correlation,
|
|
47
|
+
kind: 'api',
|
|
48
|
+
method: operation.method,
|
|
49
|
+
pathTemplate: operation.pathTemplate,
|
|
50
|
+
channels: {
|
|
51
|
+
path: inputs.path,
|
|
52
|
+
query: inputs.query,
|
|
53
|
+
header: inputs.header,
|
|
54
|
+
body: inputs.body,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
};
|
|
30
58
|
/**
|
|
31
59
|
* The contract declares no identifier for a control leg, so one is minted, and it
|
|
32
60
|
* has to avoid every identifier the contract already spends. The same input
|
|
@@ -57,13 +85,19 @@ const declaredLegIds = (contract, probes) => {
|
|
|
57
85
|
taken.add(legId);
|
|
58
86
|
}
|
|
59
87
|
for (const iface of contract.permittedInterfaces)
|
|
60
|
-
for (const operation of iface
|
|
88
|
+
for (const operation of operationsOf(iface))
|
|
61
89
|
for (const leg of operation.sensitivityWitness?.legs ?? [])
|
|
62
90
|
taken.add(leg.legId);
|
|
63
91
|
if (contract.fixtureReset !== null)
|
|
64
92
|
taken.add(contract.fixtureReset.legId);
|
|
65
93
|
return taken;
|
|
66
94
|
};
|
|
95
|
+
const EMPTY_COMMAND_INPUTS = {
|
|
96
|
+
argument: {},
|
|
97
|
+
option: {},
|
|
98
|
+
environment: {},
|
|
99
|
+
stdin: { kind: 'absent' },
|
|
100
|
+
};
|
|
67
101
|
const EMPTY_INPUTS = {
|
|
68
102
|
path: {},
|
|
69
103
|
query: {},
|
|
@@ -85,7 +119,12 @@ const controlInputs = (operation) => {
|
|
|
85
119
|
const declared = operation.sensitivityWitness?.legs[0]?.inputs;
|
|
86
120
|
if (declared !== undefined)
|
|
87
121
|
return declared;
|
|
88
|
-
|
|
122
|
+
// AD-10 exempts an operation with no required key, so an empty leg is a
|
|
123
|
+
// legal request for it. Which empty leg depends on the kind, because the
|
|
124
|
+
// port sends what the operation's own channels name.
|
|
125
|
+
if (!declaresNoRequiredKeys(operation))
|
|
126
|
+
return null;
|
|
127
|
+
return isCommandOperation(operation) ? EMPTY_COMMAND_INPUTS : EMPTY_INPUTS;
|
|
89
128
|
};
|
|
90
129
|
const targetOf = (iface, operation) => {
|
|
91
130
|
const inputs = controlInputs(operation);
|
|
@@ -98,10 +137,10 @@ const targetOf = (iface, operation) => {
|
|
|
98
137
|
* marker-true operation on the interface the fixture reset names, resolved
|
|
99
138
|
* independently of where the observed read came from.
|
|
100
139
|
*/
|
|
101
|
-
const selectControl = (contract) => {
|
|
140
|
+
const selectControl = (contract, permittedInterfaces) => {
|
|
102
141
|
let observed = null;
|
|
103
|
-
for (const iface of
|
|
104
|
-
for (const operation of iface
|
|
142
|
+
for (const iface of permittedInterfaces) {
|
|
143
|
+
for (const operation of operationsOf(iface)) {
|
|
105
144
|
if (operation.stateChangeMarker)
|
|
106
145
|
continue;
|
|
107
146
|
observed = targetOf(iface, operation);
|
|
@@ -116,11 +155,13 @@ const selectControl = (contract) => {
|
|
|
116
155
|
const reset = contract.fixtureReset;
|
|
117
156
|
if (reset === null)
|
|
118
157
|
return { observed, mutating: null };
|
|
119
|
-
const resetInterface =
|
|
158
|
+
const resetInterface = permittedInterfaces.find((candidate) => candidate.logicalId === reset.interfaceId);
|
|
120
159
|
let mutating = null;
|
|
121
160
|
for (const operation of resetInterface?.operations ?? []) {
|
|
122
161
|
if (!operation.stateChangeMarker)
|
|
123
162
|
continue;
|
|
163
|
+
if (resetInterface === undefined)
|
|
164
|
+
break;
|
|
124
165
|
mutating = targetOf(resetInterface, operation);
|
|
125
166
|
if (mutating !== null)
|
|
126
167
|
break;
|
|
@@ -141,12 +182,13 @@ const selectControl = (contract) => {
|
|
|
141
182
|
export const planPreflight = (input) => {
|
|
142
183
|
const { contract, probes, runId } = input;
|
|
143
184
|
for (const iface of contract.permittedInterfaces) {
|
|
144
|
-
// Already thrown at compile; asserted again because the plan is
|
|
145
|
-
// from a caller who assembled a contract by hand.
|
|
146
|
-
if (iface.kind !== 'api') {
|
|
147
|
-
throw new StructuralFailure('unsupported-interface-kind', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].kind`, `"${iface.kind}" is not supported
|
|
185
|
+
// Already thrown at compile; asserted again because the plan is
|
|
186
|
+
// reachable from a caller who assembled a contract by hand.
|
|
187
|
+
if (iface.kind !== 'api' && iface.kind !== 'cli') {
|
|
188
|
+
throw new StructuralFailure('unsupported-interface-kind', `EvalContract.permittedInterfaces[logicalId=${iface.logicalId}].kind`, `"${iface.kind}" is not supported; "api" and "cli" are (AD-10)`);
|
|
148
189
|
}
|
|
149
190
|
}
|
|
191
|
+
const permittedInterfaces = contract.permittedInterfaces;
|
|
150
192
|
const origins = [];
|
|
151
193
|
const checks = [];
|
|
152
194
|
// Keyed by interface AND operation: `Operation.operationId` is scoped to a
|
|
@@ -175,8 +217,8 @@ export const planPreflight = (input) => {
|
|
|
175
217
|
group.push(legId);
|
|
176
218
|
};
|
|
177
219
|
// 1. the sensitivity legs and their checks
|
|
178
|
-
|
|
179
|
-
iface.
|
|
220
|
+
permittedInterfaces.forEach((iface, interfaceIndex) => {
|
|
221
|
+
operationsOf(iface).forEach((operation, operationIndex) => {
|
|
180
222
|
const witness = operation.sensitivityWitness;
|
|
181
223
|
const path = `EvalContract.permittedInterfaces[${interfaceIndex}].operations[${operationIndex}]`;
|
|
182
224
|
if (witness !== null)
|
|
@@ -193,7 +235,7 @@ export const planPreflight = (input) => {
|
|
|
193
235
|
});
|
|
194
236
|
});
|
|
195
237
|
// 3. the control legs, once per contract
|
|
196
|
-
const control = selectControl(contract);
|
|
238
|
+
const control = selectControl(contract, permittedInterfaces);
|
|
197
239
|
const controlLegIds = [];
|
|
198
240
|
if (control !== null) {
|
|
199
241
|
const taken = declaredLegIds(contract, probes);
|
|
@@ -215,7 +257,7 @@ export const planPreflight = (input) => {
|
|
|
215
257
|
const mutate = mintControl('preflight-control-mutate');
|
|
216
258
|
addLeg(mutate, 'control-mutate', mutating.iface.logicalId, mutating.operation, mutating.inputs, `the minted control-mutate leg against "${mutating.operation.operationId}"`);
|
|
217
259
|
controlLegIds.push(mutate);
|
|
218
|
-
const resetOperation = mutating.iface.
|
|
260
|
+
const resetOperation = operationsOf(mutating.iface).find((candidate) => candidate.operationId === reset.operationId);
|
|
219
261
|
if (resetOperation === undefined) {
|
|
220
262
|
throw new StructuralFailure('unreachable-check-evidence', 'EvalContract.fixtureReset', `the fixture reset names operation "${reset.operationId}" on interface "${reset.interfaceId}", which the contract does not declare (AD-10)`);
|
|
221
263
|
}
|
|
@@ -246,7 +288,7 @@ export const planPreflight = (input) => {
|
|
|
246
288
|
});
|
|
247
289
|
continue;
|
|
248
290
|
}
|
|
249
|
-
const iface =
|
|
291
|
+
const iface = permittedInterfaces.find((candidate) => candidate.logicalId === witness.interfaceId);
|
|
250
292
|
const operation = iface?.operations.find((candidate) => candidate.operationId === witness.operationId);
|
|
251
293
|
if (operation === undefined) {
|
|
252
294
|
throw new StructuralFailure('unreachable-check-evidence', path, `the manifestation witness names operation "${witness.operationId}" on interface "${witness.interfaceId}", which the contract does not declare (AD-10)`);
|
|
@@ -309,5 +351,6 @@ export const planPreflight = (input) => {
|
|
|
309
351
|
legs: origins.map((origin) => origin.leg),
|
|
310
352
|
checks: [...presence, ...checks],
|
|
311
353
|
referenceSets: referenceSetMembers(contract),
|
|
354
|
+
referenceSetKeys: referenceSetKeysOf(contract),
|
|
312
355
|
};
|
|
313
356
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AnyOperation } from '../schemas/interface.ts';
|
|
2
2
|
import type { ProbeObservation, ProbeObservedBody } from '../schemas/port-messages.ts';
|
|
3
3
|
export declare const PREFLIGHT_ARTIFACT_PATH = "PreflightVerdict";
|
|
4
4
|
/**
|
|
@@ -17,7 +17,10 @@ export type ProjectedObservation = {
|
|
|
17
17
|
readonly legId: string;
|
|
18
18
|
readonly interfaceId: string;
|
|
19
19
|
readonly operationId: string;
|
|
20
|
-
|
|
20
|
+
/** the transport status, or `null` off an interface that speaks HTTP. */
|
|
21
|
+
readonly status: number | null;
|
|
22
|
+
/** the process exit code, or `null` on an interface that does. */
|
|
23
|
+
readonly exitCode: number | null;
|
|
21
24
|
readonly body: ProbeObservedBody;
|
|
22
25
|
};
|
|
23
26
|
/**
|
|
@@ -27,7 +30,7 @@ export type ProjectedObservation = {
|
|
|
27
30
|
*/
|
|
28
31
|
export declare function pruneVolatile(body: ProbeObservedBody, volatilePointers: readonly string[], artifactPath: string): ProbeObservedBody;
|
|
29
32
|
/** One observation reduced to the projection, with its volatile pointers gone. */
|
|
30
|
-
export declare function projectObservation(observation: ProbeObservation, operation:
|
|
33
|
+
export declare function projectObservation(observation: ProbeObservation, operation: AnyOperation, artifactPath: string): ProjectedObservation;
|
|
31
34
|
/**
|
|
32
35
|
* AD-11's fixture digest. Sorted by leg id first, because NFR9 forbids any
|
|
33
36
|
* stage from reading array position: two runs whose observations arrived in a
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* scoring version: two runs whose projections agree describe the same fixture.
|
|
5
5
|
*/
|
|
6
6
|
import { digestComposite } from '../canonical/digest.js';
|
|
7
|
+
import { descriptorArtifactOf, descriptorChannelOf, } from '../declared-inputs.js';
|
|
7
8
|
import { DESCRIPTOR_POINTER_PATTERN } from '../schemas/pointer.js';
|
|
8
9
|
import { decodeTail } from '../seal/plan-index.js';
|
|
9
10
|
export const PREFLIGHT_ARTIFACT_PATH = 'PreflightVerdict';
|
|
@@ -70,14 +71,33 @@ export function pruneVolatile(body, volatilePointers, artifactPath) {
|
|
|
70
71
|
}
|
|
71
72
|
/** One observation reduced to the projection, with its volatile pointers gone. */
|
|
72
73
|
export function projectObservation(observation, operation, artifactPath) {
|
|
74
|
+
// The channel the operation's descriptor describes is the one AD-10's
|
|
75
|
+
// relation reads, so it is the one the volatile pointers are pruned from.
|
|
76
|
+
// Off an interface that speaks HTTP that is the response body; off a
|
|
77
|
+
// command it is the stream or the file the operation nominates.
|
|
78
|
+
const observed = observation.kind === 'api'
|
|
79
|
+
? observation.body
|
|
80
|
+
: describedChannelOf(observation, operation);
|
|
73
81
|
return {
|
|
74
82
|
legId: observation.probeId,
|
|
75
83
|
interfaceId: observation.interfaceId,
|
|
76
84
|
operationId: observation.operationId,
|
|
77
|
-
status
|
|
78
|
-
|
|
85
|
+
// A command has no transport status. `null` is what a reader of this
|
|
86
|
+
// field asks about, and every such reader already handles it.
|
|
87
|
+
status: observation.kind === 'api' ? observation.status : null,
|
|
88
|
+
exitCode: observation.kind === 'api' ? null : observation.exitCode,
|
|
89
|
+
body: pruneVolatile(observed, operation.volatilePointers, artifactPath),
|
|
79
90
|
};
|
|
80
91
|
}
|
|
92
|
+
/** The observed value of whichever channel this operation's descriptor describes. */
|
|
93
|
+
function describedChannelOf(observation, operation) {
|
|
94
|
+
const artifactId = descriptorArtifactOf(operation);
|
|
95
|
+
if (artifactId !== null)
|
|
96
|
+
return observation.artifacts[artifactId] ?? { kind: 'absent' };
|
|
97
|
+
return descriptorChannelOf(operation) === 'stderr'
|
|
98
|
+
? observation.stderr
|
|
99
|
+
: observation.stdout;
|
|
100
|
+
}
|
|
81
101
|
/**
|
|
82
102
|
* AD-11's fixture digest. Sorted by leg id first, because NFR9 forbids any
|
|
83
103
|
* stage from reading array position: two runs whose observations arrived in a
|
|
@@ -16,10 +16,39 @@ import { evidenceOf, resolveWitnessRelation } from './witness-evidence.js';
|
|
|
16
16
|
/**
|
|
17
17
|
* AD-10 names no threshold, and this is the one the repository already speaks:
|
|
18
18
|
* the published conformance suite ships `probe/observe-anomalous-status`, and
|
|
19
|
-
* `
|
|
20
|
-
* already assumed at that boundary.
|
|
19
|
+
* an api observation's `status` is bounded to 100-599 at the port.
|
|
21
20
|
*/
|
|
22
21
|
const ANOMALOUS_STATUS = 400;
|
|
22
|
+
/**
|
|
23
|
+
* What makes a control leg anomalous, in the vocabulary of the kind it ran
|
|
24
|
+
* against, or `null` when nothing does. A command's analogue of a 4xx is a
|
|
25
|
+
* non-zero exit: both are the system saying the call did not go through, and
|
|
26
|
+
* AD-10's clean-control check is about exactly that.
|
|
27
|
+
*/
|
|
28
|
+
function anomalyOf(observation) {
|
|
29
|
+
if (observation.kind === 'api') {
|
|
30
|
+
return observation.status >= ANOMALOUS_STATUS
|
|
31
|
+
? `status ${observation.status}`
|
|
32
|
+
: null;
|
|
33
|
+
}
|
|
34
|
+
return observation.exitCode === 0 ? null : `exit code ${observation.exitCode}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Whether the observation answers the mechanism the leg asked about.
|
|
38
|
+
*
|
|
39
|
+
* `kind` alone, and deliberately not `interfaceId` or `operationId`: those two
|
|
40
|
+
* are already read by the `interface-present` check, which reports a mismatch
|
|
41
|
+
* as a failed verdict rather than a fault, and reclassifying them here would
|
|
42
|
+
* turn a shipped verdict into a thrown fault. `kind` has no such reader. An
|
|
43
|
+
* observation of the wrong mechanism is not a weaker answer to the question, it
|
|
44
|
+
* is an answer to a different one, and every check below would read it as the
|
|
45
|
+
* leg's own result.
|
|
46
|
+
*/
|
|
47
|
+
function kindMismatch(leg, observation) {
|
|
48
|
+
if (leg.request.kind === observation.kind)
|
|
49
|
+
return undefined;
|
|
50
|
+
return `leg "${leg.legId}" asked for a "${leg.request.kind}" probe and was answered with a "${observation.kind}" observation, so the port answered a question nobody asked`;
|
|
51
|
+
}
|
|
23
52
|
const check = (kind, operationId, outcome, note) => ({ kind, operationId, outcome, note });
|
|
24
53
|
/**
|
|
25
54
|
* Two projections describe the same fixture state. `legId` is excluded because
|
|
@@ -48,7 +77,7 @@ const resolveAgainst = (witness, state, plan, artifactPath) => {
|
|
|
48
77
|
// Keyed by the witness's own leg id, since the relation addresses
|
|
49
78
|
// `/interactions/{witness.legId}/…`. The scoped row asks whether that same
|
|
50
79
|
// relation would fire on a clean leg's observation.
|
|
51
|
-
return resolveWitnessRelation(witness.relation, { [witness.legId]: state.evidence }, state.leg.operation, plan.referenceSets, artifactPath).resolution;
|
|
80
|
+
return resolveWitnessRelation(witness.relation, { [witness.legId]: state.evidence }, state.leg.operation, plan.referenceSets, plan.referenceSetKeys, artifactPath).resolution;
|
|
52
81
|
};
|
|
53
82
|
export const reducePreflight = (plan, { observations }) => {
|
|
54
83
|
const byProbeId = new Map();
|
|
@@ -68,12 +97,22 @@ export const reducePreflight = (plan, { observations }) => {
|
|
|
68
97
|
const observation = byProbeId.get(leg.legId);
|
|
69
98
|
if (observation === undefined)
|
|
70
99
|
continue;
|
|
100
|
+
// The echo is checked, not assumed. Both port messages are unions, so a
|
|
101
|
+
// port can answer a command leg with a schema-valid HTTP observation and
|
|
102
|
+
// every check below reads it as the leg's own result: a command contract
|
|
103
|
+
// then passes pre-flight with four checks satisfied and no command ever
|
|
104
|
+
// run. `probeId` alone binds the two together and says nothing about
|
|
105
|
+
// whether the answer is to this question.
|
|
106
|
+
const mismatch = kindMismatch(leg, observation);
|
|
107
|
+
if (mismatch !== undefined) {
|
|
108
|
+
throw new RuntimeFault('port-contract-violation', PREFLIGHT_ARTIFACT_PATH, mismatch);
|
|
109
|
+
}
|
|
71
110
|
const projected = projectObservation(observation, leg.operation, PREFLIGHT_ARTIFACT_PATH);
|
|
72
111
|
states.set(leg.legId, {
|
|
73
112
|
leg,
|
|
74
113
|
observation,
|
|
75
114
|
projected,
|
|
76
|
-
evidence: evidenceOf(projected, observation, leg.inputs),
|
|
115
|
+
evidence: evidenceOf(projected, observation, leg.inputs, leg.operation),
|
|
77
116
|
});
|
|
78
117
|
}
|
|
79
118
|
const reduceCheck = (planned) => {
|
|
@@ -105,7 +144,7 @@ export const reducePreflight = (plan, { observations }) => {
|
|
|
105
144
|
return check(planned.kind, planned.operationId, 'failed', `witness leg "${leg.legId}" produced no observation`);
|
|
106
145
|
evidence[leg.legId] = state.evidence;
|
|
107
146
|
}
|
|
108
|
-
const { resolution } = resolveWitnessRelation(witness.relation, evidence, operation, plan.referenceSets, PREFLIGHT_ARTIFACT_PATH);
|
|
147
|
+
const { resolution } = resolveWitnessRelation(witness.relation, evidence, operation, plan.referenceSets, plan.referenceSetKeys, PREFLIGHT_ARTIFACT_PATH);
|
|
109
148
|
// AD-10's own sentence, and the most load-bearing line here: a
|
|
110
149
|
// sensitivity check that examined nothing has established nothing,
|
|
111
150
|
// so `insufficient-evidence` fails.
|
|
@@ -128,8 +167,9 @@ export const reducePreflight = (plan, { observations }) => {
|
|
|
128
167
|
const state = states.get(legId);
|
|
129
168
|
if (state === undefined)
|
|
130
169
|
return check(planned.kind, null, 'failed', `control leg "${legId}" produced no observation`);
|
|
131
|
-
|
|
132
|
-
|
|
170
|
+
const anomaly = anomalyOf(state.observation);
|
|
171
|
+
if (anomaly !== null)
|
|
172
|
+
return check(planned.kind, null, 'failed', `control leg "${legId}" observed ${anomaly}`);
|
|
133
173
|
}
|
|
134
174
|
return check(planned.kind, null, 'satisfied', null);
|
|
135
175
|
}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* unchanged. This module supplies the `Observation` shape they read and a
|
|
5
5
|
* collection predicate scoped to one operation.
|
|
6
6
|
*/
|
|
7
|
-
import { type PointerDenotesCollection } from '../evaluate/resolution.ts';
|
|
7
|
+
import { type PointerDenotesCollection, type ReferenceSetKeys } from '../evaluate/resolution.ts';
|
|
8
8
|
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
9
9
|
import type { CheckResolutionValue } from '../schemas/evidence-artifact.ts';
|
|
10
10
|
import type { Expression } from '../schemas/expression.ts';
|
|
11
|
-
import type {
|
|
11
|
+
import type { AnyOperation } from '../schemas/interface.ts';
|
|
12
12
|
import type { ProbeObservation } from '../schemas/port-messages.ts';
|
|
13
13
|
import type { JsonValue } from '../schemas/primitives.ts';
|
|
14
14
|
import type { Observation } from '../schemas/sealed-run-record.ts';
|
|
@@ -27,7 +27,7 @@ export declare const PREFLIGHT_REGEX_MATCH_STEP_BUDGET = 1000000;
|
|
|
27
27
|
* the projection does not carry. `provenance` is `baseline`: a pre-flight leg is
|
|
28
28
|
* pre-canned by definition.
|
|
29
29
|
*/
|
|
30
|
-
export declare function evidenceOf(projected: ProjectedObservation, observation: ProbeObservation, inputs: WitnessInputs): Observation;
|
|
30
|
+
export declare function evidenceOf(projected: ProjectedObservation, observation: ProbeObservation, inputs: WitnessInputs, operation: AnyOperation): Observation;
|
|
31
31
|
/** the contract's declared reference sets in the shape the resolver wants. */
|
|
32
32
|
export declare function referenceSetMembers(contract: EvalContract): Readonly<Record<string, JsonValue[]>>;
|
|
33
33
|
/**
|
|
@@ -37,6 +37,6 @@ export declare function referenceSetMembers(contract: EvalContract): Readonly<Re
|
|
|
37
37
|
* never appears, and fabricating step objects for a one-operation lookup is more
|
|
38
38
|
* machinery than the predicate.
|
|
39
39
|
*/
|
|
40
|
-
export declare function makeWitnessPointerDenotesCollection(operation:
|
|
40
|
+
export declare function makeWitnessPointerDenotesCollection(operation: AnyOperation): PointerDenotesCollection;
|
|
41
41
|
/** Resolves one witness relation over the legs it addresses. */
|
|
42
|
-
export declare function resolveWitnessRelation(relation: Expression, legEvidence: Readonly<Record<string, Observation>>, operation:
|
|
42
|
+
export declare function resolveWitnessRelation(relation: Expression, legEvidence: Readonly<Record<string, Observation>>, operation: AnyOperation, referenceSets: Readonly<Record<string, JsonValue[]>>, referenceSetKeys: ReferenceSetKeys, artifactPath: string): CheckResolutionValue;
|