@ggui-ai/protocol-conformance 0.6.3 → 0.7.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 +54 -16
- package/dist/fixtures/consume-buffer/index.d.ts.map +1 -1
- package/dist/fixtures/consume-buffer/index.js +4 -1
- package/dist/fixtures/index.d.ts +42 -4
- package/dist/fixtures/index.d.ts.map +1 -1
- package/dist/fixtures/index.js +42 -4
- package/dist/fixtures/reserved-channel-authority/index.d.ts.map +1 -1
- package/dist/fixtures/reserved-channel-authority/index.js +4 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/match-behavior.d.ts.map +1 -1
- package/dist/match-behavior.js +4 -2
- package/dist/resource-read-conformance/cases/all-ephemeral-substrate-fuses-like-none.json +29 -0
- package/dist/resource-read-conformance/cases/evicted-row-remints-from-the-durable-record.json +26 -0
- package/dist/resource-read-conformance/cases/half-wired-blueprints-only-substrate-fuses-like-none.json +29 -0
- package/dist/resource-read-conformance/cases/half-wired-identity-only-substrate-fuses-like-none.json +29 -0
- package/dist/resource-read-conformance/cases/live-row-read-returns-mount-material.json +18 -0
- package/dist/resource-read-conformance/cases/malformed-locator-stays-outside-the-typed-set.json +19 -0
- package/dist/resource-read-conformance/cases/read-miss-answers-not-found.json +23 -0
- package/dist/resource-read-conformance/cases/read-on-a-substrate-less-server-answers-not-supported.json +22 -0
- package/dist/resource-read-conformance/cases/read-record-with-purged-blueprint-answers-blueprint-unresolvable.json +29 -0
- package/dist/resource-read-conformance/cases/read-refusal-is-indistinguishable-from-a-miss.json +47 -0
- package/dist/resource-read-conformance/cases/read-without-a-delivery-channel-answers-not-mountable.json +22 -0
- package/dist/resource-read-conformance/cases/registry-match-fuses-on-not-mountable.json +40 -0
- package/dist/resource-read-conformance/cases/substrate-less-fusion-of-refusal-and-miss.json +29 -0
- package/dist/resource-read-conformance/index.d.ts +371 -0
- package/dist/resource-read-conformance/index.d.ts.map +1 -0
- package/dist/resource-read-conformance/index.js +782 -0
- package/package.json +8 -3
package/dist/resource-read-conformance/cases/read-refusal-is-indistinguishable-from-a-miss.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "read-refusal-is-indistinguishable-from-a-miss",
|
|
3
|
+
"description": "The core disclosure obligation. A caller with no claim to a render reads a locator that fully resolves for its owner, and reads one that never existed. Both answers must be the same bytes. Anything that varies — a message naming the session, a detail explaining the refusal, a different code because the access check ran late — answers 'does this render exist?' for someone with no right to ask.",
|
|
4
|
+
"server": { "durableSubstrate": "all", "liveChannel": true },
|
|
5
|
+
"caller": "other",
|
|
6
|
+
"seeds": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "identity-record",
|
|
9
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
10
|
+
"key": "fedcba9876543210",
|
|
11
|
+
"blueprint": "named"
|
|
12
|
+
},
|
|
13
|
+
{ "kind": "durable-blueprint", "componentRef": "present", "body": "stored" }
|
|
14
|
+
],
|
|
15
|
+
"reads": [
|
|
16
|
+
{
|
|
17
|
+
"as": "refused",
|
|
18
|
+
"locator": {
|
|
19
|
+
"kind": "render",
|
|
20
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
21
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
22
|
+
},
|
|
23
|
+
"expect": {
|
|
24
|
+
"kind": "typed-error",
|
|
25
|
+
"jsonRpcCode": -32002,
|
|
26
|
+
"dataCode": "NOT_FOUND",
|
|
27
|
+
"detailAbsent": true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"as": "miss",
|
|
32
|
+
"locator": {
|
|
33
|
+
"kind": "render",
|
|
34
|
+
"session": "8d5b0e41-2c96-4a7f-b3d8-1e07f9a2c645",
|
|
35
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
36
|
+
},
|
|
37
|
+
"expect": {
|
|
38
|
+
"kind": "typed-error",
|
|
39
|
+
"jsonRpcCode": -32002,
|
|
40
|
+
"dataCode": "NOT_FOUND",
|
|
41
|
+
"detailAbsent": true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"indistinguishable": ["refused", "miss"],
|
|
46
|
+
"disclosesNothing": ["3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70"]
|
|
47
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "read-without-a-delivery-channel-answers-not-mountable",
|
|
3
|
+
"description": "The locator resolves and the caller owns it, but the server wires no way to deliver a component — neither a static component URL nor a live channel. The read answers NOT_MOUNTABLE on -32006 rather than handing back a shell with nothing to mount. This is the branch that proves the invariant is about the RESULT, not the lookup: the lookup succeeded.",
|
|
4
|
+
"server": { "durableSubstrate": "all" },
|
|
5
|
+
"caller": "owner",
|
|
6
|
+
"seeds": [{ "kind": "committed-render", "session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70" }],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "resolvable",
|
|
10
|
+
"locator": {
|
|
11
|
+
"kind": "render",
|
|
12
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
13
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
14
|
+
},
|
|
15
|
+
"expect": {
|
|
16
|
+
"kind": "typed-error",
|
|
17
|
+
"jsonRpcCode": -32006,
|
|
18
|
+
"dataCode": "NOT_MOUNTABLE"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "registry-match-fuses-on-not-mountable",
|
|
3
|
+
"description": "The one place a server keeping no durable record answers something other than NOT_SUPPORTED for a read it cannot mount: the blueprint registry MATCHED the caller's key, so what the read found is a component it has no channel to deliver. The answer is NOT_MOUNTABLE — and because the match depends on the key rather than on the row, it is still identical for a refused read and a miss. This server wires NO delivery channel at all, which is what makes undeliverability follow from the declared shape rather than from any one implementation's choice about how it serves a registry match.",
|
|
4
|
+
"server": { "durableSubstrate": "none", "blueprintRegistry": true },
|
|
5
|
+
"caller": "other",
|
|
6
|
+
"seeds": [
|
|
7
|
+
{ "kind": "registered-blueprint", "as": "fallback" },
|
|
8
|
+
{ "kind": "committed-render", "session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70" }
|
|
9
|
+
],
|
|
10
|
+
"reads": [
|
|
11
|
+
{
|
|
12
|
+
"as": "refused",
|
|
13
|
+
"locator": {
|
|
14
|
+
"kind": "render",
|
|
15
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
16
|
+
"key": { "kind": "registered", "seed": "fallback" }
|
|
17
|
+
},
|
|
18
|
+
"expect": {
|
|
19
|
+
"kind": "typed-error",
|
|
20
|
+
"jsonRpcCode": -32006,
|
|
21
|
+
"dataCode": "NOT_MOUNTABLE"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"as": "miss",
|
|
26
|
+
"locator": {
|
|
27
|
+
"kind": "render",
|
|
28
|
+
"session": "8d5b0e41-2c96-4a7f-b3d8-1e07f9a2c645",
|
|
29
|
+
"key": { "kind": "registered", "seed": "fallback" }
|
|
30
|
+
},
|
|
31
|
+
"expect": {
|
|
32
|
+
"kind": "typed-error",
|
|
33
|
+
"jsonRpcCode": -32006,
|
|
34
|
+
"dataCode": "NOT_MOUNTABLE"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"indistinguishable": ["refused", "miss"],
|
|
39
|
+
"disclosesNothing": ["3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70"]
|
|
40
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "substrate-less-fusion-of-refusal-and-miss",
|
|
3
|
+
"description": "The disclosure obligation restated for a server that keeps no durable record. NOT_SUPPORTED describes the server, so it must answer for a refused row too. A deployment that reported NOT_FOUND for rows that exist and NOT_SUPPORTED for ones that never did would have rebuilt the existence oracle out of its own wiring.",
|
|
4
|
+
"server": { "durableSubstrate": "none", "liveChannel": true },
|
|
5
|
+
"caller": "other",
|
|
6
|
+
"seeds": [{ "kind": "committed-render", "session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70" }],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "refused",
|
|
10
|
+
"locator": { "kind": "render", "session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70" },
|
|
11
|
+
"expect": {
|
|
12
|
+
"kind": "typed-error",
|
|
13
|
+
"jsonRpcCode": -32006,
|
|
14
|
+
"dataCode": "NOT_SUPPORTED"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"as": "miss",
|
|
19
|
+
"locator": { "kind": "render", "session": "8d5b0e41-2c96-4a7f-b3d8-1e07f9a2c645" },
|
|
20
|
+
"expect": {
|
|
21
|
+
"kind": "typed-error",
|
|
22
|
+
"jsonRpcCode": -32006,
|
|
23
|
+
"dataCode": "NOT_SUPPORTED"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"indistinguishable": ["refused", "miss"],
|
|
28
|
+
"disclosesNothing": ["3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70"]
|
|
29
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The closed classification a typed read failure carries on
|
|
3
|
+
* `error.data.code`.
|
|
4
|
+
*
|
|
5
|
+
* The kit's decoupled copy, per the authoring posture in `../types`:
|
|
6
|
+
* fixtures compile against the kit's frozen vocabulary, never the live
|
|
7
|
+
* protocol types. CLOSED, not extensibly-closed — a fifth code is a kit
|
|
8
|
+
* version bump, because a catalog cannot grade a class it ships no case
|
|
9
|
+
* for.
|
|
10
|
+
*/
|
|
11
|
+
export type ResourceReadErrorCodeDecl = 'NOT_FOUND' | 'BLUEPRINT_UNRESOLVABLE' | 'NOT_SUPPORTED' | 'NOT_MOUNTABLE';
|
|
12
|
+
/**
|
|
13
|
+
* How much of the record-keeping substrate a re-mint needs the server
|
|
14
|
+
* to have bound.
|
|
15
|
+
*
|
|
16
|
+
* Restoring an evicted render needs the whole set — the record naming
|
|
17
|
+
* what the render was, the blueprint it names, and the component body
|
|
18
|
+
* behind that blueprint. A server holding only part of it can restore
|
|
19
|
+
* nothing, so `identity-only` and `blueprints-only` are as
|
|
20
|
+
* substrate-less as `none`; they exist as separate arms because they
|
|
21
|
+
* are the shapes an operator actually reaches, by provisioning one
|
|
22
|
+
* store and forgetting the other.
|
|
23
|
+
*
|
|
24
|
+
* `all-ephemeral` (#457): every store bound, every store DECLARING
|
|
25
|
+
* ephemeral durability — binding is not durability, and a server whose
|
|
26
|
+
* records die with the process MUST fuse like one holding nothing.
|
|
27
|
+
* The arm an operator reaches by wiring three in-memory stores.
|
|
28
|
+
*/
|
|
29
|
+
export type DurableSubstrateWiring = 'all' | 'none' | 'identity-only' | 'blueprints-only' | 'all-ephemeral';
|
|
30
|
+
/** The deployment shape a case needs the server under test to have. */
|
|
31
|
+
export interface ResourceReadServerShape {
|
|
32
|
+
readonly durableSubstrate: DurableSubstrateWiring;
|
|
33
|
+
/** Bind the blueprint registry a read can fall back to. Default false. */
|
|
34
|
+
readonly blueprintRegistry?: boolean;
|
|
35
|
+
/** Bind static component delivery (a fetchable component URL). Default false. */
|
|
36
|
+
readonly staticDelivery?: boolean;
|
|
37
|
+
/** Bind the live delivery channel. Default false. */
|
|
38
|
+
readonly liveChannel?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whose read this is. `owner` holds the seeded renders; `other` is a
|
|
42
|
+
* caller with valid credentials and no claim to them — the identity
|
|
43
|
+
* every disclosure obligation is stated against.
|
|
44
|
+
*/
|
|
45
|
+
export type ResourceReadCaller = 'owner' | 'other';
|
|
46
|
+
/**
|
|
47
|
+
* State the driver installs before the reads. CLOSED vocabulary: an
|
|
48
|
+
* unknown seed kind is a case-authoring error the runner throws on,
|
|
49
|
+
* never a skip and never a verdict on the server.
|
|
50
|
+
*
|
|
51
|
+
* Every seed belongs to the `owner` identity, whichever caller the case
|
|
52
|
+
* then reads as — that is what makes a refused read a read of something
|
|
53
|
+
* that really is there.
|
|
54
|
+
*/
|
|
55
|
+
export type ResourceReadSeed = {
|
|
56
|
+
/** A durable record of a render that has since been evicted. */
|
|
57
|
+
readonly kind: 'identity-record';
|
|
58
|
+
readonly session: string;
|
|
59
|
+
/**
|
|
60
|
+
* The contract key the record was stamped with — the
|
|
61
|
+
* `blueprintKey` segment a resume locator carries. Authored
|
|
62
|
+
* explicitly so nothing about which key resolves which record is
|
|
63
|
+
* implicit: a probe reading this record spells the same literal.
|
|
64
|
+
*/
|
|
65
|
+
readonly key: string;
|
|
66
|
+
/** Whether the record names a blueprint at all. */
|
|
67
|
+
readonly blueprint: 'named' | 'unnamed';
|
|
68
|
+
} | {
|
|
69
|
+
/** The durable blueprint an `identity-record` names. */
|
|
70
|
+
readonly kind: 'durable-blueprint';
|
|
71
|
+
/** Whether the blueprint stores a reference to a component body. */
|
|
72
|
+
readonly componentRef: 'present' | 'absent';
|
|
73
|
+
/** Whether the body behind that reference is still stored. */
|
|
74
|
+
readonly body: 'stored' | 'purged';
|
|
75
|
+
} | {
|
|
76
|
+
/** A live render row that has committed a component. */
|
|
77
|
+
readonly kind: 'committed-render';
|
|
78
|
+
readonly session: string;
|
|
79
|
+
} | {
|
|
80
|
+
/** A live render row whose generation has not committed yet. */
|
|
81
|
+
readonly kind: 'uncommitted-render';
|
|
82
|
+
readonly session: string;
|
|
83
|
+
} | {
|
|
84
|
+
/**
|
|
85
|
+
* A blueprint published to the registry a read falls back to. The
|
|
86
|
+
* SERVER computes its key, so the driver reports the key back
|
|
87
|
+
* through {@link PreparedResourceReadScenario.registeredKeys}
|
|
88
|
+
* under this `as` name, and probes reference it there.
|
|
89
|
+
*/
|
|
90
|
+
readonly kind: 'registered-blueprint';
|
|
91
|
+
readonly as: string;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* The blueprint-key segment of a locator.
|
|
95
|
+
*
|
|
96
|
+
* `literal` is a value the case authors — the kit builds the URI from
|
|
97
|
+
* it, so the case pins the exact bytes read. `registered` defers to a
|
|
98
|
+
* key the server computed for a `registered-blueprint` seed, which is
|
|
99
|
+
* the one value a case cannot know in advance.
|
|
100
|
+
*/
|
|
101
|
+
export type ResourceReadKey = {
|
|
102
|
+
readonly kind: 'literal';
|
|
103
|
+
readonly value: string;
|
|
104
|
+
} | {
|
|
105
|
+
readonly kind: 'registered';
|
|
106
|
+
readonly seed: string;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* What gets read.
|
|
110
|
+
*
|
|
111
|
+
* `render` is the protocol's locator grammar and the kit builds the URI
|
|
112
|
+
* — a case never spells a well-formed locator out by hand, so the
|
|
113
|
+
* grammar has one owner. `raw` exists for the probes whose whole point
|
|
114
|
+
* is a URI that does NOT name a locator; there the exact string IS the
|
|
115
|
+
* input under test.
|
|
116
|
+
*/
|
|
117
|
+
export type ResourceReadLocator = {
|
|
118
|
+
readonly kind: 'render';
|
|
119
|
+
readonly session: string;
|
|
120
|
+
readonly key?: ResourceReadKey;
|
|
121
|
+
} | {
|
|
122
|
+
readonly kind: 'raw';
|
|
123
|
+
readonly uri: string;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* What one probe's read MUST produce. CLOSED vocabulary — see the
|
|
127
|
+
* module docstring for what each arm deliberately leaves ungraded.
|
|
128
|
+
*/
|
|
129
|
+
export type ResourceReadExpectation = {
|
|
130
|
+
readonly kind: 'typed-error';
|
|
131
|
+
/**
|
|
132
|
+
* The canonical number. `NOT_FOUND` rides on the resource-missing
|
|
133
|
+
* number; the other three ride on the mount-unavailable one. Both
|
|
134
|
+
* are pinned as literals in the case JSON so a rename that moved
|
|
135
|
+
* the wire fails here rather than passing against a constant.
|
|
136
|
+
*/
|
|
137
|
+
readonly jsonRpcCode: number;
|
|
138
|
+
readonly dataCode: ResourceReadErrorCodeDecl;
|
|
139
|
+
/**
|
|
140
|
+
* Assert `error.data` carries NO `detail` key. Normative for
|
|
141
|
+
* `NOT_FOUND`, whose body must not vary; not authored elsewhere,
|
|
142
|
+
* because `detail` is optional context a conformant server may or
|
|
143
|
+
* may not attach.
|
|
144
|
+
*/
|
|
145
|
+
readonly detailAbsent?: boolean;
|
|
146
|
+
} | {
|
|
147
|
+
/**
|
|
148
|
+
* An error the resource-read classification does not reach:
|
|
149
|
+
* `data` carries no resource-read code.
|
|
150
|
+
*
|
|
151
|
+
* The NUMBER is deliberately not pinned — not even negatively.
|
|
152
|
+
* MCP assigns the resource-missing number to a `resources/read`
|
|
153
|
+
* of a URI the server does not serve, so a framework that maps
|
|
154
|
+
* every unrecognized URI onto it is correct, and banning that
|
|
155
|
+
* number here would fail it forever. The classification is what
|
|
156
|
+
* separates the two cases, and it is enough: a genuine miss
|
|
157
|
+
* carries one, a malformed URI carries none.
|
|
158
|
+
*/
|
|
159
|
+
readonly kind: 'outside-typed-set';
|
|
160
|
+
} | {
|
|
161
|
+
/** A result whose contents declare a delivery channel. */
|
|
162
|
+
readonly kind: 'live-mount';
|
|
163
|
+
};
|
|
164
|
+
/** One read within a case. */
|
|
165
|
+
export interface ResourceReadProbe {
|
|
166
|
+
/** Name, unique within the case. Referenced by `indistinguishable`. */
|
|
167
|
+
readonly as: string;
|
|
168
|
+
readonly locator: ResourceReadLocator;
|
|
169
|
+
readonly expect: ResourceReadExpectation;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* One resource-read conformance case. Authored as JSON under
|
|
173
|
+
* `./cases/`, consumed via {@link resourceReadCases}, graded by
|
|
174
|
+
* {@link runResourceReadConformance}.
|
|
175
|
+
*
|
|
176
|
+
* The shape IS the public API — additive changes only.
|
|
177
|
+
*/
|
|
178
|
+
export interface ResourceReadConformanceCase {
|
|
179
|
+
/** Unique case name. MUST match the JSON filename without `.json`. */
|
|
180
|
+
readonly name: string;
|
|
181
|
+
/** Which obligation this case proves. */
|
|
182
|
+
readonly description: string;
|
|
183
|
+
/** The deployment shape the driver brings up. */
|
|
184
|
+
readonly server: ResourceReadServerShape;
|
|
185
|
+
/** Whose read this is. */
|
|
186
|
+
readonly caller: ResourceReadCaller;
|
|
187
|
+
/** State installed before the reads. May be empty. */
|
|
188
|
+
readonly seeds: readonly ResourceReadSeed[];
|
|
189
|
+
/** The reads, dispatched in order against the one prepared server. */
|
|
190
|
+
readonly reads: readonly ResourceReadProbe[];
|
|
191
|
+
/**
|
|
192
|
+
* Probe names whose RAW error frames MUST be byte-identical.
|
|
193
|
+
*
|
|
194
|
+
* This is the disclosure obligation stated positively: a read of a
|
|
195
|
+
* locator the caller may not see and a read of one that never existed
|
|
196
|
+
* must be the same bytes, or the read is an existence oracle for
|
|
197
|
+
* other callers' renders. Compared on the serialized frames with only
|
|
198
|
+
* the session segments normalized away — a locator is caller-supplied
|
|
199
|
+
* and a server that echoes it back is caught by `disclosesNothing`,
|
|
200
|
+
* not excused here.
|
|
201
|
+
*/
|
|
202
|
+
readonly indistinguishable?: readonly string[];
|
|
203
|
+
/**
|
|
204
|
+
* Literal substrings that MUST NOT appear anywhere in any error frame
|
|
205
|
+
* this case produces. The values a refusal would leak if a diagnostic
|
|
206
|
+
* escaped into `message` or `detail`.
|
|
207
|
+
*/
|
|
208
|
+
readonly disclosesNothing?: readonly string[];
|
|
209
|
+
}
|
|
210
|
+
/** What the driver is asked to bring up. */
|
|
211
|
+
export interface ResourceReadScenario {
|
|
212
|
+
/** The case being prepared — for the driver's own diagnostics. */
|
|
213
|
+
readonly caseName: string;
|
|
214
|
+
readonly server: ResourceReadServerShape;
|
|
215
|
+
readonly caller: ResourceReadCaller;
|
|
216
|
+
readonly seeds: readonly ResourceReadSeed[];
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The delivery-channel fields of the render meta a successful read
|
|
220
|
+
* projects onto its contents.
|
|
221
|
+
*
|
|
222
|
+
* Narrowed to what the invariant needs: the kit asks "can this be
|
|
223
|
+
* mounted", not "what does it look like". A driver reports these off
|
|
224
|
+
* whatever its shell carries — the projection is protocol surface, the
|
|
225
|
+
* markup that transports it is not.
|
|
226
|
+
*/
|
|
227
|
+
export interface ResourceReadRenderMeta {
|
|
228
|
+
/** A fetchable component URL — the static delivery channel. */
|
|
229
|
+
readonly codeUrl?: string;
|
|
230
|
+
/** The live channel's endpoint. Only a channel WITH a token. */
|
|
231
|
+
readonly wsUrl?: string;
|
|
232
|
+
/** The live channel's token. Only a channel WITH an endpoint. */
|
|
233
|
+
readonly wsToken?: string;
|
|
234
|
+
/** A server-emitted system card, which carries its own content. */
|
|
235
|
+
readonly kind?: string;
|
|
236
|
+
}
|
|
237
|
+
/** The raw JSON-RPC error body a server put on the wire. */
|
|
238
|
+
export interface JsonRpcErrorFrame {
|
|
239
|
+
readonly code: number;
|
|
240
|
+
readonly message: string;
|
|
241
|
+
readonly data?: unknown;
|
|
242
|
+
}
|
|
243
|
+
/** What one read produced. */
|
|
244
|
+
export type ResourceReadOutcome = {
|
|
245
|
+
readonly kind: 'mount';
|
|
246
|
+
readonly renderMeta: ResourceReadRenderMeta;
|
|
247
|
+
} | {
|
|
248
|
+
readonly kind: 'error';
|
|
249
|
+
readonly error: JsonRpcErrorFrame;
|
|
250
|
+
};
|
|
251
|
+
/** A server brought up in a declared shape, ready to be read. */
|
|
252
|
+
export interface PreparedResourceReadScenario {
|
|
253
|
+
/**
|
|
254
|
+
* Read one locator. MUST resolve — a protocol-level failure is
|
|
255
|
+
* `{kind: 'error'}` carrying the RAW frame, not a throw. A throw is
|
|
256
|
+
* graded as a FAIL, since the read is the thing under test.
|
|
257
|
+
*
|
|
258
|
+
* Honest-grade contract: the reported outcome MUST be what the server
|
|
259
|
+
* really produced. A driver that fabricates a passing outcome is
|
|
260
|
+
* cheating its own conformance audit — the implementer's integrity to
|
|
261
|
+
* keep, exactly as with every other adapter the kit defines.
|
|
262
|
+
*/
|
|
263
|
+
read(uri: string): Promise<ResourceReadOutcome>;
|
|
264
|
+
/**
|
|
265
|
+
* Keys the server computed for this case's `registered-blueprint`
|
|
266
|
+
* seeds, by their `as` name. Required whenever a probe references
|
|
267
|
+
* one; a case whose reference is unresolved SKIPS, because the kit
|
|
268
|
+
* cannot construct the locator it was supposed to read.
|
|
269
|
+
*/
|
|
270
|
+
readonly registeredKeys?: Readonly<Record<string, string>>;
|
|
271
|
+
/** Tear the scenario down. Invoked after every case, pass or fail. */
|
|
272
|
+
dispose?(): Promise<void>;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Bring up a server in the declared shape. Throwing signals "I cannot
|
|
276
|
+
* express this scenario" and the runner records a SKIP with the
|
|
277
|
+
* message — never a pass.
|
|
278
|
+
*/
|
|
279
|
+
export type ResourceReadScenarioDriver = (scenario: ResourceReadScenario) => Promise<PreparedResourceReadScenario>;
|
|
280
|
+
/**
|
|
281
|
+
* Every resource-read case the kit ships, in deterministic order: the
|
|
282
|
+
* four typed classes, then the disclosure fusions, then the boundary of
|
|
283
|
+
* the classification, then the two mount cases.
|
|
284
|
+
*/
|
|
285
|
+
export declare const resourceReadCases: readonly ResourceReadConformanceCase[];
|
|
286
|
+
/** The resource URI every render locator hangs off. */
|
|
287
|
+
export declare const GGUI_RENDER_RESOURCE_URI = "ui://ggui/render";
|
|
288
|
+
/**
|
|
289
|
+
* Build the URI a probe reads. The kit owns the grammar so no case
|
|
290
|
+
* spells a well-formed locator out by hand; a `raw` locator passes
|
|
291
|
+
* through verbatim, which is the point of that arm.
|
|
292
|
+
*/
|
|
293
|
+
export declare function renderLocatorUri(locator: ResourceReadLocator, registeredKeys?: Readonly<Record<string, string>>): string;
|
|
294
|
+
/**
|
|
295
|
+
* Does this render meta carry enough to paint something? One of the
|
|
296
|
+
* three delivery channels a runtime knows: a static component URL, a
|
|
297
|
+
* live channel, or a server-emitted system card.
|
|
298
|
+
*
|
|
299
|
+
* The live channel needs BOTH halves — an endpoint with no token cannot
|
|
300
|
+
* be opened, and a token with no endpoint has nowhere to go — so a
|
|
301
|
+
* half-declared one is not a channel.
|
|
302
|
+
*/
|
|
303
|
+
export declare function declaresDeliveryChannel(meta: ResourceReadRenderMeta): boolean;
|
|
304
|
+
/** One obligation a server under test did not meet. */
|
|
305
|
+
export interface ResourceReadConformanceFailure {
|
|
306
|
+
/** The case that failed. */
|
|
307
|
+
readonly name: string;
|
|
308
|
+
/** The probe whose read produced it, when the failure is probe-scoped. */
|
|
309
|
+
readonly probe?: string;
|
|
310
|
+
/** Which obligation was violated, in the catalog's own words. */
|
|
311
|
+
readonly obligation: string;
|
|
312
|
+
readonly expected: unknown;
|
|
313
|
+
readonly actual: unknown;
|
|
314
|
+
readonly message: string;
|
|
315
|
+
}
|
|
316
|
+
/** One case the kit could not grade, and why. */
|
|
317
|
+
export interface ResourceReadConformanceSkip {
|
|
318
|
+
readonly name: string;
|
|
319
|
+
readonly reason: string;
|
|
320
|
+
}
|
|
321
|
+
/** Outcome of grading a server against the catalog. */
|
|
322
|
+
export interface ResourceReadConformanceResult {
|
|
323
|
+
/** Names of cases the server satisfied. */
|
|
324
|
+
readonly passed: readonly string[];
|
|
325
|
+
/** Cases the server got wrong — at most one entry per case. */
|
|
326
|
+
readonly failed: readonly ResourceReadConformanceFailure[];
|
|
327
|
+
/** Cases the kit could not observe. Never a pass, never a fail. */
|
|
328
|
+
readonly skipped: readonly ResourceReadConformanceSkip[];
|
|
329
|
+
}
|
|
330
|
+
/** Options for {@link runResourceReadConformance}. */
|
|
331
|
+
export interface RunResourceReadConformanceOptions {
|
|
332
|
+
/** Grade only these case names. Useful when debugging one obligation. */
|
|
333
|
+
readonly only?: readonly string[];
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Grade a server against the catalog.
|
|
337
|
+
*
|
|
338
|
+
* One scenario is prepared per case, every probe is read against it in
|
|
339
|
+
* order, then the cross-probe obligations are checked. A case
|
|
340
|
+
* contributes at most one failure — the first obligation it broke —
|
|
341
|
+
* so the result reads as one verdict per case.
|
|
342
|
+
*
|
|
343
|
+
* A conformant server produces an empty `failed` array. An empty
|
|
344
|
+
* `passed` array is NOT success: a run where every case skipped proves
|
|
345
|
+
* nothing, and callers should treat it the way the WebSocket runner's
|
|
346
|
+
* consumers already do.
|
|
347
|
+
*/
|
|
348
|
+
export declare function runResourceReadConformance(drive: ResourceReadScenarioDriver, options?: RunResourceReadConformanceOptions): Promise<ResourceReadConformanceResult>;
|
|
349
|
+
/**
|
|
350
|
+
* Validating parse of one authored case.
|
|
351
|
+
*
|
|
352
|
+
* The input is `unknown` BY DESIGN — this function IS the trust
|
|
353
|
+
* boundary, so it never leans on the static union it produces evidence
|
|
354
|
+
* for. The catalog's JSON enters the type system through a compile-time
|
|
355
|
+
* cast (tsc widens JSON-module string literals), which means the static
|
|
356
|
+
* type is the claim being checked here, not support for it. Same
|
|
357
|
+
* posture as the WebSocket runner's `parseSetupStep`.
|
|
358
|
+
*
|
|
359
|
+
* An unknown seed kind, locator kind, expectation kind or
|
|
360
|
+
* classification is a CASE-AUTHORING error: the runner throws, aborting
|
|
361
|
+
* the run loudly. It is never a skip and never a fail — those verdicts
|
|
362
|
+
* describe the server under test, not the catalog.
|
|
363
|
+
*
|
|
364
|
+
* Exported for the kit's own meta-tests and reachable from the
|
|
365
|
+
* `./resource-read-conformance` subpath, but NOT re-exported from the
|
|
366
|
+
* package root — the runner calls it for you, and a consumer needing it
|
|
367
|
+
* directly is authoring their own catalog rather than grading against
|
|
368
|
+
* this one.
|
|
369
|
+
*/
|
|
370
|
+
export declare function parseCase(input: unknown): ResourceReadConformanceCase;
|
|
371
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resource-read-conformance/index.ts"],"names":[],"mappings":"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"}
|