@ggui-ai/protocol-conformance 0.6.3 → 0.8.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.
Files changed (65) hide show
  1. package/README.md +59 -18
  2. package/dist/binding-conformance/cases/bind-blueprint-no-contract-none.json +6 -0
  3. package/dist/binding-conformance/cases/bind-contract-without-tool-names-none.json +18 -0
  4. package/dist/binding-conformance/cases/bind-declared-gadget.json +13 -0
  5. package/dist/binding-conformance/cases/bind-declared-wins-over-contract.json +23 -0
  6. package/dist/binding-conformance/cases/bind-derived-caps-at-sixteen.json +54 -0
  7. package/dist/binding-conformance/cases/bind-derived-props-and-stream.json +36 -0
  8. package/dist/binding-conformance/cases/bind-derived-skips-invalid-names.json +40 -0
  9. package/dist/binding-conformance/cases/bind-derived-union-dedupes.json +38 -0
  10. package/dist/binding-conformance/cases/bind-gadget-undeclared-none.json +6 -0
  11. package/dist/binding-conformance/cases/bind-reject-charset.json +9 -0
  12. package/dist/binding-conformance/cases/bind-reject-duplicate-pair.json +12 -0
  13. package/dist/binding-conformance/cases/bind-reject-empty-list.json +9 -0
  14. package/dist/binding-conformance/cases/bind-reject-overlong-name.json +13 -0
  15. package/dist/binding-conformance/cases/bind-reject-server-charset.json +9 -0
  16. package/dist/binding-conformance/cases/bind-reject-too-many-entries.json +27 -0
  17. package/dist/binding-conformance/cases/filter-case-sensitive-server.json +7 -0
  18. package/dist/binding-conformance/cases/filter-case-sensitive-tool.json +7 -0
  19. package/dist/binding-conformance/cases/filter-none-passes-bound.json +7 -0
  20. package/dist/binding-conformance/cases/filter-none-passes-unbound.json +6 -0
  21. package/dist/binding-conformance/cases/filter-pair-bare-never-matches.json +7 -0
  22. package/dist/binding-conformance/cases/filter-pair-exact.json +10 -0
  23. package/dist/binding-conformance/cases/filter-pair-not-cross-entry.json +10 -0
  24. package/dist/binding-conformance/cases/filter-server-excludes-bare.json +7 -0
  25. package/dist/binding-conformance/cases/filter-server-match.json +7 -0
  26. package/dist/binding-conformance/cases/filter-tool-cross-server.json +7 -0
  27. package/dist/binding-conformance/cases/filter-tool-excludes-unbound.json +6 -0
  28. package/dist/binding-conformance/cases/filter-tool-matches-bare-entry.json +7 -0
  29. package/dist/binding-conformance/cases/filter-tool-no-match.json +7 -0
  30. package/dist/binding-conformance/index.d.ts +214 -0
  31. package/dist/binding-conformance/index.d.ts.map +1 -0
  32. package/dist/binding-conformance/index.js +153 -0
  33. package/dist/fixtures/consume-buffer/index.d.ts.map +1 -1
  34. package/dist/fixtures/consume-buffer/index.js +4 -1
  35. package/dist/fixtures/index.d.ts +42 -4
  36. package/dist/fixtures/index.d.ts.map +1 -1
  37. package/dist/fixtures/index.js +42 -4
  38. package/dist/fixtures/reserved-channel-authority/index.d.ts.map +1 -1
  39. package/dist/fixtures/reserved-channel-authority/index.js +4 -2
  40. package/dist/index.d.ts +4 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +12 -0
  43. package/dist/match-behavior.d.ts.map +1 -1
  44. package/dist/match-behavior.js +4 -2
  45. package/dist/resolution-conformance/cases/resolve-bundle-host-computed.json +3 -3
  46. package/dist/resolution-conformance/cases/resolve-default-host.json +2 -2
  47. package/dist/resolution-conformance/cases/resolve-loopback-host-http-scheme.json +2 -2
  48. package/dist/resource-read-conformance/cases/all-ephemeral-substrate-fuses-like-none.json +29 -0
  49. package/dist/resource-read-conformance/cases/channel-less-read-mounts-inline.json +24 -0
  50. package/dist/resource-read-conformance/cases/evicted-row-remints-from-the-durable-record.json +26 -0
  51. package/dist/resource-read-conformance/cases/half-wired-blueprints-only-substrate-fuses-like-none.json +29 -0
  52. package/dist/resource-read-conformance/cases/half-wired-identity-only-substrate-fuses-like-none.json +29 -0
  53. package/dist/resource-read-conformance/cases/live-row-read-returns-mount-material.json +18 -0
  54. package/dist/resource-read-conformance/cases/malformed-locator-stays-outside-the-typed-set.json +19 -0
  55. package/dist/resource-read-conformance/cases/read-miss-answers-not-found.json +23 -0
  56. package/dist/resource-read-conformance/cases/read-on-a-substrate-less-server-answers-not-supported.json +22 -0
  57. package/dist/resource-read-conformance/cases/read-record-with-purged-blueprint-answers-blueprint-unresolvable.json +29 -0
  58. package/dist/resource-read-conformance/cases/read-refusal-is-indistinguishable-from-a-miss.json +47 -0
  59. package/dist/resource-read-conformance/cases/read-without-a-delivery-channel-answers-not-mountable.json +33 -0
  60. package/dist/resource-read-conformance/cases/registry-match-fuses-on-not-mountable.json +40 -0
  61. package/dist/resource-read-conformance/cases/substrate-less-fusion-of-refusal-and-miss.json +29 -0
  62. package/dist/resource-read-conformance/index.d.ts +383 -0
  63. package/dist/resource-read-conformance/index.d.ts.map +1 -0
  64. package/dist/resource-read-conformance/index.js +793 -0
  65. package/package.json +13 -3
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Binding-conformance catalog — MCP tool-binding resolution + search
3
+ * filter semantics (SPEC §7.7.4 — tool bindings & discovery).
4
+ *
5
+ * ## Why this is a pure-function catalog
6
+ *
7
+ * Two pure obligations connect a registry artifact to the MCP tools
8
+ * it renders:
9
+ *
10
+ * 1. RESOLUTION — given a manifest, which binding set is
11
+ * effective? A declared `mcpTools` list wins entirely; a
12
+ * blueprint without one derives bare tool names from its
13
+ * contract's lineage fields
14
+ * (`propsSpec.properties[*].sourceTool`,
15
+ * `streamSpec[*].source.tool`); a schema-invalid list rejects
16
+ * with the manifest-validation code. Bindings are search
17
+ * metadata only — they never enter contract canonicalization
18
+ * or any cache identity.
19
+ * 2. FILTERING — given an artifact's stored binding set and a
20
+ * search query's `tool` / `server` params, does the artifact
21
+ * match? Both dimensions are case-sensitive exact and must land
22
+ * on a single entry; a bare entry never satisfies a server
23
+ * dimension; no dimensions given passes everything.
24
+ *
25
+ * Both are deterministic functions — no render, transport, or wire
26
+ * frame — so they get the same treatment as the registry gate
27
+ * (`../registration-conformance`) and bundle-URL resolution
28
+ * (`../resolution-conformance`): catalogs of JSON cases graded
29
+ * against caller-supplied functions.
30
+ *
31
+ * ## Polyglot, decoupled
32
+ *
33
+ * Each case ships as raw JSON under `./cases/`.
34
+ * {@link runBindingResolutionCases} / {@link runBindingFilterCases}
35
+ * take the implementation as a callback — the kit never imports a
36
+ * concrete resolver or search filter, so adopters drive their OWN.
37
+ * The reference binding (`./binding-conformance.test.ts`) restates
38
+ * faithful minimal implementations in-test.
39
+ */
40
+ import type { DataContract } from "@ggui-ai/protocol";
41
+ /**
42
+ * One MCP tool binding as authored on a manifest / stored on search
43
+ * metadata. `server` carries `serverInfo.name` semantics; a bare
44
+ * entry (no `server`) is server-agnostic.
45
+ */
46
+ export interface McpToolBindingDecl {
47
+ readonly server?: string;
48
+ readonly tool: string;
49
+ }
50
+ /**
51
+ * The binding-relevant subset of an artifact manifest the resolver
52
+ * reads. Authored kit-local — decoupled from any shipping manifest
53
+ * schema on purpose; `contract` reuses the protocol's
54
+ * {@link DataContract} type the way `../registration-conformance`
55
+ * does.
56
+ */
57
+ export interface BindingManifestEntry {
58
+ /** Which manifest kind the entry models. Only blueprints derive. */
59
+ readonly kind: "gadget" | "blueprint";
60
+ /** The `mcpTools` list as authored — possibly invalid. */
61
+ readonly mcpTools?: readonly McpToolBindingDecl[];
62
+ /** The blueprint's contract, when it has one. */
63
+ readonly contract?: DataContract;
64
+ }
65
+ /**
66
+ * The code a schema-invalid `mcpTools` list classifies into.
67
+ * Extensibly-closed `(string & {})` tail so a later protocol
68
+ * revision's code rides through without a kit bump — same
69
+ * discipline as `GadgetGateRejectCode` in
70
+ * `../registration-conformance`.
71
+ */
72
+ export type BindingRejectCode = "manifest_invalid" | (string & {});
73
+ /**
74
+ * What resolving one manifest's bindings produces: accept with a
75
+ * `source` + `bindings` pair (declared or derived — present together
76
+ * or absent together), accept with NEITHER (the artifact has no
77
+ * bindings and is not findable by tool), or reject with the
78
+ * manifest-validation code.
79
+ */
80
+ export type BindingResolutionOutcome = {
81
+ readonly outcome: "accept";
82
+ readonly source?: "declared" | "derived";
83
+ readonly bindings?: readonly McpToolBindingDecl[];
84
+ } | {
85
+ readonly outcome: "reject";
86
+ readonly code: BindingRejectCode;
87
+ };
88
+ /**
89
+ * A search query's tool/server params as one filter input. Both
90
+ * optional — an absent dimension does not constrain. Matching is
91
+ * case-sensitive exact on both dimensions.
92
+ */
93
+ export interface McpToolFilterDecl {
94
+ readonly tool?: string;
95
+ readonly server?: string;
96
+ }
97
+ /**
98
+ * One binding-resolution case. Authored as JSON under `./cases/`,
99
+ * consumed via {@link bindingResolutionCases}, graded by
100
+ * {@link runBindingResolutionCases}.
101
+ *
102
+ * The shape IS the public API — additive changes only.
103
+ */
104
+ export interface BindingResolutionCase {
105
+ /** Unique case name. MUST match the JSON filename without `.json`. */
106
+ readonly name: string;
107
+ /** Which binding obligation this case proves. */
108
+ readonly description: string;
109
+ /** The manifest subset fed to the resolver. */
110
+ readonly entry: BindingManifestEntry;
111
+ /**
112
+ * The outcome a spec-conformant resolver MUST produce. Binding
113
+ * lists are compared order-sensitively: declared bindings carry
114
+ * authored order; derived bindings carry first-appearance order
115
+ * (props in declaration order, then stream channels), duplicates
116
+ * collapsed to the first occurrence.
117
+ */
118
+ readonly expect: BindingResolutionOutcome;
119
+ }
120
+ /**
121
+ * One filter-semantics case. Authored as JSON under `./cases/`,
122
+ * consumed via {@link bindingFilterCases}, graded by
123
+ * {@link runBindingFilterCases}.
124
+ *
125
+ * The shape IS the public API — additive changes only.
126
+ */
127
+ export interface BindingFilterCase {
128
+ /** Unique case name. MUST match the JSON filename without `.json`. */
129
+ readonly name: string;
130
+ /** Which filter obligation this case proves. */
131
+ readonly description: string;
132
+ /** The artifact's stored binding set — absent models an unbound artifact. */
133
+ readonly bindings?: readonly McpToolBindingDecl[];
134
+ /** The query's tool/server params — `{}` models neither given. */
135
+ readonly filters: McpToolFilterDecl;
136
+ /** Whether a spec-conformant filter matches the artifact. */
137
+ readonly expect: boolean;
138
+ }
139
+ /**
140
+ * Every binding-resolution case the kit ships, in deterministic
141
+ * order — declared first, then derived, then the no-binding edges,
142
+ * then the schema rejects.
143
+ */
144
+ export declare const bindingResolutionCases: readonly BindingResolutionCase[];
145
+ /**
146
+ * Every filter-semantics case the kit ships, in deterministic
147
+ * order — tool-dimension, server-dimension, pair, no-filter
148
+ * passthrough, then case-sensitivity.
149
+ */
150
+ export declare const bindingFilterCases: readonly BindingFilterCase[];
151
+ /** One resolution case the resolver under test graded wrong. */
152
+ export interface BindingResolutionMismatch {
153
+ readonly name: string;
154
+ /** The outcome the catalog says a conformant resolver MUST produce. */
155
+ readonly expected: BindingResolutionOutcome;
156
+ /** The outcome the resolver under test actually produced. */
157
+ readonly actual: BindingResolutionOutcome;
158
+ }
159
+ /** Outcome of grading a resolver against the resolution catalog. */
160
+ export interface BindingResolutionResult {
161
+ /** Names of cases the resolver graded correctly. */
162
+ readonly passed: readonly string[];
163
+ /** Cases the resolver graded wrong — empty iff fully conformant. */
164
+ readonly failed: readonly BindingResolutionMismatch[];
165
+ }
166
+ /** One filter case the predicate under test graded wrong. */
167
+ export interface BindingFilterMismatch {
168
+ readonly name: string;
169
+ /** Whether the catalog says a conformant filter matches. */
170
+ readonly expected: boolean;
171
+ /** What the predicate under test actually returned. */
172
+ readonly actual: boolean;
173
+ }
174
+ /** Outcome of grading a filter predicate against the filter catalog. */
175
+ export interface BindingFilterResult {
176
+ /** Names of cases the predicate graded correctly. */
177
+ readonly passed: readonly string[];
178
+ /** Cases the predicate graded wrong — empty iff fully conformant. */
179
+ readonly failed: readonly BindingFilterMismatch[];
180
+ }
181
+ /**
182
+ * Grade a binding resolver against the resolution catalog.
183
+ *
184
+ * `resolve` MUST be a pure computation of `(entry) →
185
+ * BindingResolutionOutcome` — schema validation of a declared list
186
+ * plus declared-wins/derivation precedence, composed however the
187
+ * implementation likes. The kit deliberately does NOT import a
188
+ * concrete resolver — adopters pass their own (the reference
189
+ * binding uses a faithful in-test implementation; see
190
+ * `./binding-conformance.test.ts`). A conformant resolver produces
191
+ * an empty `failed` array.
192
+ *
193
+ * `resolve` is invoked exactly once per case, in
194
+ * {@link bindingResolutionCases} order; it MUST be pure and MUST
195
+ * NOT throw (a throwing resolver is itself non-conformant — wrap it
196
+ * so a classified rejection becomes a returned outcome).
197
+ */
198
+ export declare function runBindingResolutionCases(resolve: (entry: BindingManifestEntry) => BindingResolutionOutcome): BindingResolutionResult;
199
+ /**
200
+ * Grade a search filter predicate against the filter catalog.
201
+ *
202
+ * `matches` MUST be a pure computation of `(bindings, filters) →
203
+ * boolean` — the same predicate every storage implementation shares
204
+ * so `tool=` / `server=` behave identically everywhere. The kit
205
+ * deliberately does NOT import a concrete predicate — adopters pass
206
+ * their own. A conformant predicate produces an empty `failed`
207
+ * array.
208
+ *
209
+ * `matches` is invoked exactly once per case, in
210
+ * {@link bindingFilterCases} order; it MUST be pure and MUST NOT
211
+ * throw.
212
+ */
213
+ export declare function runBindingFilterCases(matches: (bindings: readonly McpToolBindingDecl[] | undefined, filters: McpToolFilterDecl) => boolean): BindingFilterResult;
214
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/binding-conformance/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,153 @@
1
+ import bindBlueprintNoContractNone from "./cases/bind-blueprint-no-contract-none.json" with { type: "json" };
2
+ import bindContractWithoutToolNamesNone from "./cases/bind-contract-without-tool-names-none.json" with { type: "json" };
3
+ import bindDeclaredGadget from "./cases/bind-declared-gadget.json" with { type: "json" };
4
+ import bindDeclaredWinsOverContract from "./cases/bind-declared-wins-over-contract.json" with { type: "json" };
5
+ import bindDerivedCapsAtSixteen from "./cases/bind-derived-caps-at-sixteen.json" with { type: "json" };
6
+ import bindDerivedPropsAndStream from "./cases/bind-derived-props-and-stream.json" with { type: "json" };
7
+ import bindDerivedSkipsInvalidNames from "./cases/bind-derived-skips-invalid-names.json" with { type: "json" };
8
+ import bindDerivedUnionDedupes from "./cases/bind-derived-union-dedupes.json" with { type: "json" };
9
+ import bindGadgetUndeclaredNone from "./cases/bind-gadget-undeclared-none.json" with { type: "json" };
10
+ import bindRejectCharset from "./cases/bind-reject-charset.json" with { type: "json" };
11
+ import bindRejectDuplicatePair from "./cases/bind-reject-duplicate-pair.json" with { type: "json" };
12
+ import bindRejectEmptyList from "./cases/bind-reject-empty-list.json" with { type: "json" };
13
+ import bindRejectOverlongName from "./cases/bind-reject-overlong-name.json" with { type: "json" };
14
+ import bindRejectServerCharset from "./cases/bind-reject-server-charset.json" with { type: "json" };
15
+ import bindRejectTooManyEntries from "./cases/bind-reject-too-many-entries.json" with { type: "json" };
16
+ import filterCaseSensitiveServer from "./cases/filter-case-sensitive-server.json" with { type: "json" };
17
+ import filterCaseSensitiveTool from "./cases/filter-case-sensitive-tool.json" with { type: "json" };
18
+ import filterNonePassesBound from "./cases/filter-none-passes-bound.json" with { type: "json" };
19
+ import filterNonePassesUnbound from "./cases/filter-none-passes-unbound.json" with { type: "json" };
20
+ import filterPairBareNeverMatches from "./cases/filter-pair-bare-never-matches.json" with { type: "json" };
21
+ import filterPairExact from "./cases/filter-pair-exact.json" with { type: "json" };
22
+ import filterPairNotCrossEntry from "./cases/filter-pair-not-cross-entry.json" with { type: "json" };
23
+ import filterServerExcludesBare from "./cases/filter-server-excludes-bare.json" with { type: "json" };
24
+ import filterServerMatch from "./cases/filter-server-match.json" with { type: "json" };
25
+ import filterToolCrossServer from "./cases/filter-tool-cross-server.json" with { type: "json" };
26
+ import filterToolExcludesUnbound from "./cases/filter-tool-excludes-unbound.json" with { type: "json" };
27
+ import filterToolMatchesBareEntry from "./cases/filter-tool-matches-bare-entry.json" with { type: "json" };
28
+ import filterToolNoMatch from "./cases/filter-tool-no-match.json" with { type: "json" };
29
+ /**
30
+ * Every binding-resolution case the kit ships, in deterministic
31
+ * order — declared first, then derived, then the no-binding edges,
32
+ * then the schema rejects.
33
+ */
34
+ export const bindingResolutionCases = [
35
+ bindDeclaredGadget,
36
+ bindDeclaredWinsOverContract,
37
+ bindDerivedPropsAndStream,
38
+ bindDerivedUnionDedupes,
39
+ bindDerivedSkipsInvalidNames,
40
+ bindDerivedCapsAtSixteen,
41
+ bindBlueprintNoContractNone,
42
+ bindContractWithoutToolNamesNone,
43
+ bindGadgetUndeclaredNone,
44
+ bindRejectCharset,
45
+ bindRejectServerCharset,
46
+ bindRejectDuplicatePair,
47
+ bindRejectOverlongName,
48
+ bindRejectTooManyEntries,
49
+ bindRejectEmptyList,
50
+ ];
51
+ /**
52
+ * Every filter-semantics case the kit ships, in deterministic
53
+ * order — tool-dimension, server-dimension, pair, no-filter
54
+ * passthrough, then case-sensitivity.
55
+ */
56
+ export const bindingFilterCases = [
57
+ filterToolCrossServer,
58
+ filterToolMatchesBareEntry,
59
+ filterToolNoMatch,
60
+ filterServerMatch,
61
+ filterServerExcludesBare,
62
+ filterPairExact,
63
+ filterPairNotCrossEntry,
64
+ filterPairBareNeverMatches,
65
+ filterNonePassesBound,
66
+ filterNonePassesUnbound,
67
+ filterToolExcludesUnbound,
68
+ filterCaseSensitiveTool,
69
+ filterCaseSensitiveServer,
70
+ ];
71
+ function bindingListsEqual(a, b) {
72
+ if (a === undefined || b === undefined)
73
+ return a === b;
74
+ if (a.length !== b.length)
75
+ return false;
76
+ return a.every((entry, i) => {
77
+ const other = b[i];
78
+ return other !== undefined && entry.tool === other.tool && entry.server === other.server;
79
+ });
80
+ }
81
+ function resolutionOutcomeEquals(a, b) {
82
+ if (a.outcome === "reject" || b.outcome === "reject") {
83
+ return a.outcome === "reject" && b.outcome === "reject" && a.code === b.code;
84
+ }
85
+ return a.source === b.source && bindingListsEqual(a.bindings, b.bindings);
86
+ }
87
+ /**
88
+ * Grade a binding resolver against the resolution catalog.
89
+ *
90
+ * `resolve` MUST be a pure computation of `(entry) →
91
+ * BindingResolutionOutcome` — schema validation of a declared list
92
+ * plus declared-wins/derivation precedence, composed however the
93
+ * implementation likes. The kit deliberately does NOT import a
94
+ * concrete resolver — adopters pass their own (the reference
95
+ * binding uses a faithful in-test implementation; see
96
+ * `./binding-conformance.test.ts`). A conformant resolver produces
97
+ * an empty `failed` array.
98
+ *
99
+ * `resolve` is invoked exactly once per case, in
100
+ * {@link bindingResolutionCases} order; it MUST be pure and MUST
101
+ * NOT throw (a throwing resolver is itself non-conformant — wrap it
102
+ * so a classified rejection becomes a returned outcome).
103
+ */
104
+ export function runBindingResolutionCases(resolve) {
105
+ const passed = [];
106
+ const failed = [];
107
+ for (const testCase of bindingResolutionCases) {
108
+ const actual = resolve(testCase.entry);
109
+ if (resolutionOutcomeEquals(actual, testCase.expect)) {
110
+ passed.push(testCase.name);
111
+ }
112
+ else {
113
+ failed.push({
114
+ name: testCase.name,
115
+ expected: testCase.expect,
116
+ actual,
117
+ });
118
+ }
119
+ }
120
+ return { passed, failed };
121
+ }
122
+ /**
123
+ * Grade a search filter predicate against the filter catalog.
124
+ *
125
+ * `matches` MUST be a pure computation of `(bindings, filters) →
126
+ * boolean` — the same predicate every storage implementation shares
127
+ * so `tool=` / `server=` behave identically everywhere. The kit
128
+ * deliberately does NOT import a concrete predicate — adopters pass
129
+ * their own. A conformant predicate produces an empty `failed`
130
+ * array.
131
+ *
132
+ * `matches` is invoked exactly once per case, in
133
+ * {@link bindingFilterCases} order; it MUST be pure and MUST NOT
134
+ * throw.
135
+ */
136
+ export function runBindingFilterCases(matches) {
137
+ const passed = [];
138
+ const failed = [];
139
+ for (const testCase of bindingFilterCases) {
140
+ const actual = matches(testCase.bindings, testCase.filters);
141
+ if (actual === testCase.expect) {
142
+ passed.push(testCase.name);
143
+ }
144
+ else {
145
+ failed.push({
146
+ name: testCase.name,
147
+ expected: testCase.expect,
148
+ actual,
149
+ });
150
+ }
151
+ }
152
+ return { passed, failed };
153
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/consume-buffer/index.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;gCAEgC;AAChC,eAAO,MAAM,qBAAqB,EAAE,SAAS,QAAQ,EAIpD,CAAC"}
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 an MCP-binding driver, not this catalog.
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
@@ -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
- * an MCP-binding driver. Declared here rather than papered over with
57
- * a fixture that fails conformant servers on sequencing alone.
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;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"}
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"}
@@ -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
- * an MCP-binding driver. Declared here rather than papered over with
57
- * a fixture that fails conformant servers on sequencing alone.
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":"AA4BA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qEAAqE;AACrE,eAAO,MAAM,gCAAgC,EAAE,SAAS,QAAQ,EAE/D,CAAC"}
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 MCP-binding driver — the gap is declared here
25
- * rather than faked with a frame the wire cannot carry.
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,10 @@ 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 { bindingFilterCases, bindingResolutionCases, runBindingFilterCases, runBindingResolutionCases, } from './binding-conformance/index.js';
24
+ export type { BindingFilterCase, BindingFilterMismatch, BindingFilterResult, BindingManifestEntry, BindingRejectCode, BindingResolutionCase, BindingResolutionMismatch, BindingResolutionOutcome, BindingResolutionResult, McpToolBindingDecl, McpToolFilterDecl, } from './binding-conformance/index.js';
25
+ export { declaresDeliveryChannel, renderLocatorUri, resourceReadCases, runResourceReadConformance, GGUI_RENDER_RESOURCE_URI, } from './resource-read-conformance/index.js';
26
+ 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
27
  export { loadFixture, listFixtures, loadAllFixtures } from './loader.js';
24
28
  export { runConformance } from './run-conformance.js';
25
29
  export type { RunConformanceConfig, ConformanceResult, ConformanceFailure, SkippedFixture, ConformanceReporter, InputEnvelopeDispatch, HostContextObservedInputEnvelope, } from './run-conformance.js';
@@ -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;AAG3C,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -30,6 +30,18 @@ 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
+ // Binding-conformance — MCP tool-binding resolution (declared wins,
34
+ // contract-lineage derivation, schema-invalid rejects) + the search
35
+ // filter semantics (`tool=` / `server=` case-sensitive exact,
36
+ // AND-composed per entry).
37
+ export { bindingFilterCases, bindingResolutionCases, runBindingFilterCases, runBindingResolutionCases, } from './binding-conformance/index.js';
38
+ // Resource-read conformance — the kit's first MCP-binding driver, and
39
+ // it binds `resources/read` ONLY (`tools/call` has none). A read of a
40
+ // render locator has exactly two exits: a result whose contents
41
+ // declare a delivery channel, or one typed JSON-RPC error.
42
+ // Unlike the three catalogs above this one drives a live server, so
43
+ // the caller supplies a scenario driver rather than a pure function.
44
+ export { declaresDeliveryChannel, renderLocatorUri, resourceReadCases, runResourceReadConformance, GGUI_RENDER_RESOURCE_URI, } from './resource-read-conformance/index.js';
33
45
  // Runtime loader — look up a fixture by name from the inlined catalog.
34
46
  export { loadFixture, listFixtures, loadAllFixtures } from './loader.js';
35
47
  // 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":"AA6FA,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"}
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"}
@@ -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 an MCP-binding driver; that gap is
88
- * declared here rather than papered over with a weaker assertion.
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';
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "resolve-bundle-host-computed",
3
- "description": "A descriptor with a hostname-only `bundleHost` (no scheme, no path) and no explicit `bundleUrl`. The resolver MUST compute both the bundle and style URLs as `https://<bundleHost>/bundles/<package>/<version>/<file>` — the path layout matching `@ggui-ai/registry-core`'s `BundleStorage` so a bundle published to one registry resolves cleanly from the other.",
3
+ "description": "A descriptor with a hostname-only `bundleHost` (no scheme, no path) and no explicit `bundleUrl`. The resolver MUST compute both the bundle and style URLs as `https://<bundleHost>/bundles/public/<package>/<version>/<file>` — the PUBLIC prefix of `@ggui-ai/registry-core`'s visibility-split `BundleStorage` layout (H1). bundleHost-tier composition is anonymous render-time fetching, which only the public prefix serves; private artifacts reach the iframe via an explicit presigned `bundleUrl`, never via host composition. Keeping the shapes aligned means a bundle published to one registry resolves cleanly from the other.",
4
4
  "entry": {
5
5
  "package": "@acme/leaflet-wrapper",
6
6
  "version": "2.3.1",
7
7
  "bundleHost": "cdn.example.com"
8
8
  },
9
9
  "expect": {
10
- "bundleUrl": "https://cdn.example.com/bundles/@acme/leaflet-wrapper/2.3.1/bundle.js",
11
- "styleUrl": "https://cdn.example.com/bundles/@acme/leaflet-wrapper/2.3.1/style.css"
10
+ "bundleUrl": "https://cdn.example.com/bundles/public/@acme/leaflet-wrapper/2.3.1/bundle.js",
11
+ "styleUrl": "https://cdn.example.com/bundles/public/@acme/leaflet-wrapper/2.3.1/style.css"
12
12
  }
13
13
  }