@ggui-ai/protocol-conformance 0.10.0 → 0.12.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "action-payload-schema-violation",
3
- "description": "A `data:submit` action naming a DECLARED action whose `data` violates the entry's declared payload schema is rejected at receipt: the server replies an `error` frame with code CONTRACT_VIOLATION (echoing the action's requestId) and the envelope is NOT appended to the consume buffer. Proves the payload-schema half of the declared-action contract (SPEC Section 4.6 receipt validation) — name-membership alone does not admit an action whose payload breaks the contract.",
3
+ "description": "A `data:submit` action naming a DECLARED action whose `data` violates the entry's declared payload schema is rejected at receipt: the server replies an `error` frame with code CONTRACT_VIOLATION (echoing the action's requestId) and the envelope is NOT appended to the consume buffer. Proves the payload-schema half of the declared-action contract (SPEC Section 4.6 receipt validation) — name-membership alone does not admit an action whose payload breaks the contract. The rejection's recovery payload is the SPEC Section 7.9 contract_violation shape: `payload.details.violations` entries carry field + message + the producing JSON Schema `keyword` (draft-2026-08-19 — the failure-class segmentation surface).",
4
4
  "skipReason": null,
5
5
  "setup": [
6
6
  {
@@ -32,6 +32,7 @@
32
32
  "expectedBehavior": {
33
33
  "kind": "error-frame",
34
34
  "code": "CONTRACT_VIOLATION",
35
- "requestId": "ck-schema-violation-1-req"
35
+ "requestId": "ck-schema-violation-1-req",
36
+ "contractViolationPayload": { "requireKeyword": true }
36
37
  }
37
38
  }
@@ -24,6 +24,7 @@
24
24
  "expectedBehavior": {
25
25
  "kind": "error-frame",
26
26
  "code": "CONTRACT_VIOLATION",
27
- "requestId": "ck-undeclared-action-1-req"
27
+ "requestId": "ck-undeclared-action-1-req",
28
+ "contractViolationPayload": {}
28
29
  }
29
30
  }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Host-helper conformance catalog (ggui#600) — grades the library that
3
+ * mounts a ggui view and answers the MCP-Apps bridge (a "host helper"):
4
+ * does it answer `ui/initialize` well-formed, advertise truthfully,
5
+ * refuse honestly and boundedly, and either relay the runtime tool
6
+ * family or stand as a declared read-only tier?
7
+ *
8
+ * ## Why this catalog exists
9
+ *
10
+ * The 2026-08-21 production incident (ggui#596): a chat-rail host
11
+ * mounted interactive cards with its `tools/call` relay off — legal
12
+ * under the external MCP Apps spec (relay is an optional capability),
13
+ * invisible to every test, discovered by a user's dead tap. This
14
+ * catalog is the structural catch: a helper vendor runs it in CI and
15
+ * the scorecard names the tier — `relaying` or `read-only` — so an
16
+ * assembler reads the grade instead of shipping the discovery.
17
+ *
18
+ * ## Driver contract
19
+ *
20
+ * The kit drives JSON-RPC messages through a {@link HostHelperPort}
21
+ * the implementer supplies — the same implementation-as-callbacks
22
+ * pattern as the props-schema catalog. No DOM, no postMessage plumbing:
23
+ * an adapter binds the port to the helper's real transport (window
24
+ * messaging, an in-process machine, a WebView bridge).
25
+ *
26
+ * ## Grades
27
+ *
28
+ * - `H1-initialize-well-formed` — `ui/initialize` answers a result
29
+ * carrying a `hostCapabilities` object (empty is legal).
30
+ * - `H2-advertisement-truthful` — every advertised capability with a
31
+ * probe mapping answers its method family (advertised ⊆ answered).
32
+ * An advertises-but-refuses helper makes the runtime's confirmed-
33
+ * failure latch structurally unreachable — the worst dead-tap shape.
34
+ * - `H3-refusal-honest` — an unsupported request is refused IN-BAND
35
+ * with JSON-RPC `-32601` naming the method. Silent drops fail: a
36
+ * refusal is recoverable, a hang leaves the runtime guessing.
37
+ * - `H4-refusal-bounded` — the refusal arrives within the probe
38
+ * timeout (a refusal is immediate by nature; only delivery is slow).
39
+ * - `R1-relay-round-trip` — a relaying helper forwards `tools/call`
40
+ * for the runtime tool family and returns the result envelope
41
+ * UNMODIFIED — including failure result envelopes (`{ok:false}`
42
+ * passes through; re-shaping breaks the runtime's self-healing).
43
+ * - `R2-relay-advertised` — a relaying helper advertises
44
+ * `serverTools` (truthful positive advertisement).
45
+ *
46
+ * - `T1-theme-coverage` — OPTIONAL (like the C-class chrome audit):
47
+ * when a theme registration is supplied, it covers the consumed-
48
+ * token manifest or declares explicit inherit (ggui#598's
49
+ * registration gate, graded at the helper's door). The kit carries
50
+ * no theme machinery — the option takes the VALIDATOR AS A CALLBACK
51
+ * (implementation-as-callbacks, the kit's own pattern); the
52
+ * reference validate is `@ggui-ai/design`'s `validateThemeCoverage`
53
+ * bound to the shipped `consumed-tokens.manifest.json` tokens.
54
+ *
55
+ * A helper that refuses the relay honestly is graded **tier
56
+ * `read-only`** — a LEGAL grade, with the R cases skipped, never
57
+ * failed. `nonconforming` means a dishonesty case failed.
58
+ */
59
+ /** Minimal JSON-RPC request the driver sends through the port. */
60
+ export interface JsonRpcRequest {
61
+ readonly jsonrpc: '2.0';
62
+ readonly id: number | string;
63
+ readonly method: string;
64
+ readonly params?: unknown;
65
+ }
66
+ /** Minimal JSON-RPC response the port returns (null = no answer). */
67
+ export interface JsonRpcResponse {
68
+ readonly jsonrpc: '2.0';
69
+ readonly id: number | string;
70
+ readonly result?: unknown;
71
+ readonly error?: {
72
+ readonly code: number;
73
+ readonly message: string;
74
+ };
75
+ }
76
+ /**
77
+ * The implementation under test, as a message port: deliver one
78
+ * request to the helper, resolve with its response — or `null` when
79
+ * the helper produced none (a drop). Adapters own transports.
80
+ */
81
+ export interface HostHelperPort {
82
+ send(request: JsonRpcRequest): Promise<JsonRpcResponse | null>;
83
+ }
84
+ /**
85
+ * Style inventory of the helper's mount surfaces, collected by the
86
+ * vendor (computed styles on web, style objects on RN) and graded by
87
+ * the kit — the pure-node split that keeps DOM out of the catalog.
88
+ * The helper OWNS containment only; every visual property beyond it is
89
+ * chrome the theme contract cannot reach (the round-6 class:
90
+ * `McpAppIframe` hardcoded borderWidth/#e5e5e5/radius on both slots,
91
+ * present in every #589 rejection round). Silhouette (rim, clip,
92
+ * radius) belongs to the EMBEDDING host outside the helper; tokens
93
+ * belong to the theme; the helper paints nothing.
94
+ */
95
+ export interface ChromeAudit {
96
+ /** Styles the helper applies to the mounted view's slot element. */
97
+ readonly slotStyles: Record<string, string>;
98
+ /** Styles the helper applies to its empty/fallback slot. */
99
+ readonly emptySlotStyles: Record<string, string>;
100
+ }
101
+ /**
102
+ * What the theme-coverage callback returns — structurally identical
103
+ * to `@ggui-ai/design`'s `ThemeCoverageResult`, declared here so the
104
+ * kit's dependency surface stays `@ggui-ai/protocol` + `ws` (the
105
+ * validator is injected, never imported).
106
+ */
107
+ export interface ThemeCoverageValidationResult {
108
+ /** True iff every obligated manifest token is covered in both modes. */
109
+ readonly covered: boolean;
110
+ /** Obligated tokens not covered, per mode. */
111
+ readonly uncovered: {
112
+ readonly light: readonly string[];
113
+ readonly dark: readonly string[];
114
+ };
115
+ /** Tokens satisfied via explicit inherit declarations. */
116
+ readonly inheritMatched: readonly string[];
117
+ /** Manifest tokens excluded from the obligation (non-definable). */
118
+ readonly excluded: readonly string[];
119
+ }
120
+ /**
121
+ * Theme-coverage grading input (T1). `registration` is the helper's
122
+ * theme registration document pair, OPAQUE to the kit — only the
123
+ * supplied `validate` callback reads it. The reference callback is
124
+ * `@ggui-ai/design`'s `validateThemeCoverage` bound to the shipped
125
+ * `consumed-tokens.manifest.json` `tokens` array:
126
+ *
127
+ * ```ts
128
+ * const docs: ThemeRegistrationDocs = { light, dark };
129
+ * themeCoverage: {
130
+ * registration: docs,
131
+ * validate: () => validateThemeCoverage(docs, manifest.tokens),
132
+ * }
133
+ * ```
134
+ */
135
+ export interface ThemeCoverageOptions {
136
+ readonly registration: unknown;
137
+ readonly validate: (registration: unknown) => ThemeCoverageValidationResult;
138
+ }
139
+ export interface HostHelperConformanceOptions {
140
+ /**
141
+ * How long a refusal may take before it counts as a hang (H4 /
142
+ * silent-drop detection). Refusals are immediate by nature; the
143
+ * default absorbs slow transports, not slow decisions.
144
+ */
145
+ readonly refusalTimeoutMs?: number;
146
+ /**
147
+ * Chrome audit for the C-grades. Absent ⇒ C cases report `skip`
148
+ * (self-certification pending) — the tier is decided by H/R alone.
149
+ */
150
+ readonly chromeAudit?: ChromeAudit;
151
+ /**
152
+ * Theme registration + coverage validator for the T-grades. Absent
153
+ * ⇒ T cases report `skip` (no theme registration supplied) — an
154
+ * unthemed helper surface has no coverage obligation.
155
+ */
156
+ readonly themeCoverage?: ThemeCoverageOptions;
157
+ }
158
+ export type HostHelperCaseOutcome = 'pass' | 'fail' | 'skip' | 'warn';
159
+ export interface HostHelperCaseResult {
160
+ readonly id: string;
161
+ readonly outcome: HostHelperCaseOutcome;
162
+ readonly detail: string;
163
+ }
164
+ export type HostHelperTier = 'relaying' | 'read-only' | 'nonconforming';
165
+ export interface HostHelperConformanceReport {
166
+ readonly catalog: 'host-helper-conformance';
167
+ readonly tier: HostHelperTier;
168
+ readonly cases: readonly HostHelperCaseResult[];
169
+ /** The failing case ids — empty on a conforming helper of either tier. */
170
+ readonly failures: readonly string[];
171
+ }
172
+ /**
173
+ * Run the catalog against one helper port. Pure protocol driving —
174
+ * safe anywhere node runs; a helper vendor calls this from their CI.
175
+ */
176
+ export declare function runHostHelperConformance(port: HostHelperPort, options?: HostHelperConformanceOptions): Promise<HostHelperConformanceReport>;
177
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host-helper-conformance/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,377 @@
1
+ /**
2
+ * Host-helper conformance catalog (ggui#600) — grades the library that
3
+ * mounts a ggui view and answers the MCP-Apps bridge (a "host helper"):
4
+ * does it answer `ui/initialize` well-formed, advertise truthfully,
5
+ * refuse honestly and boundedly, and either relay the runtime tool
6
+ * family or stand as a declared read-only tier?
7
+ *
8
+ * ## Why this catalog exists
9
+ *
10
+ * The 2026-08-21 production incident (ggui#596): a chat-rail host
11
+ * mounted interactive cards with its `tools/call` relay off — legal
12
+ * under the external MCP Apps spec (relay is an optional capability),
13
+ * invisible to every test, discovered by a user's dead tap. This
14
+ * catalog is the structural catch: a helper vendor runs it in CI and
15
+ * the scorecard names the tier — `relaying` or `read-only` — so an
16
+ * assembler reads the grade instead of shipping the discovery.
17
+ *
18
+ * ## Driver contract
19
+ *
20
+ * The kit drives JSON-RPC messages through a {@link HostHelperPort}
21
+ * the implementer supplies — the same implementation-as-callbacks
22
+ * pattern as the props-schema catalog. No DOM, no postMessage plumbing:
23
+ * an adapter binds the port to the helper's real transport (window
24
+ * messaging, an in-process machine, a WebView bridge).
25
+ *
26
+ * ## Grades
27
+ *
28
+ * - `H1-initialize-well-formed` — `ui/initialize` answers a result
29
+ * carrying a `hostCapabilities` object (empty is legal).
30
+ * - `H2-advertisement-truthful` — every advertised capability with a
31
+ * probe mapping answers its method family (advertised ⊆ answered).
32
+ * An advertises-but-refuses helper makes the runtime's confirmed-
33
+ * failure latch structurally unreachable — the worst dead-tap shape.
34
+ * - `H3-refusal-honest` — an unsupported request is refused IN-BAND
35
+ * with JSON-RPC `-32601` naming the method. Silent drops fail: a
36
+ * refusal is recoverable, a hang leaves the runtime guessing.
37
+ * - `H4-refusal-bounded` — the refusal arrives within the probe
38
+ * timeout (a refusal is immediate by nature; only delivery is slow).
39
+ * - `R1-relay-round-trip` — a relaying helper forwards `tools/call`
40
+ * for the runtime tool family and returns the result envelope
41
+ * UNMODIFIED — including failure result envelopes (`{ok:false}`
42
+ * passes through; re-shaping breaks the runtime's self-healing).
43
+ * - `R2-relay-advertised` — a relaying helper advertises
44
+ * `serverTools` (truthful positive advertisement).
45
+ *
46
+ * - `T1-theme-coverage` — OPTIONAL (like the C-class chrome audit):
47
+ * when a theme registration is supplied, it covers the consumed-
48
+ * token manifest or declares explicit inherit (ggui#598's
49
+ * registration gate, graded at the helper's door). The kit carries
50
+ * no theme machinery — the option takes the VALIDATOR AS A CALLBACK
51
+ * (implementation-as-callbacks, the kit's own pattern); the
52
+ * reference validate is `@ggui-ai/design`'s `validateThemeCoverage`
53
+ * bound to the shipped `consumed-tokens.manifest.json` tokens.
54
+ *
55
+ * A helper that refuses the relay honestly is graded **tier
56
+ * `read-only`** — a LEGAL grade, with the R cases skipped, never
57
+ * failed. `nonconforming` means a dishonesty case failed.
58
+ */
59
+ const METHOD_NOT_SUPPORTED = -32601;
60
+ const DEFAULT_REFUSAL_TIMEOUT_MS = 2_000;
61
+ /** A method no ggui helper answers — the honest-refusal probe. */
62
+ const UNSUPPORTED_PROBE_METHOD = 'ggui-conformance/unsupported-probe';
63
+ /**
64
+ * Containment styles a helper may legitimately apply to its mount
65
+ * surfaces: sizing, layout participation, overflow clipping, and
66
+ * stacking — never color, border, radius, shadow, or typography.
67
+ * Vendor-prefixed and camelCase/kebab-case spellings both normalize.
68
+ */
69
+ const CONTAINMENT_STYLE_ALLOWLIST = new Set([
70
+ 'overflow',
71
+ 'overflowx',
72
+ 'overflowy',
73
+ 'width',
74
+ 'height',
75
+ 'minwidth',
76
+ 'minheight',
77
+ 'maxwidth',
78
+ 'maxheight',
79
+ 'flex',
80
+ 'flexgrow',
81
+ 'flexshrink',
82
+ 'flexbasis',
83
+ 'alignself',
84
+ 'display',
85
+ 'position',
86
+ 'top',
87
+ 'right',
88
+ 'bottom',
89
+ 'left',
90
+ 'inset',
91
+ 'zindex',
92
+ 'contain',
93
+ 'aspectratio',
94
+ ]);
95
+ /**
96
+ * Border-family properties whose value can be judged: an EXPLICIT
97
+ * non-painting value (`none` / `0`) is containment — it neutralizes
98
+ * user-agent defaults and paints nothing — while any painting value
99
+ * is chrome. Only the border family gets value-aware treatment; every
100
+ * other visual property is chrome regardless of value.
101
+ */
102
+ const BORDER_FAMILY_RE = /^border/;
103
+ const NON_PAINTING_VALUES = new Set(['none', '0', '0px']);
104
+ function isContainmentStyle(property, value) {
105
+ const normalized = property.toLowerCase().replace(/-/g, '');
106
+ if (CONTAINMENT_STYLE_ALLOWLIST.has(normalized))
107
+ return true;
108
+ return (BORDER_FAMILY_RE.test(normalized) &&
109
+ NON_PAINTING_VALUES.has(value.trim().toLowerCase()));
110
+ }
111
+ let nextId = 1;
112
+ function request(method, params) {
113
+ return { jsonrpc: '2.0', id: `hh-${nextId++}`, method, ...(params !== undefined ? { params } : {}) };
114
+ }
115
+ async function sendWithTimeout(port, req, timeoutMs) {
116
+ const started = Date.now();
117
+ let timer;
118
+ const timeout = new Promise((resolve) => {
119
+ timer = setTimeout(() => resolve('timeout'), timeoutMs);
120
+ });
121
+ const raced = await Promise.race([port.send(req), timeout]);
122
+ if (timer !== undefined)
123
+ clearTimeout(timer);
124
+ if (raced === 'timeout') {
125
+ return { response: null, timedOut: true, ms: Date.now() - started };
126
+ }
127
+ return { response: raced, timedOut: false, ms: Date.now() - started };
128
+ }
129
+ function isRefusal(resp) {
130
+ return resp?.error !== undefined && resp.error.code === METHOD_NOT_SUPPORTED;
131
+ }
132
+ /**
133
+ * Run the catalog against one helper port. Pure protocol driving —
134
+ * safe anywhere node runs; a helper vendor calls this from their CI.
135
+ */
136
+ export async function runHostHelperConformance(port, options = {}) {
137
+ const refusalTimeoutMs = options.refusalTimeoutMs ?? DEFAULT_REFUSAL_TIMEOUT_MS;
138
+ const cases = [];
139
+ // ── H1: initialize well-formed ────────────────────────────────────
140
+ const init = await sendWithTimeout(port, request('ui/initialize', {
141
+ appInfo: { name: 'ggui-conformance-driver', version: '0' },
142
+ appCapabilities: {},
143
+ }), refusalTimeoutMs);
144
+ const initResult = init.response?.result;
145
+ const capabilities = initResult !== undefined &&
146
+ typeof initResult.hostCapabilities === 'object' &&
147
+ initResult.hostCapabilities !== null
148
+ ? initResult.hostCapabilities
149
+ : undefined;
150
+ cases.push(capabilities !== undefined
151
+ ? {
152
+ id: 'H1-initialize-well-formed',
153
+ outcome: 'pass',
154
+ detail: `hostCapabilities: {${Object.keys(capabilities).join(', ')}}`,
155
+ }
156
+ : {
157
+ id: 'H1-initialize-well-formed',
158
+ outcome: 'fail',
159
+ detail: init.timedOut
160
+ ? 'ui/initialize did not answer within the probe timeout'
161
+ : 'ui/initialize result carries no hostCapabilities object',
162
+ });
163
+ const advertisesServerTools = capabilities !== undefined && capabilities['serverTools'] !== undefined;
164
+ // ── relay probe (feeds H2 and R1) ─────────────────────────────────
165
+ // The probe's `payload: {}` is non-primitive DELIBERATELY: helpers
166
+ // that stage primitive action payloads into a host affordance before
167
+ // relaying (e.g. a chat composer's staging gate) fall THROUGH to the
168
+ // relay on a non-primitive payload — so this probe grades the relay
169
+ // itself, never the staging path. An all-primitive payload against
170
+ // such a helper would legally answer the staged acceptance instead
171
+ // of round-tripping the relay; do not "simplify" this shape.
172
+ // (First observed live on the guuey kit baseline, ggui#600.)
173
+ const relayProbe = await sendWithTimeout(port, request('tools/call', {
174
+ name: 'ggui_runtime_submit_action',
175
+ arguments: {
176
+ kind: 'dispatch',
177
+ sessionId: 'conformance-probe',
178
+ payload: {},
179
+ actionId: 'probe-1',
180
+ firedAt: 0,
181
+ },
182
+ }), refusalTimeoutMs);
183
+ const relayAnswered = relayProbe.response !== null && relayProbe.response.error === undefined;
184
+ const relayRefused = isRefusal(relayProbe.response);
185
+ // ── H2: advertisement truthfulness ────────────────────────────────
186
+ if (capabilities === undefined) {
187
+ cases.push({
188
+ id: 'H2-advertisement-truthful',
189
+ outcome: 'skip',
190
+ detail: 'no capabilities captured (H1 failed)',
191
+ });
192
+ }
193
+ else if (!advertisesServerTools) {
194
+ cases.push({
195
+ id: 'H2-advertisement-truthful',
196
+ outcome: 'pass',
197
+ detail: 'nothing advertised beyond the probe map — vacuously truthful',
198
+ });
199
+ }
200
+ else {
201
+ cases.push(relayAnswered
202
+ ? {
203
+ id: 'H2-advertisement-truthful',
204
+ outcome: 'pass',
205
+ detail: 'serverTools advertised and tools/call answered',
206
+ }
207
+ : {
208
+ id: 'H2-advertisement-truthful',
209
+ outcome: 'fail',
210
+ detail: 'serverTools advertised but tools/call was refused or dropped — the runtime latch is structurally unreachable on this shape (ggui#596)',
211
+ });
212
+ }
213
+ // ── H3 + H4: refusal honesty + boundedness ────────────────────────
214
+ const refusal = await sendWithTimeout(port, request(UNSUPPORTED_PROBE_METHOD), refusalTimeoutMs);
215
+ if (isRefusal(refusal.response)) {
216
+ const namesMethod = refusal.response?.error?.message.includes(UNSUPPORTED_PROBE_METHOD) ??
217
+ false;
218
+ cases.push({
219
+ id: 'H3-refusal-honest',
220
+ outcome: 'pass',
221
+ detail: namesMethod
222
+ ? 'in-band -32601 naming the method'
223
+ : 'in-band -32601 (message does not name the method — acceptable, naming recommended)',
224
+ });
225
+ cases.push({
226
+ id: 'H4-refusal-bounded',
227
+ outcome: 'pass',
228
+ detail: `refused in ${refusal.ms}ms`,
229
+ });
230
+ }
231
+ else {
232
+ cases.push({
233
+ id: 'H3-refusal-honest',
234
+ outcome: 'fail',
235
+ detail: refusal.timedOut
236
+ ? 'unsupported request HUNG — a silent drop leaves the runtime unable to distinguish refusal from loss'
237
+ : 'unsupported request answered without a -32601 refusal',
238
+ });
239
+ cases.push({
240
+ id: 'H4-refusal-bounded',
241
+ outcome: refusal.timedOut ? 'fail' : 'skip',
242
+ detail: refusal.timedOut
243
+ ? 'no answer within the probe timeout'
244
+ : 'not measurable (H3 failed without a timeout)',
245
+ });
246
+ }
247
+ // ── R cases ───────────────────────────────────────────────────────
248
+ if (relayAnswered) {
249
+ const relayResult = relayProbe.response?.result;
250
+ const envelope = relayResult?.structuredContent;
251
+ cases.push(envelope !== undefined && typeof envelope === 'object'
252
+ ? {
253
+ id: 'R1-relay-round-trip',
254
+ outcome: 'pass',
255
+ detail: 'result envelope returned intact (failure envelopes must pass through unmodified — the runtime self-heals on ANY well-formed result)',
256
+ }
257
+ : {
258
+ id: 'R1-relay-round-trip',
259
+ outcome: 'fail',
260
+ detail: 'tools/call answered but the result carries no structuredContent envelope',
261
+ });
262
+ cases.push(advertisesServerTools
263
+ ? {
264
+ id: 'R2-relay-advertised',
265
+ outcome: 'pass',
266
+ detail: 'relay wired and serverTools advertised',
267
+ }
268
+ : {
269
+ id: 'R2-relay-advertised',
270
+ outcome: 'fail',
271
+ detail: 'relay answers but serverTools is not advertised — under-advertising costs the runtime a failed-gesture probe on every boot',
272
+ });
273
+ }
274
+ else if (relayRefused) {
275
+ cases.push({
276
+ id: 'R1-relay-round-trip',
277
+ outcome: 'skip',
278
+ detail: 'read-only tier — relay honestly refused',
279
+ });
280
+ cases.push({
281
+ id: 'R2-relay-advertised',
282
+ outcome: advertisesServerTools ? 'fail' : 'skip',
283
+ detail: advertisesServerTools
284
+ ? 'advertised yet refused (see H2)'
285
+ : 'read-only tier — nothing to advertise',
286
+ });
287
+ }
288
+ else {
289
+ cases.push({
290
+ id: 'R1-relay-round-trip',
291
+ outcome: 'fail',
292
+ detail: 'tools/call was silently dropped — neither relayed nor refused',
293
+ });
294
+ cases.push({
295
+ id: 'R2-relay-advertised',
296
+ outcome: 'skip',
297
+ detail: 'not gradable over a dropped relay',
298
+ });
299
+ }
300
+ // ── C1: zero ungoverned chrome ────────────────────────────────────
301
+ if (options.chromeAudit === undefined) {
302
+ cases.push({
303
+ id: 'C1-containment-only',
304
+ outcome: 'skip',
305
+ detail: 'no chrome audit supplied — self-certification pending (collect the slot style inventories and re-run)',
306
+ });
307
+ }
308
+ else {
309
+ const offending = [];
310
+ for (const [surface, styles] of [
311
+ ['slot', options.chromeAudit.slotStyles],
312
+ ['emptySlot', options.chromeAudit.emptySlotStyles],
313
+ ]) {
314
+ for (const [prop, value] of Object.entries(styles)) {
315
+ if (!isContainmentStyle(prop, value)) {
316
+ offending.push(`${surface}.${prop}`);
317
+ }
318
+ }
319
+ }
320
+ cases.push(offending.length === 0
321
+ ? {
322
+ id: 'C1-containment-only',
323
+ outcome: 'pass',
324
+ detail: 'both mount surfaces carry containment styles only',
325
+ }
326
+ : {
327
+ id: 'C1-containment-only',
328
+ outcome: 'fail',
329
+ detail: `ungoverned chrome the theme contract cannot reach: ${offending.join(', ')} — the helper owns containment only (silhouette = embedding host, tokens = theme; round-6 doctrine)`,
330
+ });
331
+ }
332
+ // ── T1: token coverage ────────────────────────────────────────────
333
+ if (options.themeCoverage === undefined) {
334
+ cases.push({
335
+ id: 'T1-theme-coverage',
336
+ outcome: 'skip',
337
+ detail: 'no theme registration supplied — an unthemed helper surface has no coverage obligation (supply themeCoverage to grade)',
338
+ });
339
+ }
340
+ else {
341
+ const coverage = options.themeCoverage.validate(options.themeCoverage.registration);
342
+ if (coverage.covered) {
343
+ cases.push({
344
+ id: 'T1-theme-coverage',
345
+ outcome: 'pass',
346
+ detail: `manifest covered — ${coverage.inheritMatched.length} inherit-matched, ${coverage.excluded.length} excluded (non-definable)`,
347
+ });
348
+ }
349
+ else {
350
+ const nameUncovered = (mode, tokens) => {
351
+ if (tokens.length === 0)
352
+ return undefined;
353
+ const named = tokens.slice(0, 10).join(', ');
354
+ const rest = tokens.length - 10;
355
+ return `${mode} uncovered (${tokens.length}): ${named}${rest > 0 ? ` …${rest} more` : ''}`;
356
+ };
357
+ const perMode = [
358
+ nameUncovered('light', coverage.uncovered.light),
359
+ nameUncovered('dark', coverage.uncovered.dark),
360
+ ].filter((part) => part !== undefined);
361
+ cases.push({
362
+ id: 'T1-theme-coverage',
363
+ outcome: 'fail',
364
+ detail: `consumed-token manifest not covered — ${perMode.join('; ')} (cover the tokens or declare explicit inherit; silence is not a legal way to inherit)`,
365
+ });
366
+ }
367
+ }
368
+ const failures = cases
369
+ .filter((c) => c.outcome === 'fail')
370
+ .map((c) => c.id);
371
+ const tier = failures.length > 0
372
+ ? 'nonconforming'
373
+ : relayAnswered
374
+ ? 'relaying'
375
+ : 'read-only';
376
+ return { catalog: 'host-helper-conformance', tier, cases, failures };
377
+ }
@@ -1 +1 @@
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"}
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;AAqUD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAgBzD"}
@@ -273,6 +273,50 @@ function matchErrorFrame(behavior, frames) {
273
273
  message: `expected an \`error\` frame with \`payload.code === ${behavior.code}\`${behavior.requestId !== undefined ? ` echoing requestId '${behavior.requestId}'` : ''}; received none.`,
274
274
  };
275
275
  }
276
+ if (behavior.contractViolationPayload !== undefined && match.kind === 'frame') {
277
+ return matchContractViolationPayload(behavior.contractViolationPayload, match.parsed, frames);
278
+ }
279
+ return { kind: 'pass' };
280
+ }
281
+ /**
282
+ * Grade the SPEC §7.9 `contract_violation` recovery payload on a
283
+ * matched error frame — the transport-observable half of the payload
284
+ * pin (draft-2026-08-19). Only the declared assertions fire; extra
285
+ * fields anywhere in the payload are ignored (additive tolerance,
286
+ * VERSION-POLICY §1.2).
287
+ */
288
+ function matchContractViolationPayload(assertions, parsed, frames) {
289
+ const received = frames.map((f) => (f.kind === 'frame' ? f.parsed : f));
290
+ const payload = parsed['payload'];
291
+ const details = isRecord(payload) ? payload['details'] : undefined;
292
+ const violations = isRecord(details) ? details['violations'] : undefined;
293
+ const minViolations = assertions.minViolations ?? 1;
294
+ if (!Array.isArray(violations) || violations.length < minViolations) {
295
+ return {
296
+ kind: 'fail',
297
+ expected: { payload: { details: { violations: `array with >= ${minViolations} entries` } } },
298
+ received,
299
+ message: `expected the error frame's \`payload.details.violations\` to be an array with at least ${minViolations} entr${minViolations === 1 ? 'y' : 'ies'} (SPEC §7.9 contract_violation payload); received ${Array.isArray(violations) ? `${violations.length}` : 'none'}.`,
300
+ };
301
+ }
302
+ for (const [index, entry] of violations.entries()) {
303
+ if (!isRecord(entry) || typeof entry['field'] !== 'string' || typeof entry['message'] !== 'string') {
304
+ return {
305
+ kind: 'fail',
306
+ expected: { violations: [{ field: '<string>', message: '<string>' }] },
307
+ received,
308
+ message: `violations[${index}] must carry string \`field\` + \`message\` (SPEC §7.9 ContractViolation shape).`,
309
+ };
310
+ }
311
+ if (assertions.requireKeyword === true && typeof entry['keyword'] !== 'string') {
312
+ return {
313
+ kind: 'fail',
314
+ expected: { violations: [{ keyword: '<string>' }] },
315
+ received,
316
+ message: `violations[${index}] lacks the \`keyword\` field — validator-produced violations MUST retain the JSON Schema keyword that fired (SPEC §7.9, draft-2026-08-19).`,
317
+ };
318
+ }
319
+ }
276
320
  return { kind: 'pass' };
277
321
  }
278
322
  /**
@@ -0,0 +1,40 @@
1
+ {
2
+ "id": "required-order-canonical",
3
+ "description": "Representation-insensitivity pin (2026-08-20 incident): the wrapper's `required` array is DERIVED from properties iteration order — an order-unstable source (a document-store Map round-trip legally reorders object keys). `required` is set-semantics in JSON Schema, so the canonical form sorts every `required` array (derived and authored, at every depth); two representations of one contract MUST build byte-identical canonical schemas and one propsSchemaHash. This case lists properties in NON-sorted insertion order; a builder that reproduces iteration order emits required:[\"tickets\",\"asOf\"] and fails both the schema and hash compare.",
4
+ "propsSpec": {
5
+ "properties": {
6
+ "tickets": {
7
+ "schema": { "type": "array", "items": { "type": "string" } },
8
+ "required": true
9
+ },
10
+ "asOf": {
11
+ "schema": { "type": "string" },
12
+ "required": true
13
+ }
14
+ }
15
+ },
16
+ "propsSchema": {
17
+ "additionalProperties": false,
18
+ "properties": {
19
+ "asOf": { "type": "string" },
20
+ "tickets": { "items": { "type": "string" }, "type": "array" }
21
+ },
22
+ "required": ["asOf", "tickets"],
23
+ "type": "object"
24
+ },
25
+ "propsSchemaHash": "b9d16dbdc03fa678ffe6af44a8d6a2f96c59d0913bff35e866516bfcecb67316",
26
+ "propsSchemaProfile": "grammar-safe",
27
+ "samples": [
28
+ { "props": { "asOf": "2026-08-20", "tickets": ["t-1"] }, "valid": true },
29
+ {
30
+ "props": { "tickets": ["t-1"] },
31
+ "valid": false,
32
+ "note": "asOf required regardless of declaration order"
33
+ },
34
+ {
35
+ "props": { "asOf": "2026-08-20" },
36
+ "valid": false,
37
+ "note": "tickets required regardless of declaration order"
38
+ }
39
+ ]
40
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/props-schema-conformance/index.ts"],"names":[],"mappings":"AAyCA;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,iCAAiC;IACjC,QAAQ,CAAC,kBAAkB,EAAE,cAAc,GAAG,MAAM,CAAC;IACrD,QAAQ,CAAC,OAAO,EAAE,SAAS,4BAA4B,EAAE,CAAC;CAC3D;AAED,oEAAoE;AACpE,eAAO,MAAM,2BAA2B,EAAE,SAAS,0BAA0B,EAS1C,CAAC;AAEpC,mDAAmD;AACnD,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,CACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IAC3D,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IAC/D;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC;CACd;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,6BAA6B,EAAE,CAAC;CAC7D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,yBAAyB,GAC9B,4BAA4B,CAuC9B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/props-schema-conformance/index.ts"],"names":[],"mappings":"AA0CA;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,iCAAiC;IACjC,QAAQ,CAAC,kBAAkB,EAAE,cAAc,GAAG,MAAM,CAAC;IACrD,QAAQ,CAAC,OAAO,EAAE,SAAS,4BAA4B,EAAE,CAAC;CAC3D;AAED,oEAAoE;AACpE,eAAO,MAAM,2BAA2B,EAAE,SAAS,0BAA0B,EAU1C,CAAC;AAEpC,mDAAmD;AACnD,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,CACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IAC3D,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IAC/D;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC;CACd;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,6BAA6B,EAAE,CAAC;CAC7D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,yBAAyB,GAC9B,4BAA4B,CAuC9B"}
@@ -37,6 +37,7 @@ import formatOutOfListFull from './cases/format-out-of-list-full.json' with { ty
37
37
  import nullableNormalization from './cases/nullable-normalization.json' with { type: 'json' };
38
38
  import nullableObjectClosed from './cases/nullable-object-closed.json' with { type: 'json' };
39
39
  import outOfCorePatternFull from './cases/out-of-core-pattern-full.json' with { type: 'json' };
40
+ import requiredOrderCanonical from './cases/required-order-canonical.json' with { type: 'json' };
40
41
  import schedulerEnumAuthority from './cases/scheduler-enum-authority.json' with { type: 'json' };
41
42
  /** The published catalog, id-sorted for deterministic reporting. */
42
43
  export const propsSchemaConformanceCases = [
@@ -46,6 +47,7 @@ export const propsSchemaConformanceCases = [
46
47
  nullableNormalization,
47
48
  nullableObjectClosed,
48
49
  outOfCorePatternFull,
50
+ requiredOrderCanonical,
49
51
  schedulerEnumAuthority,
50
52
  ];
51
53
  /**
package/dist/types.d.ts CHANGED
@@ -280,6 +280,27 @@ export interface ErrorFrameBehavior {
280
280
  * to the fixture's own dispatched frame rather than any error the
281
281
  * observation window happens to catch. */
282
282
  readonly requestId?: string;
283
+ /**
284
+ * Optional shape assertions on the matched frame's
285
+ * `payload.details` recovery payload — the SPEC §7.9
286
+ * `contract_violation` shape (`{error, tool, violations[], hint,
287
+ * propsSchemaHash?}`), load-bearing since draft-2026-08-19
288
+ * (`ContractViolation.keyword` segments failure classes; the §2.3.2
289
+ * breach classifier joins on the payload). Additive-tolerant per
290
+ * VERSION-POLICY §1.2: only the pinned fields assert; extra fields
291
+ * on the payload or its entries never fail. Omit entirely for the
292
+ * plain code/requestId match (every pre-existing fixture).
293
+ */
294
+ readonly contractViolationPayload?: {
295
+ /** Minimum `details.violations` entries (default 1). Every entry
296
+ * MUST carry string `field` + `message`. */
297
+ readonly minViolations?: number;
298
+ /** When true, every violation entry MUST carry a string `keyword`
299
+ * (the JSON Schema keyword that produced it). Set on fixtures
300
+ * whose violations are validator-produced; leave unset where a
301
+ * synthetic violation (no schema keyword) is legal. */
302
+ readonly requireKeyword?: boolean;
303
+ };
283
304
  }
284
305
  /**
285
306
  * Expect a canonical channel-3 delivery frame (SPEC §12.2):
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ggui-ai/protocol-conformance",
3
- "version": "0.10.0",
4
- "description": "Conformance test kit for the ggui protocol. Drives a behavioral fixture catalog against a live implementation over WebSocket, a resources/read catalog against a live MCP server, and four pure-function catalogs (schema, registration, resolution, binding) for the gadget and tool-binding obligations, reporting a scorecard-style pass / fail / skip. MCP builders adopt this kit to prove their implementation is protocol-conformant.",
3
+ "version": "0.12.0",
4
+ "description": "Conformance test kit for the ggui protocol. Drives a behavioral fixture catalog against a live implementation over WebSocket, a resources/read catalog against a live MCP server, and six pure-function catalogs (schema, registration, resolution, binding, props-schema, host-helper) for the gadget, tool-binding, and schema-precise-render and host-helper obligations, reporting a scorecard-style pass / fail / skip. MCP builders adopt this kit to prove their implementation is protocol-conformant.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
7
7
  "ggui",
@@ -60,11 +60,16 @@
60
60
  "types": "./dist/props-schema-conformance/index.d.ts",
61
61
  "import": "./dist/props-schema-conformance/index.js",
62
62
  "default": "./dist/props-schema-conformance/index.js"
63
+ },
64
+ "./host-helper-conformance": {
65
+ "types": "./dist/host-helper-conformance/index.d.ts",
66
+ "import": "./dist/host-helper-conformance/index.js",
67
+ "default": "./dist/host-helper-conformance/index.js"
63
68
  }
64
69
  },
65
70
  "dependencies": {
66
71
  "ws": "^8.20.1",
67
- "@ggui-ai/protocol": "0.10.0"
72
+ "@ggui-ai/protocol": "0.12.0"
68
73
  },
69
74
  "devDependencies": {
70
75
  "@types/node": "^22.0.0",