eval-quality 1.4.2 → 3.0.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 +6 -6
- package/corpus/dev/README.md +24 -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/captured-read-back.json +1 -0
- package/corpus/dev/contracts/checklist-selection.json +1 -0
- 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 -1
- 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/notes-tool-server.json +1 -0
- package/corpus/dev/contracts/per-key-split-oracles.json +1 -1
- package/corpus/dev/contracts/review-corpus.json +1 -1
- 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.js +44 -6
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/mcp-adapter.d.ts +32 -0
- package/dist/adapters/mcp-adapter.js +357 -0
- package/dist/adapters/mcp-target-policy.d.ts +39 -0
- package/dist/adapters/mcp-target-policy.js +30 -0
- package/dist/cli/render.d.ts +8 -3
- package/dist/cli/render.js +13 -6
- package/dist/cli/run.js +2 -1
- package/dist/core/compile/bindings.d.ts +8 -18
- package/dist/core/compile/bindings.js +13 -10
- package/dist/core/compile/compile.js +6 -1
- package/dist/core/compile/interface-inventory.d.ts +81 -3
- package/dist/core/compile/interface-inventory.js +134 -23
- package/dist/core/compile/reachability.d.ts +73 -1
- package/dist/core/compile/reachability.js +134 -19
- package/dist/core/compile/schema-version.d.ts +15 -2
- package/dist/core/compile/schema-version.js +11 -3
- package/dist/core/compile/sensitivity-witness.d.ts +22 -10
- package/dist/core/compile/sensitivity-witness.js +101 -13
- package/dist/core/coverage/operations.d.ts +1 -1
- package/dist/core/coverage/operations.js +1 -1
- package/dist/core/coverage/relevance.d.ts +3 -3
- package/dist/core/coverage/relevance.js +3 -3
- package/dist/core/declared-inputs.d.ts +21 -9
- package/dist/core/declared-inputs.js +51 -16
- package/dist/core/evaluate/evidence-resolution.d.ts +8 -7
- package/dist/core/evaluate/evidence-resolution.js +25 -18
- package/dist/core/preflight/plan.js +43 -6
- package/dist/core/preflight/projection.d.ts +10 -1
- package/dist/core/preflight/projection.js +9 -5
- package/dist/core/preflight/reduce.js +6 -2
- package/dist/core/preflight/witness-evidence.js +31 -9
- package/dist/core/schemas/artifact.d.ts +145 -49
- package/dist/core/schemas/defect-signature.d.ts +280 -23
- package/dist/core/schemas/defect-signature.js +65 -37
- package/dist/core/schemas/eval-contract.d.ts +33 -48
- package/dist/core/schemas/eval-contract.js +3 -3
- package/dist/core/schemas/interface.d.ts +193 -55
- package/dist/core/schemas/interface.js +82 -15
- package/dist/core/schemas/plan.d.ts +45 -1
- package/dist/core/schemas/plan.js +13 -2
- package/dist/core/schemas/pointer.d.ts +23 -9
- package/dist/core/schemas/pointer.js +25 -11
- package/dist/core/schemas/port-messages.d.ts +81 -0
- package/dist/core/schemas/port-messages.js +50 -3
- package/dist/core/schemas/primitives.d.ts +18 -0
- package/dist/core/schemas/primitives.js +29 -0
- package/dist/core/schemas/probe-policy.d.ts +41 -0
- package/dist/core/schemas/probe-policy.js +61 -1
- package/dist/core/schemas/probe.d.ts +156 -2
- package/dist/core/schemas/probe.js +45 -2
- package/dist/core/schemas/sealed-run-record.d.ts +11 -5
- package/dist/core/schemas/sealed-run-record.js +21 -9
- package/dist/core/schemas/sensitivity-witness.d.ts +31 -7
- package/dist/core/schemas/sensitivity-witness.js +32 -9
- package/dist/core/score/bindings.d.ts +1 -1
- package/dist/core/score/bindings.js +4 -4
- package/dist/core/score/qualification.d.ts +7 -5
- package/dist/core/score/qualification.js +92 -23
- package/dist/core/score/score.d.ts +1 -1
- package/dist/core/score/score.js +24 -1
- package/dist/core/seal/derived-reference.js +20 -17
- package/dist/core/seal/plan-index.d.ts +18 -9
- package/dist/core/seal/plan-index.js +79 -37
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/ports/environment-probe-port.d.ts +50 -17
- package/dist/ports/environment-probe-port.js +26 -17
- package/dist/testing/conformance.d.ts +3 -2
- package/dist/testing/conformance.js +2 -1
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +1 -1
- package/dist/testing/probe-conformance.d.ts +90 -13
- package/dist/testing/probe-conformance.js +375 -160
- package/package.json +4 -2
- package/schemas/eval-contract.schema.json +571 -18
- package/schemas/probe.schema.json +152 -12
- package/schemas/rubric.schema.json +1 -1
- package/schemas/sealed-run-record.schema.json +24 -17
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** resolves a pointer to its step and operation; nothing about reachability. */
|
|
2
|
-
import type { AnyOperation, CommandOperation, InterfaceKindName, Operation, PermittedInterface } from '../schemas/interface.ts';
|
|
2
|
+
import type { AnyOperation, CommandOperation, InterfaceKindName, McpOperation, Operation, PermittedInterface } from '../schemas/interface.ts';
|
|
3
3
|
import type { InteractionStep } from '../schemas/plan.ts';
|
|
4
4
|
import { type EvidenceChannelName, type InputChannelName } from '../schemas/pointer.ts';
|
|
5
5
|
/**
|
|
@@ -17,13 +17,13 @@ export declare const decodeTail: (tailSource: string) => readonly string[];
|
|
|
17
17
|
export type EvidenceTarget = {
|
|
18
18
|
stepId: string;
|
|
19
19
|
channel: EvidenceChannelName;
|
|
20
|
-
|
|
20
|
+
inputChannel: InputChannelName | null;
|
|
21
21
|
artifactId: string | null;
|
|
22
22
|
tail: readonly string[];
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
25
|
* Parses one `InteractionPointer` string (`INTERACTION_POINTER_PATTERN` in
|
|
26
|
-
* `pointer.ts`) into its step id, channel,
|
|
26
|
+
* `pointer.ts`) into its step id, channel, input channel, and tail, using
|
|
27
27
|
* the schema's own channel partition so this accepts exactly what
|
|
28
28
|
* `InteractionPointer.safeParse` accepts. A should-never-happen precondition
|
|
29
29
|
* violation throws `TypeError`, per `digest.ts`'s precedent.
|
|
@@ -38,14 +38,15 @@ export declare function parseEvidenceTarget(pointer: string): EvidenceTarget;
|
|
|
38
38
|
*
|
|
39
39
|
* `operationOf` stays narrow on purpose. It hands a resolved `Operation` to
|
|
40
40
|
* every downstream consumer, so widening its return type to the operation
|
|
41
|
-
* union would retype seventeen files at once. A command operation
|
|
42
|
-
* `undefined` from it and to a value from
|
|
43
|
-
* caller that has to branch reads the declaring kind first.
|
|
41
|
+
* union would retype seventeen files at once. A command operation and a tool
|
|
42
|
+
* call each resolve to `undefined` from it and to a value from their own
|
|
43
|
+
* accessor, and each caller that has to branch reads the declaring kind first.
|
|
44
44
|
*/
|
|
45
45
|
export type PlanIndex = {
|
|
46
46
|
stepOf: (stepId: string) => InteractionStep | undefined;
|
|
47
47
|
operationOf: (operationId: string) => Operation | undefined;
|
|
48
48
|
commandOperationOf: (operationId: string) => CommandOperation | undefined;
|
|
49
|
+
mcpOperationOf: (operationId: string) => McpOperation | undefined;
|
|
49
50
|
interfaceKindOf: (operationId: string) => InterfaceKindName | undefined;
|
|
50
51
|
stepsUsing: (operationId: string) => readonly InteractionStep[];
|
|
51
52
|
};
|
|
@@ -70,9 +71,17 @@ export declare function buildPlanIndex(interactionPlan: readonly InteractionStep
|
|
|
70
71
|
export declare function resolveStep(index: PlanIndex, stepId: string): InteractionStep;
|
|
71
72
|
/**
|
|
72
73
|
* The declared operation of whichever kind, for the callers that read only
|
|
73
|
-
* fields
|
|
74
|
+
* fields all three shapes carry. Callers reading a kind-specific field ask
|
|
74
75
|
* `interfaceKindOf` first and then take the matching accessor.
|
|
75
76
|
*/
|
|
76
77
|
export declare const anyOperationOf: (index: PlanIndex, operationId: string) => AnyOperation | undefined;
|
|
77
|
-
/**
|
|
78
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Resolves an operation id through the index or throws. See `resolveStep`.
|
|
80
|
+
*
|
|
81
|
+
* Reads all three maps. It read `operationOf` alone, so it threw for a command
|
|
82
|
+
* operation and then for a tool call with the message "the permitted interfaces
|
|
83
|
+
* do not declare it", which is false: they declare it, and a different accessor
|
|
84
|
+
* holds it. Callers narrow with the operation predicates in
|
|
85
|
+
* `core/declared-inputs.ts`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function resolveOperation(index: PlanIndex, operationId: string): AnyOperation;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { IDENTIFIER_ROOTED_CHANNEL, INPUT_CHANNELS, SCALAR_CHANNELS, TAIL_BEARING_CHANNELS, TRANSPORT_ROOTED_CHANNEL, } from '../schemas/pointer.js';
|
|
1
|
+
import { IDENTIFIER_ROOTED_CHANNEL, INPUT_CHANNELS, INPUT_ROOTED_CHANNEL, SCALAR_CHANNELS, TAIL_BEARING_CHANNELS, } from '../schemas/pointer.js';
|
|
3
2
|
import { IDENTIFIER_CHARSET_SOURCE } from '../schemas/primitives.js';
|
|
4
3
|
// An RFC 6901 reference token, respelled here because pointer.ts keeps its
|
|
5
4
|
// own TOKEN/TAIL fragments private. IDENTIFIER_CHARSET_SOURCE and the channel
|
|
@@ -15,7 +14,7 @@ const alternation = (members) => members.join('|');
|
|
|
15
14
|
// Named capture groups replace positional indices, avoiding a fragile
|
|
16
15
|
// dependency on `IDENTIFIER_CHARSET_SOURCE` staying free of its own capturing
|
|
17
16
|
// groups.
|
|
18
|
-
const EVIDENCE_TARGET_PATTERN = new RegExp(`^/interactions/(?<stepId>${IDENTIFIER_CHARSET_SOURCE})/(?:(?<tailBearingChannel>${alternation(TAIL_BEARING_CHANNELS)})(?<tailBearingTail>${TAIL_SOURCE})|(?<scalarChannel>${alternation(SCALAR_CHANNELS)})|${
|
|
17
|
+
const EVIDENCE_TARGET_PATTERN = new RegExp(`^/interactions/(?<stepId>${IDENTIFIER_CHARSET_SOURCE})/(?:(?<tailBearingChannel>${alternation(TAIL_BEARING_CHANNELS)})(?<tailBearingTail>${TAIL_SOURCE})|(?<scalarChannel>${alternation(SCALAR_CHANNELS)})|${INPUT_ROOTED_CHANNEL}/(?<inputChannel>${alternation(INPUT_CHANNELS)})(?<callInputsTail>${TAIL_SOURCE})|${IDENTIFIER_ROOTED_CHANNEL}/(?<artifactId>${IDENTIFIER_CHARSET_SOURCE})(?<artifactTail>${TAIL_SOURCE}))$`);
|
|
19
18
|
const isEvidenceChannel = (value) => TAIL_BEARING_CHANNELS.includes(value) ||
|
|
20
19
|
SCALAR_CHANNELS.includes(value);
|
|
21
20
|
const isInputChannel = (value) => INPUT_CHANNELS.includes(value);
|
|
@@ -28,7 +27,7 @@ export const decodeToken = (token) => token.replace(/~1/g, '/').replace(/~0/g, '
|
|
|
28
27
|
export const decodeTail = (tailSource) => tailSource === '' ? [] : tailSource.slice(1).split('/').map(decodeToken);
|
|
29
28
|
/**
|
|
30
29
|
* Parses one `InteractionPointer` string (`INTERACTION_POINTER_PATTERN` in
|
|
31
|
-
* `pointer.ts`) into its step id, channel,
|
|
30
|
+
* `pointer.ts`) into its step id, channel, input channel, and tail, using
|
|
32
31
|
* the schema's own channel partition so this accepts exactly what
|
|
33
32
|
* `InteractionPointer.safeParse` accepts. A should-never-happen precondition
|
|
34
33
|
* violation throws `TypeError`, per `digest.ts`'s precedent.
|
|
@@ -47,7 +46,7 @@ export function parseEvidenceTarget(pointer) {
|
|
|
47
46
|
return {
|
|
48
47
|
stepId,
|
|
49
48
|
channel: groups.scalarChannel,
|
|
50
|
-
|
|
49
|
+
inputChannel: null,
|
|
51
50
|
artifactId: null,
|
|
52
51
|
tail: [],
|
|
53
52
|
};
|
|
@@ -60,20 +59,20 @@ export function parseEvidenceTarget(pointer) {
|
|
|
60
59
|
return {
|
|
61
60
|
stepId,
|
|
62
61
|
channel: groups.tailBearingChannel,
|
|
63
|
-
|
|
62
|
+
inputChannel: null,
|
|
64
63
|
artifactId: null,
|
|
65
64
|
tail: decodeTail(groups.tailBearingTail ?? ''),
|
|
66
65
|
};
|
|
67
66
|
}
|
|
68
|
-
if (groups.
|
|
69
|
-
if (!isInputChannel(groups.
|
|
67
|
+
if (groups.inputChannel !== undefined) {
|
|
68
|
+
if (!isInputChannel(groups.inputChannel)) {
|
|
70
69
|
// Unreachable: INPUT_CHANNELS is exactly what this group can match.
|
|
71
|
-
throw new TypeError(`call-inputs evidence target names no
|
|
70
|
+
throw new TypeError(`call-inputs evidence target names no input channel: ${pointer}`);
|
|
72
71
|
}
|
|
73
72
|
return {
|
|
74
73
|
stepId,
|
|
75
74
|
channel: 'call-inputs',
|
|
76
|
-
|
|
75
|
+
inputChannel: groups.inputChannel,
|
|
77
76
|
artifactId: null,
|
|
78
77
|
tail: decodeTail(groups.callInputsTail ?? ''),
|
|
79
78
|
};
|
|
@@ -82,7 +81,7 @@ export function parseEvidenceTarget(pointer) {
|
|
|
82
81
|
return {
|
|
83
82
|
stepId,
|
|
84
83
|
channel: IDENTIFIER_ROOTED_CHANNEL,
|
|
85
|
-
|
|
84
|
+
inputChannel: null,
|
|
86
85
|
artifactId: groups.artifactId,
|
|
87
86
|
tail: decodeTail(groups.artifactTail ?? ''),
|
|
88
87
|
};
|
|
@@ -123,40 +122,73 @@ export function buildPlanIndex(interactionPlan, permittedInterfaces, options = {
|
|
|
123
122
|
}
|
|
124
123
|
const operations = new Map();
|
|
125
124
|
const commandOperations = new Map();
|
|
125
|
+
const mcpOperations = new Map();
|
|
126
126
|
const kinds = new Map();
|
|
127
127
|
const duplicateOperationIds = new Set();
|
|
128
|
+
/**
|
|
129
|
+
* Records one operation id against the kind that declared it and answers
|
|
130
|
+
* whether the caller may store the operation. An id two permitted
|
|
131
|
+
* interfaces both declare is removed from every map instead of being
|
|
132
|
+
* resolved by array order, so `operationOf` and its two siblings answer
|
|
133
|
+
* `undefined` for it. One closure serves all three arms: the bookkeeping is
|
|
134
|
+
* the same for every kind and only the destination map differs.
|
|
135
|
+
*/
|
|
136
|
+
const claim = (operationId, kind) => {
|
|
137
|
+
if (kinds.has(operationId) || duplicateOperationIds.has(operationId)) {
|
|
138
|
+
if (duplicateIds === 'throw') {
|
|
139
|
+
throw new TypeError(`duplicate operation id across permitted interfaces: ${operationId}`);
|
|
140
|
+
}
|
|
141
|
+
operations.delete(operationId);
|
|
142
|
+
commandOperations.delete(operationId);
|
|
143
|
+
mcpOperations.delete(operationId);
|
|
144
|
+
kinds.delete(operationId);
|
|
145
|
+
duplicateOperationIds.add(operationId);
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
kinds.set(operationId, kind);
|
|
149
|
+
return true;
|
|
150
|
+
};
|
|
128
151
|
for (const iface of permittedInterfaces) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
152
|
+
// Narrowed on the interface's own kind before its operations are read.
|
|
153
|
+
// Each branch of `PermittedInterface` declares its own `operations`
|
|
154
|
+
// element type, so an arm that narrowed first iterates
|
|
155
|
+
// `CommandOperation`, `McpOperation` or `Operation` and stores it with
|
|
156
|
+
// no cast. Widening through `operationsOf` first discards that
|
|
157
|
+
// correlation, and no later kind test recovers it. `web` shares the api
|
|
158
|
+
// map: it carries the api operation shape and every consumer of a
|
|
159
|
+
// resolved operation reads the same declared fields off both.
|
|
160
|
+
switch (iface.kind) {
|
|
161
|
+
case 'cli':
|
|
162
|
+
for (const operation of iface.operations) {
|
|
163
|
+
if (claim(operation.operationId, iface.kind))
|
|
164
|
+
commandOperations.set(operation.operationId, operation);
|
|
134
165
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
else {
|
|
141
|
-
kinds.set(operation.operationId, iface.kind);
|
|
142
|
-
// Sorted into the two maps by the interface's own kind rather
|
|
143
|
-
// than by probing the operation for a field: `web` and `mcp`
|
|
144
|
-
// carry the api operation shape and belong in the same map as
|
|
145
|
-
// `api`, since every consumer of a resolved operation reads
|
|
146
|
-
// the same declared fields off all three.
|
|
147
|
-
if (iface.kind === 'cli') {
|
|
148
|
-
commandOperations.set(operation.operationId, operation);
|
|
166
|
+
continue;
|
|
167
|
+
case 'mcp':
|
|
168
|
+
for (const operation of iface.operations) {
|
|
169
|
+
if (claim(operation.operationId, iface.kind))
|
|
170
|
+
mcpOperations.set(operation.operationId, operation);
|
|
149
171
|
}
|
|
150
|
-
|
|
151
|
-
|
|
172
|
+
continue;
|
|
173
|
+
case 'api':
|
|
174
|
+
case 'web':
|
|
175
|
+
for (const operation of iface.operations) {
|
|
176
|
+
if (claim(operation.operationId, iface.kind))
|
|
177
|
+
operations.set(operation.operationId, operation);
|
|
152
178
|
}
|
|
153
|
-
|
|
179
|
+
continue;
|
|
154
180
|
}
|
|
181
|
+
// Reachable only once a fifth kind joins the union, and then `iface` is
|
|
182
|
+
// no longer `never` and this line fails the typecheck. That is the
|
|
183
|
+
// forcing function the three hand-narrowed casts did not have: a kind
|
|
184
|
+
// with no arm above was sorted into the api map by exhaustion.
|
|
185
|
+
iface;
|
|
155
186
|
}
|
|
156
187
|
return {
|
|
157
188
|
stepOf: (stepId) => steps.get(stepId),
|
|
158
189
|
operationOf: (operationId) => operations.get(operationId),
|
|
159
190
|
commandOperationOf: (operationId) => commandOperations.get(operationId),
|
|
191
|
+
mcpOperationOf: (operationId) => mcpOperations.get(operationId),
|
|
160
192
|
interfaceKindOf: (operationId) => kinds.get(operationId),
|
|
161
193
|
stepsUsing: (operationId) => stepsByOperation.get(operationId) ?? [],
|
|
162
194
|
};
|
|
@@ -177,13 +209,23 @@ export function resolveStep(index, stepId) {
|
|
|
177
209
|
}
|
|
178
210
|
/**
|
|
179
211
|
* The declared operation of whichever kind, for the callers that read only
|
|
180
|
-
* fields
|
|
212
|
+
* fields all three shapes carry. Callers reading a kind-specific field ask
|
|
181
213
|
* `interfaceKindOf` first and then take the matching accessor.
|
|
182
214
|
*/
|
|
183
|
-
export const anyOperationOf = (index, operationId) => index.operationOf(operationId) ??
|
|
184
|
-
|
|
215
|
+
export const anyOperationOf = (index, operationId) => index.operationOf(operationId) ??
|
|
216
|
+
index.commandOperationOf(operationId) ??
|
|
217
|
+
index.mcpOperationOf(operationId);
|
|
218
|
+
/**
|
|
219
|
+
* Resolves an operation id through the index or throws. See `resolveStep`.
|
|
220
|
+
*
|
|
221
|
+
* Reads all three maps. It read `operationOf` alone, so it threw for a command
|
|
222
|
+
* operation and then for a tool call with the message "the permitted interfaces
|
|
223
|
+
* do not declare it", which is false: they declare it, and a different accessor
|
|
224
|
+
* holds it. Callers narrow with the operation predicates in
|
|
225
|
+
* `core/declared-inputs.ts`.
|
|
226
|
+
*/
|
|
185
227
|
export function resolveOperation(index, operationId) {
|
|
186
|
-
const operation = index
|
|
228
|
+
const operation = anyOperationOf(index, operationId);
|
|
187
229
|
if (operation === undefined) {
|
|
188
230
|
throw new TypeError(`step names an operation the permitted interfaces do not declare: ${operationId}`);
|
|
189
231
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ export type { ScoringPolicy } from './core/schemas/scoring-policy.ts';
|
|
|
12
12
|
export type { SealedEvaluatorBrief } from './core/schemas/sealed-evaluator-brief.ts';
|
|
13
13
|
export type { SealedRunRecord } from './core/schemas/sealed-run-record.ts';
|
|
14
14
|
export type { FixtureReset, ManifestationWitness, SensitivityWitness, SensitivityWitnessLeg, WitnessChannel, WitnessInputs, } from './core/schemas/sensitivity-witness.ts';
|
|
15
|
-
export declare const VERSION = "
|
|
15
|
+
export declare const VERSION = "3.0.0";
|
package/dist/index.js
CHANGED
|
@@ -4,25 +4,34 @@
|
|
|
4
4
|
* identifier to an authorized target is the adapter's job, from configuration
|
|
5
5
|
* outside the contract.
|
|
6
6
|
*
|
|
7
|
-
* Four rules an implementation MUST follow
|
|
8
|
-
* no logic; `src/testing/probe-conformance.ts`
|
|
7
|
+
* Four rules an implementation MUST follow, whichever mechanism it speaks.
|
|
8
|
+
* Prose here because `ports/` holds no logic; `src/testing/probe-conformance.ts`
|
|
9
|
+
* is the executable half.
|
|
9
10
|
*
|
|
10
|
-
* 1. Apply the policy before
|
|
11
|
-
* target.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
11
|
+
* 1. Apply the policy before anything reaches the system under test, and again
|
|
12
|
+
* to every target the first one leads to. On HTTP that second clause is
|
|
13
|
+
* every redirect; on a mechanism that starts a process it is every process
|
|
14
|
+
* the authorization causes to run.
|
|
15
|
+
* 2. Act on exactly what the policy validated, and revalidate nothing away.
|
|
16
|
+
* Over HTTP: issue the request against the validated address
|
|
17
|
+
* (`canonicalAddress`), keep the original host in the `Host` header, verify
|
|
18
|
+
* TLS against that host, and never re-resolve a hostname after validation,
|
|
19
|
+
* since re-resolving between the check and the connection is the classic
|
|
20
|
+
* way past an allowlist like this one; where a host resolves to several
|
|
21
|
+
* addresses, validate each and connect only to a validated one. Over a
|
|
22
|
+
* mechanism that starts a process: spawn the authorized target with an argv
|
|
23
|
+
* array and never through a shell, so no declared value can become a
|
|
24
|
+
* metacharacter, and pass only the environment the mapping declares.
|
|
18
25
|
* 3. A policy denial throws `forbidden-target`; a cap throws
|
|
19
|
-
* `budget-exhausted`; an abort throws `aborted`; a
|
|
20
|
-
* `port-failure`.
|
|
21
|
-
* 4. Every
|
|
22
|
-
* or 5xx
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* `budget-exhausted`; an abort throws `aborted`; a failure to reach the
|
|
27
|
+
* system at all throws `port-failure`.
|
|
28
|
+
* 4. Every answer the system returns is an observation, whatever it says. A
|
|
29
|
+
* 4xx or 5xx, a non-zero exit, and a tool result flagged as an error all
|
|
30
|
+
* resolve to a schema-valid `ProbeObservation`, since AD-10's "every
|
|
31
|
+
* declared seeded fault being observed to fire" reads the answer as
|
|
32
|
+
* payload. Throw on one of those and a seeded fault goes invisible, which
|
|
33
|
+
* makes the whole pre-flight vacuous. What throws under rule 3 is the case
|
|
34
|
+
* where nothing answered.
|
|
26
35
|
*/
|
|
27
36
|
import { ProbeObservation, ProbeRequest } from '../core/schemas/port-messages.ts';
|
|
28
37
|
import type { PortMethod } from './port.ts';
|
|
@@ -78,6 +87,15 @@ export declare const probeParsers: {
|
|
|
78
87
|
kind: import("zod").ZodLiteral<"absent">;
|
|
79
88
|
}, import("zod/v4/core").$strict>], "kind">;
|
|
80
89
|
}, import("zod/v4/core").$strict>;
|
|
90
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
91
|
+
probeId: import("zod").ZodString;
|
|
92
|
+
interfaceId: import("zod").ZodString;
|
|
93
|
+
operationId: import("zod").ZodString;
|
|
94
|
+
kind: import("zod").ZodLiteral<"mcp">;
|
|
95
|
+
toolName: import("zod").ZodString;
|
|
96
|
+
channels: import("zod").ZodObject<{
|
|
97
|
+
arguments: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodType<import("../core/schemas/primitives.ts").JsonValue, unknown, import("zod/v4/core").$ZodTypeInternals<import("../core/schemas/primitives.ts").JsonValue, unknown>>>;
|
|
98
|
+
}, import("zod/v4/core").$strict>;
|
|
81
99
|
}, import("zod/v4/core").$strict>], "kind">;
|
|
82
100
|
readonly response: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
83
101
|
probeId: import("zod").ZodString;
|
|
@@ -128,5 +146,20 @@ export declare const probeParsers: {
|
|
|
128
146
|
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
129
147
|
kind: import("zod").ZodLiteral<"absent">;
|
|
130
148
|
}, import("zod/v4/core").$strict>], "kind">>;
|
|
149
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
150
|
+
probeId: import("zod").ZodString;
|
|
151
|
+
interfaceId: import("zod").ZodString;
|
|
152
|
+
operationId: import("zod").ZodString;
|
|
153
|
+
kind: import("zod").ZodLiteral<"mcp">;
|
|
154
|
+
isError: import("zod").ZodBoolean;
|
|
155
|
+
result: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
156
|
+
kind: import("zod").ZodLiteral<"json">;
|
|
157
|
+
value: import("zod").ZodType<import("../core/schemas/primitives.ts").JsonValue, unknown, import("zod/v4/core").$ZodTypeInternals<import("../core/schemas/primitives.ts").JsonValue, unknown>>;
|
|
158
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
159
|
+
kind: import("zod").ZodLiteral<"text">;
|
|
160
|
+
value: import("zod").ZodString;
|
|
161
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
162
|
+
kind: import("zod").ZodLiteral<"absent">;
|
|
163
|
+
}, import("zod/v4/core").$strict>], "kind">;
|
|
131
164
|
}, import("zod/v4/core").$strict>], "kind">;
|
|
132
165
|
};
|
|
@@ -4,25 +4,34 @@
|
|
|
4
4
|
* identifier to an authorized target is the adapter's job, from configuration
|
|
5
5
|
* outside the contract.
|
|
6
6
|
*
|
|
7
|
-
* Four rules an implementation MUST follow
|
|
8
|
-
* no logic; `src/testing/probe-conformance.ts`
|
|
7
|
+
* Four rules an implementation MUST follow, whichever mechanism it speaks.
|
|
8
|
+
* Prose here because `ports/` holds no logic; `src/testing/probe-conformance.ts`
|
|
9
|
+
* is the executable half.
|
|
9
10
|
*
|
|
10
|
-
* 1. Apply the policy before
|
|
11
|
-
* target.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
11
|
+
* 1. Apply the policy before anything reaches the system under test, and again
|
|
12
|
+
* to every target the first one leads to. On HTTP that second clause is
|
|
13
|
+
* every redirect; on a mechanism that starts a process it is every process
|
|
14
|
+
* the authorization causes to run.
|
|
15
|
+
* 2. Act on exactly what the policy validated, and revalidate nothing away.
|
|
16
|
+
* Over HTTP: issue the request against the validated address
|
|
17
|
+
* (`canonicalAddress`), keep the original host in the `Host` header, verify
|
|
18
|
+
* TLS against that host, and never re-resolve a hostname after validation,
|
|
19
|
+
* since re-resolving between the check and the connection is the classic
|
|
20
|
+
* way past an allowlist like this one; where a host resolves to several
|
|
21
|
+
* addresses, validate each and connect only to a validated one. Over a
|
|
22
|
+
* mechanism that starts a process: spawn the authorized target with an argv
|
|
23
|
+
* array and never through a shell, so no declared value can become a
|
|
24
|
+
* metacharacter, and pass only the environment the mapping declares.
|
|
18
25
|
* 3. A policy denial throws `forbidden-target`; a cap throws
|
|
19
|
-
* `budget-exhausted`; an abort throws `aborted`; a
|
|
20
|
-
* `port-failure`.
|
|
21
|
-
* 4. Every
|
|
22
|
-
* or 5xx
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* `budget-exhausted`; an abort throws `aborted`; a failure to reach the
|
|
27
|
+
* system at all throws `port-failure`.
|
|
28
|
+
* 4. Every answer the system returns is an observation, whatever it says. A
|
|
29
|
+
* 4xx or 5xx, a non-zero exit, and a tool result flagged as an error all
|
|
30
|
+
* resolve to a schema-valid `ProbeObservation`, since AD-10's "every
|
|
31
|
+
* declared seeded fault being observed to fire" reads the answer as
|
|
32
|
+
* payload. Throw on one of those and a seeded fault goes invisible, which
|
|
33
|
+
* makes the whole pre-flight vacuous. What throws under rule 3 is the case
|
|
34
|
+
* where nothing answered.
|
|
26
35
|
*/
|
|
27
36
|
import { ProbeObservation, ProbeRequest, } from '../core/schemas/port-messages.js';
|
|
28
37
|
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
@@ -7,14 +7,15 @@ export type ConformanceOutcome = {
|
|
|
7
7
|
readonly passed: boolean;
|
|
8
8
|
readonly detail: string;
|
|
9
9
|
};
|
|
10
|
-
export type ConformancePort = 'corpus' | 'clock' | 'file-system' | 'environment-probe' | 'command-probe';
|
|
10
|
+
export type ConformancePort = 'corpus' | 'clock' | 'file-system' | 'environment-probe' | 'command-probe' | 'mcp-probe';
|
|
11
11
|
/** how many outcomes a complete run of each port produces. Asserted as literals by fixture 58. */
|
|
12
12
|
export declare const CONFORMANCE_OUTCOME_COUNTS: {
|
|
13
13
|
readonly corpus: 6;
|
|
14
14
|
readonly clock: 6;
|
|
15
15
|
readonly 'file-system': 12;
|
|
16
16
|
readonly 'environment-probe': 19;
|
|
17
|
-
readonly 'command-probe':
|
|
17
|
+
readonly 'command-probe': 16;
|
|
18
|
+
readonly 'mcp-probe': 14;
|
|
18
19
|
};
|
|
19
20
|
export type ConformanceReport = {
|
|
20
21
|
readonly subject: string;
|
|
@@ -19,7 +19,8 @@ export const CONFORMANCE_OUTCOME_COUNTS = {
|
|
|
19
19
|
clock: 6,
|
|
20
20
|
'file-system': 12,
|
|
21
21
|
'environment-probe': 19,
|
|
22
|
-
'command-probe':
|
|
22
|
+
'command-probe': 16,
|
|
23
|
+
'mcp-probe': 14,
|
|
23
24
|
};
|
|
24
25
|
/** "Promptly" with no bound is unfalsifiable. One second clears any real adapter's abort latency and sits well inside a default test timeout. */
|
|
25
26
|
export const DEFAULT_ABORT_BUDGET_MS = 1000;
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
export type { RuntimeFaultCode } from '../core/schemas/faults.ts';
|
|
14
14
|
export { RUNTIME_FAULT_CODES, RuntimeFault } from '../core/schemas/faults.ts';
|
|
15
15
|
export type { ClockReadRequest, ClockReadResponse, CorpusResolveRequest, CorpusResolveResponse, FileReadRequest, FileReadResponse, FileWriteRequest, FileWriteResponse, ProbeObservation, ProbeObservedBody, ProbeRequest, ProbeRequestBody, } from '../core/schemas/port-messages.ts';
|
|
16
|
-
export type { CommandTargetAuthorization, CommandTargetPolicy, ProbeTargetAuthorization, ProbeTargetPolicy, } from '../core/schemas/probe-policy.ts';
|
|
16
|
+
export type { CommandTargetAuthorization, CommandTargetPolicy, McpTargetAuthorization, McpTargetPolicy, ProbeTargetAuthorization, ProbeTargetPolicy, } from '../core/schemas/probe-policy.ts';
|
|
17
17
|
export type { ClockPort } from '../ports/clock-port.ts';
|
|
18
18
|
export { clockReadParsers } from '../ports/clock-port.ts';
|
|
19
19
|
export type { CorpusPort } from '../ports/corpus-port.ts';
|
|
@@ -24,5 +24,5 @@ export type { FileSystemPort } from '../ports/file-system-port.ts';
|
|
|
24
24
|
export { fileReadParsers, fileWriteParsers, } from '../ports/file-system-port.ts';
|
|
25
25
|
export type { BuiltSubject, ConformanceOutcome, ConformancePort, ConformanceReport, PortSubject, ScenarioKind, } from './conformance.ts';
|
|
26
26
|
export { CONFORMANCE_OUTCOME_COUNTS, formatConformanceReport, runClockPortConformance, runCorpusPortConformance, runFileSystemPortConformance, } from './conformance.ts';
|
|
27
|
-
export type { CommandProbeSubject, ProbeSubject } from './probe-conformance.ts';
|
|
28
|
-
export { runCommandLineProbeConformance, runEnvironmentProbePortConformance, } from './probe-conformance.ts';
|
|
27
|
+
export type { CommandProbeSubject, McpProbeSubject, ProbeSubject, } from './probe-conformance.ts';
|
|
28
|
+
export { runCommandLineProbeConformance, runEnvironmentProbePortConformance, runMcpProbeConformance, } from './probe-conformance.ts';
|
package/dist/testing/index.js
CHANGED
|
@@ -16,4 +16,4 @@ export { corpusResolveParsers } from '../ports/corpus-port.js';
|
|
|
16
16
|
export { probeParsers } from '../ports/environment-probe-port.js';
|
|
17
17
|
export { fileReadParsers, fileWriteParsers, } from '../ports/file-system-port.js';
|
|
18
18
|
export { CONFORMANCE_OUTCOME_COUNTS, formatConformanceReport, runClockPortConformance, runCorpusPortConformance, runFileSystemPortConformance, } from './conformance.js';
|
|
19
|
-
export { runCommandLineProbeConformance, runEnvironmentProbePortConformance, } from './probe-conformance.js';
|
|
19
|
+
export { runCommandLineProbeConformance, runEnvironmentProbePortConformance, runMcpProbeConformance, } from './probe-conformance.js';
|
|
@@ -4,24 +4,44 @@
|
|
|
4
4
|
* since only it knows how its own interface-to-target mapping is wired.
|
|
5
5
|
*
|
|
6
6
|
* `runEnvironmentProbePortConformance` is the `api` arm: thirteen assertions,
|
|
7
|
-
* every scenario HTTP (
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* a non-zero exit read as an observation,
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* every scenario HTTP (an authorized target reached, an anomalous status read
|
|
8
|
+
* as an observation, an unmapped interface, four denied address classes, a
|
|
9
|
+
* method, a scheme, a redirect revalidated and refused, and three caps).
|
|
10
|
+
* `runCommandLineProbeConformance` is the `cli` arm: ten, over an authorized
|
|
11
|
+
* invocation, a non-zero exit read as an observation, an unmapped interface, an
|
|
12
|
+
* unmapped executable, an unauthorized subcommand path, an unpermitted
|
|
13
|
+
* environment key, a shell-metacharacter argument proven to reach the process
|
|
14
|
+
* as one literal token rather than a shell expansion, a declared artifact
|
|
15
|
+
* captured, and both caps.
|
|
16
|
+
* `runMcpProbeConformance` is the `mcp` arm: eight, over an authorized tool
|
|
17
|
+
* call, a tool-reported error read as an observation, an unmapped interface, an
|
|
18
|
+
* unauthorized tool, a declared argument proven to cross the JSON-RPC frame
|
|
19
|
+
* unchanged, the structured result the operation's descriptor describes, and
|
|
20
|
+
* both caps.
|
|
21
|
+
*
|
|
22
|
+
* Every field an authorization scopes owes a denial, which is the largest term
|
|
23
|
+
* in the three counts: an HTTP authorization scopes the interface, four
|
|
24
|
+
* address classes, the method and the scheme; a command authorization the
|
|
25
|
+
* interface, the executable, the subcommand path and the permitted environment
|
|
26
|
+
* keys; a tool-server authorization the interface and the tool. Each arm then adds the caps its
|
|
27
|
+
* mechanism can be made to exceed and the answers it has to read as
|
|
28
|
+
* observations.
|
|
29
|
+
*
|
|
30
|
+
* The arms are separate functions rather than one, because their subjects need
|
|
15
31
|
* disjoint fixtures (an HTTP redirect chain has no command analogue, and a
|
|
16
|
-
* subcommand allowlist has no
|
|
17
|
-
* mechanism is not asked to fake
|
|
32
|
+
* subcommand allowlist has no tool-call one) and a subject presenting for one
|
|
33
|
+
* mechanism is not asked to fake another's scenarios. What they do share is
|
|
34
|
+
* the machinery below `ArmAssertion`: one assertion shape generic over the
|
|
35
|
+
* subject type, one runner, one resolve-side checker and one call-count
|
|
36
|
+
* checker, so a fourth mechanism writes its subject and its list and nothing
|
|
37
|
+
* else.
|
|
18
38
|
*
|
|
19
|
-
* Each assertion in
|
|
39
|
+
* Each assertion in every arm builds its own `'resolves'` subject and reads
|
|
20
40
|
* `underlyingCalls()` from a counter starting at zero, so every count below is
|
|
21
41
|
* absolute.
|
|
22
42
|
*/
|
|
23
43
|
import type { ProbeRequest } from '../core/schemas/port-messages.ts';
|
|
24
|
-
import type { CommandTargetPolicy, ProbeTargetPolicy } from '../core/schemas/probe-policy.ts';
|
|
44
|
+
import type { CommandTargetPolicy, McpTargetPolicy, ProbeTargetPolicy } from '../core/schemas/probe-policy.ts';
|
|
25
45
|
import type { ConformanceReport, PortSubject } from './conformance.ts';
|
|
26
46
|
export type ProbeSubject = PortSubject<ProbeRequest> & {
|
|
27
47
|
readonly policy: ProbeTargetPolicy;
|
|
@@ -72,6 +92,8 @@ export type CommandProbeSubject = PortSubject<ProbeRequest> & {
|
|
|
72
92
|
readonly unmappedExecutableRequest: ProbeRequest;
|
|
73
93
|
/** an interface-executable pair the policy names, with a subcommandPath no authorization for it permits. */
|
|
74
94
|
readonly unauthorizedSubcommandRequest: ProbeRequest;
|
|
95
|
+
/** authorized in every other respect, declaring one environment key its authorization's permittedEnvironmentKeys omits. */
|
|
96
|
+
readonly unauthorizedEnvironmentKeyRequest: ProbeRequest;
|
|
75
97
|
/** authorized, and answered by the fixture exiting non-zero. */
|
|
76
98
|
readonly nonZeroExitRequest: ProbeRequest;
|
|
77
99
|
/** authorized, carrying a shell-metacharacter value on one argument channel key. */
|
|
@@ -88,9 +110,64 @@ export type CommandProbeSubject = PortSubject<ProbeRequest> & {
|
|
|
88
110
|
readonly overOutputRequest: ProbeRequest;
|
|
89
111
|
};
|
|
90
112
|
/**
|
|
91
|
-
*
|
|
113
|
+
* Sixteen outcomes: the six shared assertions plus the ten above. Unlike the
|
|
92
114
|
* `api` arm, every cap here has an assertion: a command subject's fixture
|
|
93
115
|
* script can be told to overrun a byte cap directly, with no oversize-request
|
|
94
116
|
* problem to work around.
|
|
95
117
|
*/
|
|
96
118
|
export declare function runCommandLineProbeConformance(subject: CommandProbeSubject): Promise<ConformanceReport>;
|
|
119
|
+
/**
|
|
120
|
+
* The `mcp` arm's subject, on the division the other two draw: the subject
|
|
121
|
+
* knows how its own mapping is wired and what its fixture server answers, the
|
|
122
|
+
* suite only knows what each request should produce.
|
|
123
|
+
*
|
|
124
|
+
* Two of its requests carry a value the suite has to compare against
|
|
125
|
+
* something, so the subject publishes that value beside the request. Both
|
|
126
|
+
* comparisons read a scalar the tool returns rather than a collection: a check
|
|
127
|
+
* over an empty collection resolves to insufficient evidence, so an assertion
|
|
128
|
+
* spelled that way would report vacuous and could never witness a dropped
|
|
129
|
+
* argument or a dropped result.
|
|
130
|
+
*/
|
|
131
|
+
export type McpProbeSubject = PortSubject<ProbeRequest> & {
|
|
132
|
+
readonly policy: McpTargetPolicy;
|
|
133
|
+
/** a tool call the policy ALLOWS, against the subject's own fixture server. */
|
|
134
|
+
readonly authorizedRequest: ProbeRequest;
|
|
135
|
+
/** an interfaceId no authorization names. */
|
|
136
|
+
readonly unmappedInterfaceRequest: ProbeRequest;
|
|
137
|
+
/** an interfaceId the policy names, asking for a toolName its authorization omits. */
|
|
138
|
+
readonly unauthorizedToolRequest: ProbeRequest;
|
|
139
|
+
/** authorized, and answered by a tool result carrying the envelope's error flag AND the content the tool reported the failure with, since the assertion checks both survived. */
|
|
140
|
+
readonly errorResultRequest: ProbeRequest;
|
|
141
|
+
/** authorized, carrying a metacharacter-bearing value on one argument key. */
|
|
142
|
+
readonly argumentEchoRequest: ProbeRequest;
|
|
143
|
+
/** the exact literal `argumentEchoRequest` carries, so the assertion can confirm the tool received it byte for byte. */
|
|
144
|
+
readonly argumentEchoValue: string;
|
|
145
|
+
/** the structured-result key the fixture tool publishes that received value under. */
|
|
146
|
+
readonly argumentEchoResultKey: string;
|
|
147
|
+
/** authorized, and answered with the structured result the operation's descriptor describes. */
|
|
148
|
+
readonly structuredResultRequest: ProbeRequest;
|
|
149
|
+
/** the keys that result carries, so a dropped or emptied result channel fails. */
|
|
150
|
+
readonly structuredResultKeys: readonly string[];
|
|
151
|
+
/** authorized against a maxElapsedMs the server is made to answer past. */
|
|
152
|
+
readonly overElapsedRequest: ProbeRequest;
|
|
153
|
+
/** authorized against a maxOutputBytes the server is made to write past. */
|
|
154
|
+
readonly overResultBytesRequest: ProbeRequest;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Fourteen outcomes: the six shared assertions plus the eight above. Fewer
|
|
158
|
+
* than either other arm because a tool-server authorization scopes two fields:
|
|
159
|
+
* one session is opened against one server and every tool it offers belongs to
|
|
160
|
+
* that server, so the interface identifier is the server identity and the tool
|
|
161
|
+
* allowlist is the only thing left to deny on.
|
|
162
|
+
*
|
|
163
|
+
* Two rules the reference adapter follows are outside what a green run
|
|
164
|
+
* certifies, and an author reading this should know which. A JSON-RPC error
|
|
165
|
+
* answering `tools/call` is an observation on the same terms a tool-reported
|
|
166
|
+
* error is, and the byte cap applies to the server's own stderr as well as its
|
|
167
|
+
* stdout. Neither has an assertion here, because the derivation above gives
|
|
168
|
+
* each arm one denial per authorization-scoped field and one assertion per cap
|
|
169
|
+
* the suite can make a subject exceed, and both of these are a second spelling
|
|
170
|
+
* of an assertion the arm already carries. The reference adapter's own tests
|
|
171
|
+
* cover both.
|
|
172
|
+
*/
|
|
173
|
+
export declare function runMcpProbeConformance(subject: McpProbeSubject): Promise<ConformanceReport>;
|