@ggui-ai/protocol-conformance 0.6.2 → 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/README.md
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
# @ggui-ai/protocol-conformance
|
|
2
2
|
|
|
3
|
-
Conformance test kit for the ggui protocol. Ships
|
|
3
|
+
Conformance test kit for the ggui protocol. Ships JSON case catalogs + runners that drive them against a live implementation — the behavioral fixtures over WebSocket, the `resources/read` cases over the MCP binding — and report scorecard-style pass / fail / skip output.
|
|
4
4
|
|
|
5
5
|
This kit is the protocol's conformance surface: it lets a third-party MCP builder prove their implementation is protocol-conformant without reimplementing the test harness.
|
|
6
6
|
|
|
7
7
|
## Grading mechanisms
|
|
8
8
|
|
|
9
|
-
The kit grades protocol obligations through **
|
|
9
|
+
The kit grades protocol obligations through **four mechanisms**, each matched to where the obligation is observable:
|
|
10
10
|
|
|
11
11
|
1. **Path-A WS fixtures** — wire-observable behaviors graded from frames the runner collects over the live channel (acks, error frames, canonical `data` deliveries).
|
|
12
12
|
2. **Pure-function catalogs** — deterministic validation obligations (the SPEC §7.7.2 gadget obligations) graded against a caller-supplied function; no host, render, or transport.
|
|
13
13
|
3. **Session-state host read-back** — stateful obligations with no wire response (e.g. `host_context_observed` persisting onto `GguiSession.hostContext`): the runner dispatches the C→S frame, waits out the observation window, then reads the GguiSession field back through `ConformanceHost.readSessionField()` and deep-equals it against the fixture's `expected`. No host (or a host without the method, or a read that throws) → the fixture SKIPS with the reason — a host that cannot read state cannot grade it, and the kit never converts that gap into a pass.
|
|
14
|
+
4. **MCP-binding scenario driver** — request/response obligations on the MCP surface, where the deployment shape is part of what is under test. The `resources/read` catalog is the first: a case declares a server shape, a caller identity and a seed set, the adopter's driver brings a server up that way, and the kit reads locators against it and grades the raw JSON-RPC frames. A driver that cannot express a scenario throws, and the case SKIPS — never passes.
|
|
14
15
|
|
|
15
|
-
A
|
|
16
|
+
A fifth surface — the **Path-B browser-host driver** for DOM-level claims (`bootstrap-failure`, `props-update`) — is honestly absent: it is not yet packaged, and those fixtures skip wherever the kit runs (see below).
|
|
16
17
|
|
|
17
18
|
## Transport
|
|
18
19
|
|
|
19
|
-
**
|
|
20
|
+
**The behavioral fixture catalog is WebSocket-only.** The canonical ggui live-channel transport is WS (see SPEC §12 Transport Bindings). `TransportConfig` is shaped as an extensibly-closed union so later live-channel transports (HTTP long-poll) can be added without breaking the public API.
|
|
21
|
+
|
|
22
|
+
The MCP surface is graded separately, by catalog rather than by transport config — see `resource-read-conformance` below. Its cases are deliberately NOT registered in `fixturesByContract`: everything in that map is driven over a WebSocket, so an MCP case there would be a permanent skip on every WS run, which is the false gate the kit's exact skip-set pinning exists to prevent. `resources/read` is the only MCP method bound today; `tools/call` has no driver yet.
|
|
20
23
|
|
|
21
24
|
## Path-A vs Path-B matchability
|
|
22
25
|
|
|
@@ -42,7 +45,7 @@ The Path-B driver is not yet packaged — no browser-host harness ships with the
|
|
|
42
45
|
|
|
43
46
|
The partition is intentional: Path-A FAILs are vendor-neutrality bugs the server owns; Path-B SKIPs are not fails — they are claims a different driver is responsible for.
|
|
44
47
|
|
|
45
|
-
One declared grading gap on the action loop: `action-ack` proves the append half of the consume-buffer contract; the retrieval half (the agent draining the buffer via `ggui_consume`) is an MCP tool call a WS
|
|
48
|
+
One declared grading gap on the action loop: `action-ack` proves the append half of the consume-buffer contract; the retrieval half (the agent draining the buffer via `ggui_consume`) is an MCP **tool call**, which a WS runner cannot drive. The resource-read catalog below does not close it — that driver binds `resources/read`, and `tools/call` is a different method with a different seam. Grading it needs a tool-call driver, not a weaker WS assertion.
|
|
46
49
|
|
|
47
50
|
## Pure-function conformance catalogs
|
|
48
51
|
|
|
@@ -74,27 +77,62 @@ if (schema.failed.length + gate.failed.length + urls.failed.length > 0) {
|
|
|
74
77
|
|
|
75
78
|
The `schema-conformance` meta-test binds its catalog to the live `@ggui-ai/protocol` `clientCapabilitiesSpecSchema` — a drift-catch if the wire schema diverges from the §7.7.2 obligations the catalog freezes. The `registration-conformance` and `resolution-conformance` meta-tests verify catalog coherence against faithful in-test implementations (the kit stays vendor-neutral — it does not depend on a server implementation); grading the _shipping_ gate / resolver is an implementation-side test that drives the corresponding runner.
|
|
76
79
|
|
|
80
|
+
## Resource-read conformance — the MCP binding
|
|
81
|
+
|
|
82
|
+
A read of a render locator (`ui://ggui/render/{sessionId}` or `ui://ggui/render/{sessionId}/{blueprintKey}`) has exactly **two exits**: a result whose contents declare a delivery channel — a live mount — or one typed JSON-RPC error. There is no third outcome, and in particular no successful result carrying a shell that can never paint anything.
|
|
83
|
+
|
|
84
|
+
That is what makes the read host-checkable. A host that gets `contents` back can mount them without inspecting anything; a host that gets an error routes on `error.data.code` — "come back never" versus "come back with a fresh render" — without parsing prose.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { runResourceReadConformance } from "@ggui-ai/protocol-conformance/resource-read-conformance";
|
|
88
|
+
|
|
89
|
+
const result = await runResourceReadConformance(async (scenario) => {
|
|
90
|
+
// Bring YOUR server up in `scenario.server`'s shape, as
|
|
91
|
+
// `scenario.caller`, with `scenario.seeds` applied.
|
|
92
|
+
const server = await bootMyServer(scenario);
|
|
93
|
+
return {
|
|
94
|
+
// Keys your registry assigned to `registered-blueprint` seeds.
|
|
95
|
+
registeredKeys: server.registeredKeys,
|
|
96
|
+
// MUST resolve. A protocol failure is `{kind: 'error'}` carrying
|
|
97
|
+
// the RAW frame — an MCP client's reconstructed error rewrites
|
|
98
|
+
// `message`, and the disclosure obligation is graded on bytes.
|
|
99
|
+
read: (uri) => server.readResource(uri),
|
|
100
|
+
dispose: () => server.close(),
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (result.failed.length > 0 || result.passed.length === 0) process.exit(1);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Throwing from the driver means "I cannot express this scenario" and the case **skips** with that reason — never passes. Throwing from `read` is a **fail**, because the read is the thing under test.
|
|
108
|
+
|
|
109
|
+
The catalog grades all four failure classes (`NOT_FOUND` on `-32002`; `BLUEPRINT_UNRESOLVABLE` / `NOT_SUPPORTED` / `NOT_MOUNTABLE` on `-32006`), the mount half on both a live row and a re-minted one, and the disclosure obligation: a read refused for lack of entitlement and a read of a locator that never existed must be **byte-identical**, on a server that keeps durable records, on one that keeps none, on the two half-wired shapes in between, and on one whose blueprint registry matches the probed key.
|
|
110
|
+
|
|
111
|
+
It deliberately does **not** grade: the order in which a substrate-less server answers (`NOT_SUPPORTED` describes the deployment, so answering it immediately is correct); `detail` wording on any code; the `NOT_FOUND` message literal (its _constancy_ is what is normative); internal-error message text; the number a URI naming no locator receives (that belongs to the transport binding — only the negative is graded, that it must not be one of the four); and the shell's markup (success is graded on the projected render meta, never on DOM shape).
|
|
112
|
+
|
|
77
113
|
## Conformance status
|
|
78
114
|
|
|
79
115
|
What is actually graded against shipping code today, and what is still awaiting a driver. This is an inventory, not a roadmap — a mechanism is listed as proven only if a test in the repo drives it against the real implementation on every push.
|
|
80
116
|
|
|
81
|
-
Every test below is a plain `*.test.ts` inside a package's `src/`, so it runs in that package's ordinary vitest suite. The ggui repo's per-push CI runs `turbo run test` across all non-e2e packages, so **all
|
|
117
|
+
Every test below is a plain `*.test.ts` inside a package's `src/`, so it runs in that package's ordinary vitest suite. The ggui repo's per-push CI runs `turbo run test` across all non-e2e packages, so **all six rows below are gated on every push** — the kit needs no dedicated workflow, and adopters wiring it into their own CI need nothing more than their existing unit-test task.
|
|
82
118
|
|
|
83
|
-
| Obligation
|
|
84
|
-
|
|
|
85
|
-
| Gadget wire schema (§7.7.2)
|
|
86
|
-
| Registration gate (§7.7.3, §7.9)
|
|
87
|
-
| Bundle-URL resolution (§7.7.2)
|
|
88
|
-
| Path-A WS fixtures — first-party
|
|
89
|
-
| Path-A WS fixtures — vendor-neutral
|
|
119
|
+
| Obligation | Graded against | Driver |
|
|
120
|
+
| ------------------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| Gadget wire schema (§7.7.2) | the shipping `@ggui-ai/protocol` `clientCapabilitiesSpecSchema` | this kit's own `src/schema-conformance/schema-conformance.test.ts` |
|
|
122
|
+
| Registration gate (§7.7.3, §7.9) | the shipping gate trio in `@ggui-ai/mcp-server-handlers` | `mcp-server-handlers/src/renders/assert-gadgets.conformance.test.ts` |
|
|
123
|
+
| Bundle-URL resolution (§7.7.2) | the shipping `resolveGadgetUrls` in `@ggui-ai/mcp-server-handlers` | `mcp-server-handlers/src/renders/resolve-gadget-urls.conformance.test.ts` |
|
|
124
|
+
| Path-A WS fixtures — first-party | the real `@ggui-ai/mcp-server` GguiSession channel, booted in-process on an ephemeral port | `mcp-server/src/ggui-session-channel.conformance.test.ts` — **8 pass / 4 skip / 0 fail** |
|
|
125
|
+
| Path-A WS fixtures — vendor-neutral | `@ggui-ai/protocol-reference-server` | `protocol-reference-server/src/conformance.test.ts` — **9 pass / 3 skip / 0 fail** |
|
|
126
|
+
| `resources/read` typed failures + mount invariant | the shipping `registerGguiRenderResourceTemplate` in `@ggui-ai/mcp-server` | `mcp-server/src/mcp-apps-outbound.resource-read.conformance.test.ts` — **12 pass / 0 skip / 0 fail** |
|
|
90
127
|
|
|
91
|
-
Both WS drivers pin their pass set _and_ their skip set as exact sets. A fixture silently degrading to a skip fails the build, and so does a skipped fixture that quietly starts passing — a skip set that can grow unnoticed is a false gate, and re-pinning it is meant to be a deliberate act.
|
|
128
|
+
Both WS drivers pin their pass set _and_ their skip set as exact sets, and the resource-read driver pins its skip set as exactly empty. A fixture silently degrading to a skip fails the build, and so does a skipped fixture that quietly starts passing — a skip set that can grow unnoticed is a false gate, and re-pinning it is meant to be a deliberate act.
|
|
92
129
|
|
|
93
130
|
**Awaiting a driver:**
|
|
94
131
|
|
|
95
|
-
- **Path-B browser-host fixtures** — `bootstrap-bundle-fetch-failed`, `bootstrap-meta-missing` (both need MCP-Apps-host fault injection) and `props-update-roundtrip` (assertion is on rendered DOM). No browser-host adapter ships with the kit, so these skip on every driver above. Honestly absent, not silently passing.
|
|
132
|
+
- **Path-B browser-host fixtures** — `bootstrap-bundle-fetch-failed`, `bootstrap-meta-missing` (both need MCP-Apps-host fault injection) and `props-update-roundtrip` (assertion is on rendered DOM). No browser-host adapter ships with the kit, so these skip on every WS driver above. Honestly absent, not silently passing.
|
|
96
133
|
- **`version-mismatch` on the first-party server** — needs a `server-version-override` seam the channel deliberately does not expose; adding a production seam with no production caller purely to drive a fixture was rejected. It passes on the reference server, which has a per-render override.
|
|
97
|
-
- **The `ggui_consume` retrieval half of the action loop
|
|
134
|
+
- **The `ggui_consume` retrieval half of the action loop, and `stream-delivery-roundtrip`** — both are `tools/call` obligations (`ggui_consume`, `ggui_emit`). The resource-read driver binds `resources/read` only, so neither is closed by it; both await a tool-call driver.
|
|
135
|
+
- **`resources/read` on a second implementation** — the catalog is vendor-neutral by construction (the kit imports no server; the adopter supplies the driver), but it is graded against one implementation today. A second binding is what would ground the vendor-neutrality claim empirically, the way `protocol-reference-server` does for the WS catalog.
|
|
98
136
|
|
|
99
137
|
## Public API
|
|
100
138
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/consume-buffer/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/consume-buffer/index.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;gCAEgC;AAChC,eAAO,MAAM,qBAAqB,EAAE,SAAS,QAAQ,EAIpD,CAAC"}
|
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
*
|
|
21
21
|
* The retrieval half — the agent draining the buffer via
|
|
22
22
|
* `ggui_consume` — is an MCP tool call a WS-only runner cannot drive;
|
|
23
|
-
* that obligation belongs to
|
|
23
|
+
* that obligation belongs to a driver bound to `tools/call`, not this
|
|
24
|
+
* catalog. The kit's `resources/read` driver
|
|
25
|
+
* (`../../resource-read-conformance`) binds a different method and does
|
|
26
|
+
* not close it.
|
|
24
27
|
* Same declared-gap posture for the schema-validity meta-check on the
|
|
25
28
|
* DECLARED schema itself: a malformed authored schema is a fixture-
|
|
26
29
|
* authoring error the runner throws on (validating parse), while a
|
package/dist/fixtures/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* ## Current coverage
|
|
22
22
|
*
|
|
23
|
-
* Six sub-modules with content (12 fixtures). Additional sub-modules
|
|
23
|
+
* Six WebSocket sub-modules with content (12 fixtures). Additional sub-modules
|
|
24
24
|
* (`data-contract`, `tool-name-uniqueness`)
|
|
25
25
|
* are reserved for additive fixture expansion and not yet
|
|
26
26
|
* materialized — adding fixtures there is a kit minor version.
|
|
@@ -36,6 +36,43 @@
|
|
|
36
36
|
* frame to drive — so they do NOT belong in this behavioral fixture
|
|
37
37
|
* catalog.
|
|
38
38
|
*
|
|
39
|
+
* ## An MCP-binding driver EXISTS for `resources/read` — `../resource-read-conformance`
|
|
40
|
+
*
|
|
41
|
+
* This catalog used to declare the MCP-binding driver as missing. It is
|
|
42
|
+
* no longer missing. `../resource-read-conformance` ships a driver
|
|
43
|
+
* bound to the MCP **`resources/read`** method, with its own case
|
|
44
|
+
* shape, its own runner (`runResourceReadConformance`) and its own
|
|
45
|
+
* scenario-driver seam. It grades the typed-failure contract for a
|
|
46
|
+
* render locator (`ui://ggui/render/{sessionId}[/{blueprintKey}]`): the
|
|
47
|
+
* four failure classes on their canonical numbers, the constant
|
|
48
|
+
* `NOT_FOUND` body, the deny-equals-miss byte-identity obligation, and
|
|
49
|
+
* the invariant that any successful result declares a delivery channel.
|
|
50
|
+
*
|
|
51
|
+
* Its cases are NOT registered in the map below, and that is
|
|
52
|
+
* deliberate. Every entry here is driven by `runConformance()` over a
|
|
53
|
+
* live channel, so an MCP case landing in this catalog would be a
|
|
54
|
+
* permanent skip on every WebSocket run — a skip that can never become
|
|
55
|
+
* a pass on that transport, which is exactly the false gate this kit's
|
|
56
|
+
* exact skip-set pinning exists to prevent.
|
|
57
|
+
*
|
|
58
|
+
* ### Precisely what that driver does NOT close
|
|
59
|
+
*
|
|
60
|
+
* It binds ONE MCP method. `tools/call` has no driver, so both of these
|
|
61
|
+
* remain open and neither is addressed by it:
|
|
62
|
+
*
|
|
63
|
+
* - **`stream-delivery-roundtrip`** — see the next section. Needs
|
|
64
|
+
* `ggui_emit`.
|
|
65
|
+
* - **The `ggui_consume` retrieval half of the action loop** —
|
|
66
|
+
* `action-ack-sequence` proves the append half; draining the buffer
|
|
67
|
+
* is `ggui_consume`.
|
|
68
|
+
*
|
|
69
|
+
* `resources/read` and `tools/call` are different methods with
|
|
70
|
+
* different seams: the former is a stateless read of a URI the kit can
|
|
71
|
+
* construct, the latter is an invocation whose arguments and effects
|
|
72
|
+
* are the agent's vocabulary. A driver for one is not a driver for the
|
|
73
|
+
* other, and saying "the kit now has an MCP driver" without that
|
|
74
|
+
* qualifier would read as closing gaps it does not touch.
|
|
75
|
+
*
|
|
39
76
|
* ## What is NOT here — declared Path-A sequencing gap
|
|
40
77
|
*
|
|
41
78
|
* A `stream-delivery-roundtrip` fixture (an `emit-envelope`'d payload
|
|
@@ -52,9 +89,10 @@
|
|
|
52
89
|
* transport, while emission is server-side (the agent's `ggui_emit`
|
|
53
90
|
* MCP tool) — routing a host directive through the wire-frame slot
|
|
54
91
|
* would conflate the two vocabularies. Honest grading needs either a
|
|
55
|
-
* post-subscribe host-directive phase (a runner-mechanism change) or
|
|
56
|
-
*
|
|
57
|
-
*
|
|
92
|
+
* post-subscribe host-directive phase (a runner-mechanism change) or a
|
|
93
|
+
* driver bound to `tools/call`. The `resources/read` driver above is
|
|
94
|
+
* NOT that driver. Declared here rather than papered over with a
|
|
95
|
+
* fixture that fails conformant servers on sequencing alone.
|
|
58
96
|
*/
|
|
59
97
|
export { bootstrapProtocolFixtures } from './bootstrap-protocol/index.js';
|
|
60
98
|
export { consumeBufferFixtures } from './consume-buffer/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+FG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,gBAAgB,GAChB,cAAc,GACd,4BAA4B,GAC5B,0BAA0B,GAC1B,mBAAmB,GACnB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,QAAQ,EAAE,CAAC,CAOlF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,QAAQ,EAGwB,CAAC"}
|
package/dist/fixtures/index.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* ## Current coverage
|
|
22
22
|
*
|
|
23
|
-
* Six sub-modules with content (12 fixtures). Additional sub-modules
|
|
23
|
+
* Six WebSocket sub-modules with content (12 fixtures). Additional sub-modules
|
|
24
24
|
* (`data-contract`, `tool-name-uniqueness`)
|
|
25
25
|
* are reserved for additive fixture expansion and not yet
|
|
26
26
|
* materialized — adding fixtures there is a kit minor version.
|
|
@@ -36,6 +36,43 @@
|
|
|
36
36
|
* frame to drive — so they do NOT belong in this behavioral fixture
|
|
37
37
|
* catalog.
|
|
38
38
|
*
|
|
39
|
+
* ## An MCP-binding driver EXISTS for `resources/read` — `../resource-read-conformance`
|
|
40
|
+
*
|
|
41
|
+
* This catalog used to declare the MCP-binding driver as missing. It is
|
|
42
|
+
* no longer missing. `../resource-read-conformance` ships a driver
|
|
43
|
+
* bound to the MCP **`resources/read`** method, with its own case
|
|
44
|
+
* shape, its own runner (`runResourceReadConformance`) and its own
|
|
45
|
+
* scenario-driver seam. It grades the typed-failure contract for a
|
|
46
|
+
* render locator (`ui://ggui/render/{sessionId}[/{blueprintKey}]`): the
|
|
47
|
+
* four failure classes on their canonical numbers, the constant
|
|
48
|
+
* `NOT_FOUND` body, the deny-equals-miss byte-identity obligation, and
|
|
49
|
+
* the invariant that any successful result declares a delivery channel.
|
|
50
|
+
*
|
|
51
|
+
* Its cases are NOT registered in the map below, and that is
|
|
52
|
+
* deliberate. Every entry here is driven by `runConformance()` over a
|
|
53
|
+
* live channel, so an MCP case landing in this catalog would be a
|
|
54
|
+
* permanent skip on every WebSocket run — a skip that can never become
|
|
55
|
+
* a pass on that transport, which is exactly the false gate this kit's
|
|
56
|
+
* exact skip-set pinning exists to prevent.
|
|
57
|
+
*
|
|
58
|
+
* ### Precisely what that driver does NOT close
|
|
59
|
+
*
|
|
60
|
+
* It binds ONE MCP method. `tools/call` has no driver, so both of these
|
|
61
|
+
* remain open and neither is addressed by it:
|
|
62
|
+
*
|
|
63
|
+
* - **`stream-delivery-roundtrip`** — see the next section. Needs
|
|
64
|
+
* `ggui_emit`.
|
|
65
|
+
* - **The `ggui_consume` retrieval half of the action loop** —
|
|
66
|
+
* `action-ack-sequence` proves the append half; draining the buffer
|
|
67
|
+
* is `ggui_consume`.
|
|
68
|
+
*
|
|
69
|
+
* `resources/read` and `tools/call` are different methods with
|
|
70
|
+
* different seams: the former is a stateless read of a URI the kit can
|
|
71
|
+
* construct, the latter is an invocation whose arguments and effects
|
|
72
|
+
* are the agent's vocabulary. A driver for one is not a driver for the
|
|
73
|
+
* other, and saying "the kit now has an MCP driver" without that
|
|
74
|
+
* qualifier would read as closing gaps it does not touch.
|
|
75
|
+
*
|
|
39
76
|
* ## What is NOT here — declared Path-A sequencing gap
|
|
40
77
|
*
|
|
41
78
|
* A `stream-delivery-roundtrip` fixture (an `emit-envelope`'d payload
|
|
@@ -52,9 +89,10 @@
|
|
|
52
89
|
* transport, while emission is server-side (the agent's `ggui_emit`
|
|
53
90
|
* MCP tool) — routing a host directive through the wire-frame slot
|
|
54
91
|
* would conflate the two vocabularies. Honest grading needs either a
|
|
55
|
-
* post-subscribe host-directive phase (a runner-mechanism change) or
|
|
56
|
-
*
|
|
57
|
-
*
|
|
92
|
+
* post-subscribe host-directive phase (a runner-mechanism change) or a
|
|
93
|
+
* driver bound to `tools/call`. The `resources/read` driver above is
|
|
94
|
+
* NOT that driver. Declared here rather than papered over with a
|
|
95
|
+
* fixture that fails conformant servers on sequencing alone.
|
|
58
96
|
*/
|
|
59
97
|
export { bootstrapProtocolFixtures } from './bootstrap-protocol/index.js';
|
|
60
98
|
export { consumeBufferFixtures } from './consume-buffer/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/reserved-channel-authority/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/reserved-channel-authority/index.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qEAAqE;AACrE,eAAO,MAAM,gCAAgC,EAAE,SAAS,QAAQ,EAE/D,CAAC"}
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
* are Server→Client only). Agent emission enters through the
|
|
22
22
|
* `ggui_emit` MCP tool, so both the violation and the rejection that
|
|
23
23
|
* grades it are observable only on the MCP binding. That fixture
|
|
24
|
-
* belongs to a future
|
|
25
|
-
*
|
|
24
|
+
* belongs to a future driver bound to `tools/call` — the kit's
|
|
25
|
+
* `resources/read` driver (`../../resource-read-conformance`) binds a
|
|
26
|
+
* different method and does not reach `ggui_emit`. The gap is declared
|
|
27
|
+
* here rather than faked with a frame the wire cannot carry.
|
|
26
28
|
*/
|
|
27
29
|
import propsUpdateRoundtrip from './props-update-roundtrip.json' with { type: 'json' };
|
|
28
30
|
/** All fixtures asserting reserved-channel authority (SPEC §4.4). */
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export { gadgetRegistrationCases, runRegistrationConformance, } from './registra
|
|
|
20
20
|
export type { GadgetGateRejectCode, GateOutcome, RegistrationConformanceCase, RegistrationConformanceMismatch, RegistrationConformanceResult, } from './registration-conformance/index.js';
|
|
21
21
|
export { gadgetResolutionCases, runResolutionConformance, } from './resolution-conformance/index.js';
|
|
22
22
|
export type { GadgetUrlEntry, ResolvedGadgetUrls, ResolutionConformanceCase, ResolutionConformanceMismatch, ResolutionConformanceResult, } from './resolution-conformance/index.js';
|
|
23
|
+
export { declaresDeliveryChannel, renderLocatorUri, resourceReadCases, runResourceReadConformance, GGUI_RENDER_RESOURCE_URI, } from './resource-read-conformance/index.js';
|
|
24
|
+
export type { DurableSubstrateWiring, JsonRpcErrorFrame, PreparedResourceReadScenario, ResourceReadCaller, ResourceReadConformanceCase, ResourceReadConformanceFailure, ResourceReadConformanceResult, ResourceReadConformanceSkip, ResourceReadErrorCodeDecl, ResourceReadExpectation, ResourceReadKey, ResourceReadLocator, ResourceReadOutcome, ResourceReadProbe, ResourceReadRenderMeta, ResourceReadScenario, ResourceReadScenarioDriver, ResourceReadSeed, ResourceReadServerShape, RunResourceReadConformanceOptions, } from './resource-read-conformance/index.js';
|
|
23
25
|
export { loadFixture, listFixtures, loadAllFixtures } from './loader.js';
|
|
24
26
|
export { runConformance } from './run-conformance.js';
|
|
25
27
|
export type { RunConformanceConfig, ConformanceResult, ConformanceFailure, SkippedFixture, ConformanceReporter, InputEnvelopeDispatch, HostContextObservedInputEnvelope, } from './run-conformance.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,YAAY,EAEV,eAAe,EACf,wBAAwB,EACxB,sBAAsB,EACtB,UAAU,EAEV,QAAQ,EACR,qBAAqB,EAErB,SAAS,EACT,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,EAChC,gBAAgB,EAEhB,YAAY,EAEZ,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,eAAe,EAEf,aAAa,EACb,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,eAAe,EAEf,SAAS,IAAI,aAAa,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,iBAAiB,EAEjB,YAAY,IAAI,gBAAgB,GACjC,MAAM,uBAAuB,CAAC;AAK/B,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,mBAAmB,EACnB,gCAAgC,EAChC,8BAA8B,EAC9B,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AASxD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,+BAA+B,CAAC;AAKvC,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,2BAA2B,EAC3B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,qCAAqC,CAAC;AAK7C,OAAO,EACL,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,yBAAyB,EACzB,6BAA6B,EAC7B,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,YAAY,EAEV,eAAe,EACf,wBAAwB,EACxB,sBAAsB,EACtB,UAAU,EAEV,QAAQ,EACR,qBAAqB,EAErB,SAAS,EACT,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,EAChC,gBAAgB,EAEhB,YAAY,EAEZ,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,eAAe,EAEf,aAAa,EACb,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,eAAe,EAEf,SAAS,IAAI,aAAa,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,iBAAiB,EAEjB,YAAY,IAAI,gBAAgB,GACjC,MAAM,uBAAuB,CAAC;AAK/B,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,mBAAmB,EACnB,gCAAgC,EAChC,8BAA8B,EAC9B,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AASxD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,+BAA+B,CAAC;AAKvC,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,2BAA2B,EAC3B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,qCAAqC,CAAC;AAK7C,OAAO,EACL,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,yBAAyB,EACzB,6BAA6B,EAC7B,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAQ3C,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,2BAA2B,EAC3B,8BAA8B,EAC9B,6BAA6B,EAC7B,2BAA2B,EAC3B,yBAAyB,EACzB,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,uBAAuB,EACvB,iCAAiC,GAClC,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EAInB,qBAAqB,EACrB,gCAAgC,GACjC,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,13 @@ export { gadgetRegistrationCases, runRegistrationConformance, } from './registra
|
|
|
30
30
|
// compute for a gadget descriptor's transport fields (`bundleHost`
|
|
31
31
|
// precedence, default host, loopback scheme).
|
|
32
32
|
export { gadgetResolutionCases, runResolutionConformance, } from './resolution-conformance/index.js';
|
|
33
|
+
// Resource-read conformance — the kit's first MCP-binding driver, and
|
|
34
|
+
// it binds `resources/read` ONLY (`tools/call` has none). A read of a
|
|
35
|
+
// render locator has exactly two exits: a result whose contents
|
|
36
|
+
// declare a delivery channel, or one typed JSON-RPC error.
|
|
37
|
+
// Unlike the three catalogs above this one drives a live server, so
|
|
38
|
+
// the caller supplies a scenario driver rather than a pure function.
|
|
39
|
+
export { declaresDeliveryChannel, renderLocatorUri, resourceReadCases, runResourceReadConformance, GGUI_RENDER_RESOURCE_URI, } from './resource-read-conformance/index.js';
|
|
33
40
|
// Runtime loader — look up a fixture by name from the inlined catalog.
|
|
34
41
|
export { loadFixture, listFixtures, loadAllFixtures } from './loader.js';
|
|
35
42
|
// Runner — drive the catalog against a live implementation.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match-behavior.d.ts","sourceRoot":"","sources":["../src/match-behavior.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"match-behavior.d.ts","sourceRoot":"","sources":["../src/match-behavior.ts"],"names":[],"mappings":"AA+FA,OAAO,KAAK,EAIV,gBAAgB,EAIjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,gBAAgB,CAAC,MAAM,CAAC,EAC3D,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,CAAC,GACN,QAAQ,IAAI,OAAO,CAAC,gBAAgB,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAE7D;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,SAAS,aAAa,EAAE,GAC/B,WAAW,CAkDb;AAgRD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAgBzD"}
|
package/dist/match-behavior.js
CHANGED
|
@@ -84,8 +84,10 @@
|
|
|
84
84
|
* `action-ack` proves the append half of the consume-buffer contract.
|
|
85
85
|
* The retrieval half — the agent draining the buffer via
|
|
86
86
|
* `ggui_consume({sessionId})` — is an MCP tool call a WS-only runner
|
|
87
|
-
* cannot drive. Grading it needs
|
|
88
|
-
*
|
|
87
|
+
* cannot drive. Grading it needs a driver bound to `tools/call`. The
|
|
88
|
+
* kit's `resources/read` driver (`../resource-read-conformance`) does
|
|
89
|
+
* NOT reach it: different method, different seam. That gap is declared
|
|
90
|
+
* here rather than papered over with a weaker assertion.
|
|
89
91
|
*/
|
|
90
92
|
import { PROTOCOL_SCHEMA_VERSION } from '@ggui-ai/protocol';
|
|
91
93
|
import { isRecord } from '@ggui-ai/protocol';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "all-ephemeral-substrate-fuses-like-none",
|
|
3
|
+
"description": "A server binding the WHOLE substrate out of stores that declare ephemeral durability keeps no durable record — a restart erases everything — so it MUST fuse exactly like a substrate-less one (#457). Binding is not durability: deriving the NOT_SUPPORTED/NOT_FOUND split from mere binding lets an operator with three in-memory stores promise restorability the deployment cannot deliver, and the promise breaks silently, on the first restart, for every locator at once.",
|
|
4
|
+
"server": { "durableSubstrate": "all-ephemeral", "liveChannel": true },
|
|
5
|
+
"caller": "other",
|
|
6
|
+
"seeds": [{ "kind": "committed-render", "session": "6b2f8d13-4a5c-4e97-8f21-9d0c3b7a5e14" }],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "refused",
|
|
10
|
+
"locator": { "kind": "render", "session": "6b2f8d13-4a5c-4e97-8f21-9d0c3b7a5e14" },
|
|
11
|
+
"expect": {
|
|
12
|
+
"kind": "typed-error",
|
|
13
|
+
"jsonRpcCode": -32006,
|
|
14
|
+
"dataCode": "NOT_SUPPORTED"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"as": "miss",
|
|
19
|
+
"locator": { "kind": "render", "session": "0c9e4f72-8b1d-4a63-95e8-2f6a7d3c1b58" },
|
|
20
|
+
"expect": {
|
|
21
|
+
"kind": "typed-error",
|
|
22
|
+
"jsonRpcCode": -32006,
|
|
23
|
+
"dataCode": "NOT_SUPPORTED"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"indistinguishable": ["refused", "miss"],
|
|
28
|
+
"disclosesNothing": ["6b2f8d13-4a5c-4e97-8f21-9d0c3b7a5e14"]
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "evicted-row-remints-from-the-durable-record",
|
|
3
|
+
"description": "The success half on the path the durable substrate exists for. The render row is gone, but the record naming what it was survives, the blueprint it names is stored, and the component body behind that blueprint is still there — so the read restores it and hands back real mount material. Without this case the catalog would grade a server that answers every evicted locator with a typed error as fully conformant, which is the direction a broken re-mint fails in.",
|
|
4
|
+
"server": { "durableSubstrate": "all", "liveChannel": true },
|
|
5
|
+
"caller": "owner",
|
|
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": "reminted",
|
|
18
|
+
"locator": {
|
|
19
|
+
"kind": "render",
|
|
20
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
21
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
22
|
+
},
|
|
23
|
+
"expect": { "kind": "live-mount" }
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "half-wired-blueprints-only-substrate-fuses-like-none",
|
|
3
|
+
"description": "The other half-wired shape: blueprint and component storage bound, no record of what any render was. Without the record there is nothing to look a blueprint up BY, so this server restores nothing either and owes the same fused answer as one wired for nothing at all.",
|
|
4
|
+
"server": { "durableSubstrate": "blueprints-only", "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
|
+
}
|
package/dist/resource-read-conformance/cases/half-wired-identity-only-substrate-fuses-like-none.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "half-wired-identity-only-substrate-fuses-like-none",
|
|
3
|
+
"description": "A server holding the record store and nothing else can restore no render, so it is as substrate-less as one holding nothing. This is where the fusion is easiest to get wrong: the re-mint is consulted only when the row is absent, so a verdict derived from a partial substrate check answers NOT_FOUND for a row that exists and NOT_SUPPORTED for one that never did — the existence oracle, rebuilt out of a provisioning mistake.",
|
|
4
|
+
"server": { "durableSubstrate": "identity-only", "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,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "live-row-read-returns-mount-material",
|
|
3
|
+
"description": "The success half of the invariant, on the simplest path: the render is still live and the caller owns it. The result's contents must declare a delivery channel — a component URL, a live channel carrying BOTH an endpoint and a token, or a server-emitted system card. Graded on the projected render meta, never on markup: what the shell looks like is a server's own presentation concern. Note the blueprintKey segment names nothing this server has ever stored, and the read succeeds anyway — that is deliberate, and it makes a second obligation graded here: when the row is present and readable, the ROW is what gets mounted and the supplied key is not consulted. A server that validated the key against its own records and refused the mismatch would fail this case, correctly, because a resume locator's key exists to resolve a render that is GONE.",
|
|
4
|
+
"server": { "durableSubstrate": "all", "liveChannel": true },
|
|
5
|
+
"caller": "owner",
|
|
6
|
+
"seeds": [{ "kind": "committed-render", "session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70" }],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "live",
|
|
10
|
+
"locator": {
|
|
11
|
+
"kind": "render",
|
|
12
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
13
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
14
|
+
},
|
|
15
|
+
"expect": { "kind": "live-mount" }
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/dist/resource-read-conformance/cases/malformed-locator-stays-outside-the-typed-set.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "malformed-locator-stays-outside-the-typed-set",
|
|
3
|
+
"description": "A URI with an empty session segment names no render locator, so it is not a read of one and the four classifications do not apply. The graded law is exactly one negative: the error carries NO resource-read code on error.data.code. The NUMBER is not graded, not even negatively — MCP assigns the resource-missing number to a resources/read of a URI the server does not serve, so a framework mapping every unrecognized URI onto it is correct and must not fail here. The classification alone keeps the two apart: a genuine miss carries NOT_FOUND and the constant message, a malformed URI carries no classification at all.",
|
|
4
|
+
"server": { "durableSubstrate": "all", "liveChannel": true },
|
|
5
|
+
"caller": "owner",
|
|
6
|
+
"seeds": [],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "empty-session",
|
|
10
|
+
"locator": { "kind": "raw", "uri": "ui://ggui/render/" },
|
|
11
|
+
"expect": { "kind": "outside-typed-set" }
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"as": "empty-session-with-key",
|
|
15
|
+
"locator": { "kind": "raw", "uri": "ui://ggui/render//fedcba9876543210" },
|
|
16
|
+
"expect": { "kind": "outside-typed-set" }
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "read-miss-answers-not-found",
|
|
3
|
+
"description": "A read of a locator that never existed, on a server that keeps durable records and could have restored one, answers NOT_FOUND on -32002 with a body carrying no detail. -32002 is the number a missing resource already rides on, and for a locator keyed by session id a missing session and a missing resource are one condition. The absent detail is what keeps this answer identical to a refusal.",
|
|
4
|
+
"server": { "durableSubstrate": "all", "liveChannel": true },
|
|
5
|
+
"caller": "owner",
|
|
6
|
+
"seeds": [],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "miss",
|
|
10
|
+
"locator": {
|
|
11
|
+
"kind": "render",
|
|
12
|
+
"session": "8d5b0e41-2c96-4a7f-b3d8-1e07f9a2c645",
|
|
13
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
14
|
+
},
|
|
15
|
+
"expect": {
|
|
16
|
+
"kind": "typed-error",
|
|
17
|
+
"jsonRpcCode": -32002,
|
|
18
|
+
"dataCode": "NOT_FOUND",
|
|
19
|
+
"detailAbsent": true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "read-on-a-substrate-less-server-answers-not-supported",
|
|
3
|
+
"description": "A server that keeps no durable record cannot restore an evicted render for anybody, so a read it cannot serve answers NOT_SUPPORTED on -32006. This is a property of the deployment, not of the locator — which is why the catalog does not grade WHEN the answer is produced. A substrate-less server may answer immediately, before any per-locator work.",
|
|
4
|
+
"server": { "durableSubstrate": "none", "liveChannel": true },
|
|
5
|
+
"caller": "owner",
|
|
6
|
+
"seeds": [],
|
|
7
|
+
"reads": [
|
|
8
|
+
{
|
|
9
|
+
"as": "evicted",
|
|
10
|
+
"locator": {
|
|
11
|
+
"kind": "render",
|
|
12
|
+
"session": "8d5b0e41-2c96-4a7f-b3d8-1e07f9a2c645",
|
|
13
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
14
|
+
},
|
|
15
|
+
"expect": {
|
|
16
|
+
"kind": "typed-error",
|
|
17
|
+
"jsonRpcCode": -32006,
|
|
18
|
+
"dataCode": "NOT_SUPPORTED"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "read-record-with-purged-blueprint-answers-blueprint-unresolvable",
|
|
3
|
+
"description": "A durable record survives its render and names a blueprint, but the blueprint is gone. The read answers BLUEPRINT_UNRESOLVABLE on -32006 — not an internal error. Nothing malfunctioned: the record kept its promise and the thing it pointed at was reaped. A host reading -32006 knows a retry of this locator cannot succeed, which -32603 would have told it the opposite of.",
|
|
4
|
+
"server": { "durableSubstrate": "all", "liveChannel": true },
|
|
5
|
+
"caller": "owner",
|
|
6
|
+
"seeds": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "identity-record",
|
|
9
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
10
|
+
"key": "fedcba9876543210",
|
|
11
|
+
"blueprint": "named"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"reads": [
|
|
15
|
+
{
|
|
16
|
+
"as": "evicted",
|
|
17
|
+
"locator": {
|
|
18
|
+
"kind": "render",
|
|
19
|
+
"session": "3f1a9c22-7b4e-4d18-9a05-6c2e8b1d4f70",
|
|
20
|
+
"key": { "kind": "literal", "value": "fedcba9876543210" }
|
|
21
|
+
},
|
|
22
|
+
"expect": {
|
|
23
|
+
"kind": "typed-error",
|
|
24
|
+
"jsonRpcCode": -32006,
|
|
25
|
+
"dataCode": "BLUEPRINT_UNRESOLVABLE"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|