@ggui-ai/protocol-conformance 0.2.0-alpha.4 → 0.3.0-rc.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 (83) hide show
  1. package/README.md +32 -13
  2. package/dist/cli.d.ts +11 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +48 -20
  5. package/dist/conformance-host.d.ts +81 -76
  6. package/dist/conformance-host.d.ts.map +1 -1
  7. package/dist/conformance-host.js +0 -44
  8. package/dist/fixtures/bootstrap-protocol/bootstrap-bundle-fetch-failed.json +3 -3
  9. package/dist/fixtures/bootstrap-protocol/bootstrap-meta-missing.json +3 -3
  10. package/dist/fixtures/bootstrap-protocol/bootstrap-success.json +3 -3
  11. package/dist/fixtures/consume-buffer/action-ack-sequence.json +28 -0
  12. package/dist/fixtures/consume-buffer/action-payload-schema-violation.json +37 -0
  13. package/dist/fixtures/consume-buffer/index.d.ts +6 -0
  14. package/dist/fixtures/consume-buffer/index.d.ts.map +1 -0
  15. package/dist/fixtures/consume-buffer/index.js +41 -0
  16. package/dist/fixtures/consume-buffer/undeclared-action-rejected.json +29 -0
  17. package/dist/fixtures/host-context/host-context-observed-persists.json +34 -0
  18. package/dist/fixtures/host-context/index.d.ts +5 -0
  19. package/dist/fixtures/host-context/index.d.ts.map +1 -0
  20. package/dist/fixtures/host-context/index.js +40 -0
  21. package/dist/fixtures/index.d.ts +28 -9
  22. package/dist/fixtures/index.d.ts.map +1 -1
  23. package/dist/fixtures/index.js +33 -14
  24. package/dist/fixtures/reserved-channel-authority/index.d.ts.map +1 -1
  25. package/dist/fixtures/reserved-channel-authority/index.js +17 -7
  26. package/dist/fixtures/reserved-channel-authority/props-update-roundtrip.json +4 -4
  27. package/dist/fixtures/schema-version-handshake/index.d.ts.map +1 -1
  28. package/dist/fixtures/schema-version-handshake/index.js +12 -4
  29. package/dist/fixtures/schema-version-handshake/version-match.json +7 -5
  30. package/dist/fixtures/schema-version-handshake/version-mismatch.json +9 -10
  31. package/dist/fixtures/subscribe-tenancy/absent-appid-defaults.json +18 -0
  32. package/dist/fixtures/subscribe-tenancy/app-mismatch.json +20 -0
  33. package/dist/fixtures/subscribe-tenancy/index.d.ts +6 -0
  34. package/dist/fixtures/subscribe-tenancy/index.d.ts.map +1 -0
  35. package/dist/fixtures/subscribe-tenancy/index.js +62 -0
  36. package/dist/index.d.ts +4 -4
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +4 -4
  39. package/dist/match-behavior.d.ts +19 -100
  40. package/dist/match-behavior.d.ts.map +1 -1
  41. package/dist/match-behavior.js +289 -246
  42. package/dist/registration-conformance/cases/gate-duplicate-hook.json +26 -0
  43. package/dist/registration-conformance/cases/gate-export-not-registered.json +1 -0
  44. package/dist/registration-conformance/cases/gate-multi-package-distinct-names-accept.json +26 -0
  45. package/dist/registration-conformance/cases/gate-no-gadgets-accept.json +1 -0
  46. package/dist/registration-conformance/cases/gate-package-mismatch.json +1 -0
  47. package/dist/registration-conformance/cases/gate-priority-not-registered-outranks-mismatch.json +1 -0
  48. package/dist/registration-conformance/cases/gate-priority-registry-outranks-public-env.json +22 -0
  49. package/dist/registration-conformance/cases/gate-public-env-missing.json +21 -0
  50. package/dist/registration-conformance/cases/gate-public-env-satisfied-accept.json +21 -0
  51. package/dist/registration-conformance/cases/gate-public-env-undeclared-wrapper-accept.json +26 -0
  52. package/dist/registration-conformance/cases/gate-registered-resolves-accept.json +1 -0
  53. package/dist/registration-conformance/cases/gate-stdlib-hook-accept.json +1 -0
  54. package/dist/registration-conformance/cases/gate-typo-classifies-as-not-registered.json +1 -0
  55. package/dist/registration-conformance/index.d.ts +64 -33
  56. package/dist/registration-conformance/index.d.ts.map +1 -1
  57. package/dist/registration-conformance/index.js +24 -8
  58. package/dist/run-conformance.d.ts +145 -6
  59. package/dist/run-conformance.d.ts.map +1 -1
  60. package/dist/run-conformance.js +531 -93
  61. package/dist/types.d.ts +319 -165
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/types.js +27 -23
  64. package/dist/ws-transport.d.ts.map +1 -1
  65. package/dist/ws-transport.js +3 -2
  66. package/package.json +3 -3
  67. package/dist/fixtures/observability-events/index.d.ts +0 -5
  68. package/dist/fixtures/observability-events/index.d.ts.map +0 -1
  69. package/dist/fixtures/observability-events/index.js +0 -22
  70. package/dist/fixtures/observability-events/observability-contract-error-emitted.json +0 -28
  71. package/dist/fixtures/observability-events/observability-wired-tool-invoked.json +0 -27
  72. package/dist/fixtures/refresh-semantics/index.d.ts +0 -5
  73. package/dist/fixtures/refresh-semantics/index.d.ts.map +0 -1
  74. package/dist/fixtures/refresh-semantics/index.js +0 -19
  75. package/dist/fixtures/refresh-semantics/stream-refresh-success.json +0 -39
  76. package/dist/fixtures/reserved-channel-authority/stream-schema-violation.json +0 -44
  77. package/dist/fixtures/wired-action-dispatch/index.d.ts +0 -5
  78. package/dist/fixtures/wired-action-dispatch/index.d.ts.map +0 -1
  79. package/dist/fixtures/wired-action-dispatch/index.js +0 -29
  80. package/dist/fixtures/wired-action-dispatch/wired-action-success.json +0 -35
  81. package/dist/fixtures/wired-action-dispatch/wired-action-tool-not-found.json +0 -30
  82. package/dist/fixtures/wired-action-dispatch/wired-action-tool-threw.json +0 -31
  83. package/dist/fixtures/wired-action-dispatch/wired-action-tool-timeout.json +0 -31
@@ -0,0 +1,37 @@
1
+ {
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.",
4
+ "skipReason": null,
5
+ "setup": [
6
+ {
7
+ "type": "create-session",
8
+ "sessionId": "ck-schema-violation-1",
9
+ "actionSpec": {
10
+ "toggleTask": {
11
+ "schema": {
12
+ "type": "object",
13
+ "properties": { "id": { "type": "string" } },
14
+ "required": ["id"]
15
+ }
16
+ }
17
+ }
18
+ }
19
+ ],
20
+ "inputEnvelope": {
21
+ "type": "action",
22
+ "requestId": "ck-schema-violation-1-req",
23
+ "payload": {
24
+ "sessionId": "ck-schema-violation-1",
25
+ "type": "data:submit",
26
+ "payload": {
27
+ "action": "toggleTask",
28
+ "data": { "id": 41 }
29
+ }
30
+ }
31
+ },
32
+ "expectedBehavior": {
33
+ "kind": "error-frame",
34
+ "code": "CONTRACT_VIOLATION",
35
+ "requestId": "ck-schema-violation-1-req"
36
+ }
37
+ }
@@ -0,0 +1,6 @@
1
+ import type { TestCase } from '../../types.js';
2
+ /** All fixtures asserting consume-buffer action routing (SPEC
3
+ * §nextStep-evolution single model + §4.4 contract enforcement +
4
+ * §4.6 receipt validation). */
5
+ export declare const consumeBufferFixtures: readonly TestCase[];
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `consume-buffer` fixture sub-module.
3
+ *
4
+ * Exercises the single action-routing model's wire-observable half:
5
+ * every UI action lands as an event on the GguiSession's consume
6
+ * buffer, and the buffer append is provable on pure WS.
7
+ *
8
+ * - `action-ack-sequence` — a declared action's ack frame carries
9
+ * `payload.sequence`, the monotonic event sequence the append
10
+ * assigned. Persistence proof.
11
+ * - `undeclared-action-rejected` — a `data:submit` action absent
12
+ * from the declared actionSpec replies an `error` frame with code
13
+ * `CONTRACT_VIOLATION`; nothing is appended. Contract-gate proof,
14
+ * name-membership half.
15
+ * - `action-payload-schema-violation` — a `data:submit` action
16
+ * naming a DECLARED entry whose `data` violates the entry's
17
+ * declared payload schema replies the same `error` frame with
18
+ * code `CONTRACT_VIOLATION`; nothing is appended. Contract-gate
19
+ * proof, payload-schema half (SPEC §4.6 receipt validation).
20
+ *
21
+ * The retrieval half — the agent draining the buffer via
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.
24
+ * Same declared-gap posture for the schema-validity meta-check on the
25
+ * DECLARED schema itself: a malformed authored schema is a fixture-
26
+ * authoring error the runner throws on (validating parse), while a
27
+ * malformed AGENT-authored schema on a live server is a `ggui_render`
28
+ * / `ggui_handshake` rejection (SPEC Section 7.9) outside this WS
29
+ * kit's observation window.
30
+ */
31
+ import actionAckSequence from './action-ack-sequence.json' with { type: 'json' };
32
+ import actionPayloadSchemaViolation from './action-payload-schema-violation.json' with { type: 'json' };
33
+ import undeclaredActionRejected from './undeclared-action-rejected.json' with { type: 'json' };
34
+ /** All fixtures asserting consume-buffer action routing (SPEC
35
+ * §nextStep-evolution single model + §4.4 contract enforcement +
36
+ * §4.6 receipt validation). */
37
+ export const consumeBufferFixtures = [
38
+ actionAckSequence,
39
+ actionPayloadSchemaViolation,
40
+ undeclaredActionRejected,
41
+ ];
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "undeclared-action-rejected",
3
+ "description": "A `data:submit` action whose name is absent from the GguiSession's declared actionSpec is rejected at the wire boundary: 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 declared-action contract gates persistence — undeclared actions never reach the agent.",
4
+ "skipReason": null,
5
+ "setup": [
6
+ {
7
+ "type": "create-session",
8
+ "sessionId": "ck-undeclared-action-1",
9
+ "actionSpec": { "toggleTask": {} }
10
+ }
11
+ ],
12
+ "inputEnvelope": {
13
+ "type": "action",
14
+ "requestId": "ck-undeclared-action-1-req",
15
+ "payload": {
16
+ "sessionId": "ck-undeclared-action-1",
17
+ "type": "data:submit",
18
+ "payload": {
19
+ "action": "doesNotExist",
20
+ "data": {}
21
+ }
22
+ }
23
+ },
24
+ "expectedBehavior": {
25
+ "kind": "error-frame",
26
+ "code": "CONTRACT_VIOLATION",
27
+ "requestId": "ck-undeclared-action-1-req"
28
+ }
29
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "host-context-observed-persists",
3
+ "description": "The iframe-runtime captures `McpUiHostContext` from the `ui/initialize` response, trims it IFRAME-SIDE to `HostContextProjection` (`projectHostContext` in `@ggui-ai/protocol` — `theme`/`styles` are deliberately not projection fields; they flow through ggui's theming pipeline), and echoes the projection via the `host_context_observed` Client→Server message. The server's obligation is purely stateful: persist `payload.hostContext` onto `GguiSession.hostContext` VERBATIM — the first-party handler patches the received projection as-is, with no server-side re-projection — so `ggui_handshake` / `ggui_consume` surface it to the agent on later turns. That is why this fixture's `expected` is exactly the projection it authors. There is no synchronous response frame, so a `no-op` (wire-silence) assertion would wrongly certify a server that drops the message; the kit grades the obligation by reading `hostContext` back through `ConformanceHost.readSessionField` after the observation window and deep-equalling it against `expected`. Hosts without that introspection seam SKIP — never a weakened pass.",
4
+ "skipReason": null,
5
+ "setup": [{ "type": "create-session", "sessionId": "ck-host-context-1" }],
6
+ "inputEnvelope": {
7
+ "type": "host_context_observed",
8
+ "payload": {
9
+ "sessionId": "ck-host-context-1",
10
+ "hostContext": {
11
+ "availableDisplayModes": ["inline", "fullscreen"],
12
+ "currentDisplayMode": "inline",
13
+ "containerDimensions": { "maxWidth": 480, "height": 320 },
14
+ "platform": "web",
15
+ "deviceCapabilities": { "touch": false, "hover": true },
16
+ "locale": "en-US",
17
+ "timeZone": "America/Los_Angeles"
18
+ }
19
+ }
20
+ },
21
+ "expectedBehavior": {
22
+ "kind": "session-state",
23
+ "field": "hostContext",
24
+ "expected": {
25
+ "availableDisplayModes": ["inline", "fullscreen"],
26
+ "currentDisplayMode": "inline",
27
+ "containerDimensions": { "maxWidth": 480, "height": 320 },
28
+ "platform": "web",
29
+ "deviceCapabilities": { "touch": false, "hover": true },
30
+ "locale": "en-US",
31
+ "timeZone": "America/Los_Angeles"
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,5 @@
1
+ import type { TestCase } from '../../types.js';
2
+ /** All fixtures asserting host-context persistence
3
+ * (`host_context_observed` → `GguiSession.hostContext`). */
4
+ export declare const hostContextFixtures: readonly TestCase[];
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/host-context/index.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;6DAC6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,QAAQ,EAElD,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `host-context` fixture sub-module.
3
+ *
4
+ * Exercises the host-context persistence obligation — the
5
+ * `host_context_observed` Client→Server live-channel message defined
6
+ * by `@ggui-ai/protocol` (`transport/websocket` union +
7
+ * `types/host-context`'s `HostContextObservedPayload`, whose contract
8
+ * is "server-side handler writes to `GguiSession.hostContext`"):
9
+ *
10
+ * - `host-context-observed-persists` — the `HostContextProjection`
11
+ * the iframe echoes after `ui/initialize` MUST land on
12
+ * `GguiSession.hostContext` exactly as received (the projection /
13
+ * trimming step is iframe-side, BEFORE emission; the first-party
14
+ * server persists the received value verbatim, which is what the
15
+ * fixture's `expected` pins). A stateful obligation with no
16
+ * response frame — graded via the kit's session-state read-back
17
+ * mechanism (`ConformanceHost.readSessionField`); hosts without
18
+ * the introspection seam SKIP with a precise reason.
19
+ *
20
+ * Authoring note: the projection vocabulary is re-derived from the
21
+ * live `HostContextProjection` — `currentDisplayMode` (NOT the
22
+ * retired `displayMode` spelling) and NO `theme` field (theme flows
23
+ * through ggui's theming pipeline, not host context). The runner's
24
+ * input-envelope parser rejects unknown projection keys loudly, so a
25
+ * stale-vocabulary fixture is a fixture-authoring error, never a
26
+ * verdict on the implementation under test.
27
+ *
28
+ * Documentation-home note (declared, not hidden): the obligation's
29
+ * normative text lives in `@ggui-ai/protocol`'s type declarations;
30
+ * SPEC.md's §12.2 frame inventory does not yet list
31
+ * `host_context_observed`. Per the protocol-and-contract bar, that
32
+ * SPEC gap should close upstream — the wire type + persistence
33
+ * contract graded here are the shipping source of truth.
34
+ */
35
+ import hostContextObservedPersists from './host-context-observed-persists.json' with { type: 'json' };
36
+ /** All fixtures asserting host-context persistence
37
+ * (`host_context_observed` → `GguiSession.hostContext`). */
38
+ export const hostContextFixtures = [
39
+ hostContextObservedPersists,
40
+ ];
@@ -20,11 +20,10 @@
20
20
  *
21
21
  * ## Current coverage
22
22
  *
23
- * Seven sub-modules with content (18 fixtures). Three additional
24
- * sub-modules (`data-contract`, `tool-name-uniqueness`,
25
- * `contract-error-payload`) are reserved for additive fixture
26
- * expansion and not yet materialized — adding fixtures there is a
27
- * kit minor version.
23
+ * Six sub-modules with content (12 fixtures). Additional sub-modules
24
+ * (`data-contract`, `tool-name-uniqueness`)
25
+ * are reserved for additive fixture expansion and not yet
26
+ * materialized — adding fixtures there is a kit minor version.
28
27
  *
29
28
  * ## What is NOT here — the gadget pure-function obligations
30
29
  *
@@ -36,13 +35,33 @@
36
35
  * caller-supplied function — there is no render, transport, or wire
37
36
  * frame to drive — so they do NOT belong in this behavioral fixture
38
37
  * catalog.
38
+ *
39
+ * ## What is NOT here — declared Path-A sequencing gap
40
+ *
41
+ * A `stream-delivery-roundtrip` fixture (an `emit-envelope`'d payload
42
+ * observed as a canonical `{type: 'data', payload: StreamEnvelope}`
43
+ * frame, graded by `stream-update`) is NOT authorable today without a
44
+ * false fail: the runner dispatches every setup directive BEFORE it
45
+ * opens the WebSocket and subscribes, and `emit-envelope` fans out to
46
+ * live subscribers only — a fresh, `fromSeq`-less subscribe replays
47
+ * nothing on declared channels (SPEC §12.2.1 invariant 1: "`fromSeq`
48
+ * absent always means empty replay"), so the setup-time emission is
49
+ * gone before the runner can observe it. The fixture's
50
+ * `inputEnvelope` cannot carry the emission either: an input envelope
51
+ * is by contract a Client→Server wire frame the runner sends on the
52
+ * transport, while emission is server-side (the agent's `ggui_emit`
53
+ * MCP tool) — routing a host directive through the wire-frame slot
54
+ * 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.
39
58
  */
40
59
  export { bootstrapProtocolFixtures } from './bootstrap-protocol/index.js';
41
- export { observabilityEventsFixtures } from './observability-events/index.js';
42
- export { refreshSemanticsFixtures } from './refresh-semantics/index.js';
60
+ export { consumeBufferFixtures } from './consume-buffer/index.js';
61
+ export { hostContextFixtures } from './host-context/index.js';
43
62
  export { reservedChannelAuthorityFixtures } from './reserved-channel-authority/index.js';
44
63
  export { schemaVersionHandshakeFixtures } from './schema-version-handshake/index.js';
45
- export { wiredActionDispatchFixtures } from './wired-action-dispatch/index.js';
64
+ export { subscribeTenancyFixtures } from './subscribe-tenancy/index.js';
46
65
  import type { TestCase } from '../types.js';
47
66
  /**
48
67
  * Contract slugs — match the sub-module directory names. The
@@ -50,7 +69,7 @@ import type { TestCase } from '../types.js';
50
69
  * Extensibly-closed via `(string & {})` so additive sub-modules
51
70
  * register without an API break.
52
71
  */
53
- export type ContractSlug = 'bootstrap-protocol' | 'observability-events' | 'refresh-semantics' | 'reserved-channel-authority' | 'schema-version-handshake' | 'wired-action-dispatch' | (string & {});
72
+ export type ContractSlug = 'bootstrap-protocol' | 'consume-buffer' | 'host-context' | 'reserved-channel-authority' | 'schema-version-handshake' | 'subscribe-tenancy' | (string & {});
54
73
  /**
55
74
  * Every fixture the kit ships, grouped by the contract it exercises.
56
75
  * Order within each group matches the sub-module's `export` order.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAE/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,sBAAsB,GACtB,mBAAmB,GACnB,4BAA4B,GAC5B,0BAA0B,GAC1B,uBAAuB,GACvB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
@@ -20,11 +20,10 @@
20
20
  *
21
21
  * ## Current coverage
22
22
  *
23
- * Seven sub-modules with content (18 fixtures). Three additional
24
- * sub-modules (`data-contract`, `tool-name-uniqueness`,
25
- * `contract-error-payload`) are reserved for additive fixture
26
- * expansion and not yet materialized — adding fixtures there is a
27
- * kit minor version.
23
+ * Six sub-modules with content (12 fixtures). Additional sub-modules
24
+ * (`data-contract`, `tool-name-uniqueness`)
25
+ * are reserved for additive fixture expansion and not yet
26
+ * materialized — adding fixtures there is a kit minor version.
28
27
  *
29
28
  * ## What is NOT here — the gadget pure-function obligations
30
29
  *
@@ -36,19 +35,39 @@
36
35
  * caller-supplied function — there is no render, transport, or wire
37
36
  * frame to drive — so they do NOT belong in this behavioral fixture
38
37
  * catalog.
38
+ *
39
+ * ## What is NOT here — declared Path-A sequencing gap
40
+ *
41
+ * A `stream-delivery-roundtrip` fixture (an `emit-envelope`'d payload
42
+ * observed as a canonical `{type: 'data', payload: StreamEnvelope}`
43
+ * frame, graded by `stream-update`) is NOT authorable today without a
44
+ * false fail: the runner dispatches every setup directive BEFORE it
45
+ * opens the WebSocket and subscribes, and `emit-envelope` fans out to
46
+ * live subscribers only — a fresh, `fromSeq`-less subscribe replays
47
+ * nothing on declared channels (SPEC §12.2.1 invariant 1: "`fromSeq`
48
+ * absent always means empty replay"), so the setup-time emission is
49
+ * gone before the runner can observe it. The fixture's
50
+ * `inputEnvelope` cannot carry the emission either: an input envelope
51
+ * is by contract a Client→Server wire frame the runner sends on the
52
+ * transport, while emission is server-side (the agent's `ggui_emit`
53
+ * MCP tool) — routing a host directive through the wire-frame slot
54
+ * 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.
39
58
  */
40
59
  export { bootstrapProtocolFixtures } from './bootstrap-protocol/index.js';
41
- export { observabilityEventsFixtures } from './observability-events/index.js';
42
- export { refreshSemanticsFixtures } from './refresh-semantics/index.js';
60
+ export { consumeBufferFixtures } from './consume-buffer/index.js';
61
+ export { hostContextFixtures } from './host-context/index.js';
43
62
  export { reservedChannelAuthorityFixtures } from './reserved-channel-authority/index.js';
44
63
  export { schemaVersionHandshakeFixtures } from './schema-version-handshake/index.js';
45
- export { wiredActionDispatchFixtures } from './wired-action-dispatch/index.js';
64
+ export { subscribeTenancyFixtures } from './subscribe-tenancy/index.js';
46
65
  import { bootstrapProtocolFixtures } from './bootstrap-protocol/index.js';
47
- import { observabilityEventsFixtures } from './observability-events/index.js';
48
- import { refreshSemanticsFixtures } from './refresh-semantics/index.js';
66
+ import { consumeBufferFixtures } from './consume-buffer/index.js';
67
+ import { hostContextFixtures } from './host-context/index.js';
49
68
  import { reservedChannelAuthorityFixtures } from './reserved-channel-authority/index.js';
50
69
  import { schemaVersionHandshakeFixtures } from './schema-version-handshake/index.js';
51
- import { wiredActionDispatchFixtures } from './wired-action-dispatch/index.js';
70
+ import { subscribeTenancyFixtures } from './subscribe-tenancy/index.js';
52
71
  /**
53
72
  * Every fixture the kit ships, grouped by the contract it exercises.
54
73
  * Order within each group matches the sub-module's `export` order.
@@ -59,11 +78,11 @@ import { wiredActionDispatchFixtures } from './wired-action-dispatch/index.js';
59
78
  */
60
79
  export const fixturesByContract = {
61
80
  'bootstrap-protocol': bootstrapProtocolFixtures,
62
- 'observability-events': observabilityEventsFixtures,
63
- 'refresh-semantics': refreshSemanticsFixtures,
81
+ 'consume-buffer': consumeBufferFixtures,
82
+ 'host-context': hostContextFixtures,
64
83
  'reserved-channel-authority': reservedChannelAuthorityFixtures,
65
84
  'schema-version-handshake': schemaVersionHandshakeFixtures,
66
- 'wired-action-dispatch': wiredActionDispatchFixtures,
85
+ 'subscribe-tenancy': subscribeTenancyFixtures,
67
86
  };
68
87
  /**
69
88
  * Every fixture flat, in deterministic lexicographic order by
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/reserved-channel-authority/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qEAAqE;AACrE,eAAO,MAAM,gCAAgC,EAAE,SAAS,QAAQ,EAG/D,CAAC"}
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"}
@@ -3,19 +3,29 @@
3
3
  *
4
4
  * Exercises the reserved-channel contract (SPEC §4.4 Reserved-channel
5
5
  * Authority):
6
- * - Declared-channel schema violations surface as
7
- * `_ggui:contract-error` envelopes with `SCHEMA_VIOLATION` code.
8
6
  * - Channel-0 `props_update` round-trips deliver new props and the
9
7
  * iframe DOM reflects the update.
10
8
  *
11
- * Both fixtures are `ConformanceHost`-gated — `stream-schema-
12
- * violation` drives via malformed-tool setup, `props-update-roundtrip`
13
- * via direct envelope dispatch.
9
+ * One fixture today (`props-update-roundtrip`), `ConformanceHost`-gated
10
+ * via direct envelope dispatch. Additional reserved-channel fixtures
11
+ * (declared-channel schema-violation rejection) land here as the
12
+ * family grows — a kit minor version.
13
+ *
14
+ * ## Declared gap — the namesake MUST is not WS-gradable
15
+ *
16
+ * SPEC §4.4's headline obligation — the server REJECTS agent-authored
17
+ * deliveries on `_ggui:*` reserved channels — cannot even be
18
+ * ATTEMPTED over the channel-3 WebSocket: the Client→Server frame
19
+ * vocabulary has no frame that authors a stream delivery (clients
20
+ * subscribe, dispatch actions, and echo observations; `data` frames
21
+ * are Server→Client only). Agent emission enters through the
22
+ * `ggui_emit` MCP tool, so both the violation and the rejection that
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.
14
26
  */
15
27
  import propsUpdateRoundtrip from './props-update-roundtrip.json' with { type: 'json' };
16
- import streamSchemaViolation from './stream-schema-violation.json' with { type: 'json' };
17
28
  /** All fixtures asserting reserved-channel authority (SPEC §4.4). */
18
29
  export const reservedChannelAuthorityFixtures = [
19
30
  propsUpdateRoundtrip,
20
- streamSchemaViolation,
21
31
  ];
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "props-update-roundtrip",
3
- "description": "Host delivers a `props_update` envelope on channel 0 with a new props payload. The iframe's DOM reflects the new props within `timeoutMs` — evidence on a stamped data-attribute. Proves the host -> iframe props channel is live-wired, complementing the wired-action (iframe -> host) path.",
3
+ "description": "Host delivers a `props_update` envelope on channel 0 with a new props payload. The iframe's DOM reflects the new props within `timeoutMs` — evidence on a stamped data-attribute. Proves the host -> iframe props channel is live, complementing the action-submit (iframe -> host) path.",
4
4
  "skipReason": null,
5
5
  "setup": [
6
- { "type": "create-render", "renderId": "ck-props-update-1" },
6
+ { "type": "create-session", "sessionId": "ck-props-update-1" },
7
7
  {
8
8
  "type": "emit-envelope",
9
9
  "channel": "_ggui:props",
10
10
  "payload": {
11
11
  "type": "props_update",
12
- "renderId": "ck-props-update-1",
12
+ "sessionId": "ck-props-update-1",
13
13
  "props": { "greeting": "initial" }
14
14
  }
15
15
  }
@@ -17,7 +17,7 @@
17
17
  "inputEnvelope": {
18
18
  "type": "props-update",
19
19
  "channel": 0,
20
- "renderId": "ck-props-update-1",
20
+ "sessionId": "ck-props-update-1",
21
21
  "props": { "greeting": "updated-by-host" }
22
22
  },
23
23
  "expectedBehavior": {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/schema-version-handshake/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,yEAAyE;AACzE,eAAO,MAAM,8BAA8B,EAAE,SAAS,QAAQ,EAG7D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/schema-version-handshake/index.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,yEAAyE;AACzE,eAAO,MAAM,8BAA8B,EAAE,SAAS,QAAQ,EAG7D,CAAC"}
@@ -6,10 +6,18 @@
6
6
  * - `UPGRADE_REQUIRED` error frame on mismatch per server's
7
7
  * `versionPolicy` setting.
8
8
  *
9
- * Two fixtures; `version-match` is redundant-by-design with
10
- * `bootstrap-success` on today's harness but authored distinctly so
11
- * a `ConformanceHost` can expose the handshake as a discrete
12
- * assertion slot.
9
+ * Both fixtures declare `subscribe.supportedVersions: 'current'` —
10
+ * the runner resolves the sentinel to the kit's compiled
11
+ * `PROTOCOL_SCHEMA_VERSION`, so the catalog stays evergreen across
12
+ * protocol version bumps (no stale version literals). `version-match`
13
+ * grades BOTH halves of the happy path: the declared set is actually
14
+ * transmitted, and the ack must advertise `serverVersion` equal to
15
+ * the canonical (`expectedBehavior.serverVersion: 'current'`) — it is
16
+ * NOT redundant with `bootstrap-success`, whose ack assertion is
17
+ * versionless. `version-mismatch` grades the rejection half via the
18
+ * `server-version-override` directive: the same 'current' declaration
19
+ * excludes the override by construction, so only the override seam
20
+ * can produce the rejection.
13
21
  */
14
22
  import versionMatch from './version-match.json' with { type: 'json' };
15
23
  import versionMismatch from './version-mismatch.json' with { type: 'json' };
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "version-match",
3
- "description": "Happy-path version handshake: server advertises a schemaVersion the client supports (same as current canonical). Renderer completes the handshake without emitting `ggui:upgrade-required`. Baseline for `version-mismatch`'s negative assertion — proves the handshake path itself is observable.",
3
+ "description": "Happy-path version handshake (SPEC §12.2.2): the runner's subscribe DECLARES `supportedVersions` resolved from the 'current' sentinel (the kit's compiled canonical, evergreen across version bumps), the server's advertised schemaVersion is in the declared set, and the ack ADVERTISES `payload.serverVersion` equal to that canonical. Both halves are graded: an always-reject server fails on the error frame, and a versionless ack (legacy-pass-through, no `serverVersion`) fails the ack-field assertion — the handshake must be observable, not merely not-rejected. The runner-owned subscribe IS the probe (the inputEnvelope is descriptive, not dispatched). Baseline for `version-mismatch`'s negative assertion.",
4
4
  "skipReason": null,
5
- "setup": [{ "type": "create-render", "renderId": "ck-version-match-1" }],
5
+ "setup": [{ "type": "create-session", "sessionId": "ck-version-match-1" }],
6
+ "subscribe": {
7
+ "supportedVersions": "current"
8
+ },
6
9
  "inputEnvelope": {
7
10
  "type": "handshake",
8
- "renderId": "ck-version-match-1",
9
- "clientAccepts": ["1.1"]
11
+ "sessionId": "ck-version-match-1"
10
12
  },
11
13
  "expectedBehavior": {
12
14
  "kind": "bootstrap-success",
13
- "observabilitySequence": []
15
+ "serverVersion": "current"
14
16
  }
15
17
  }
@@ -1,25 +1,24 @@
1
1
  {
2
2
  "name": "version-mismatch",
3
- "description": "Server advertises a protocol schemaVersion outside the client's accepted set. Renderer emits `{type:'ggui:upgrade-required', server, client}` to the parent host + a matching `ProtocolError{kind:'version'}`. Host SHOULD render an inline upgrade prompt — NOT treat this as a terminal failure.",
3
+ "description": "Rejection half of the version handshake (SPEC §12.2.2): the `server-version-override` directive makes the server advertise '99.99-unsupported' for this render, while the runner's subscribe declares `supportedVersions` resolved from the SAME 'current' sentinel as `version-match` — a set that excludes the override by construction (the override literal is never the canonical), so the rejection can only come from the override seam, never from the server's real version. Expected: an `error` frame with `payload.code === 'UPGRADE_REQUIRED'`. Servers on the default reject policy also close the connection; advisory-policy servers keep it open — both satisfy the frame assertion.",
4
4
  "skipReason": null,
5
5
  "setup": [
6
- { "type": "create-render", "renderId": "ck-version-mismatch-1" },
6
+ { "type": "create-session", "sessionId": "ck-version-mismatch-1" },
7
7
  {
8
8
  "type": "server-version-override",
9
- "renderId": "ck-version-mismatch-1",
9
+ "sessionId": "ck-version-mismatch-1",
10
10
  "advertiseVersion": "99.99-unsupported"
11
11
  }
12
12
  ],
13
+ "subscribe": {
14
+ "supportedVersions": "current"
15
+ },
13
16
  "inputEnvelope": {
14
- "type": "render",
15
- "renderId": "ck-version-mismatch-1",
16
- "resource": {
17
- "uri": "ui://ggui/render"
18
- }
17
+ "type": "handshake",
18
+ "sessionId": "ck-version-mismatch-1"
19
19
  },
20
20
  "expectedBehavior": {
21
21
  "kind": "version-mismatch",
22
- "serverVersion": "99.99-unsupported",
23
- "clientAccepts": ["1.1"]
22
+ "serverVersion": "99.99-unsupported"
24
23
  }
25
24
  }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "absent-appid-defaults",
3
+ "description": "A subscribe that OMITS `appId` resolves the caller's identity-default app and acks. SPEC §12.2's subscribe-payload table makes `appId` optional: absent ⇒ the server resolves it from the connection's authenticated identity (token binding, else identity mapping, else the deployment default) — clients never invent the default. Under the kit's harness the identity-default is the conventional tenant 'conformance', so the provision-on-subscribe path must bind exactly that value to the fresh render row — a real string tenant, never an undefined one (the corrupt-row failure mode this fixture locks out: a silent ack whose provisioned row carries appId undefined, unreachable by any later legal subscribe). The runner-owned subscribe frame IS the probe (`subscribe.omitAppId` drops the runner's conventional appId stamp; the inputEnvelope is descriptive, not dispatched); graded as a session-state read-back of the bound `appId` through the host's readSessionField seam. The §12.2.3 APP_MISMATCH tenancy gate is the sibling `app-mismatch` fixture's claim and still applies to the RESOLVED value.",
4
+ "skipReason": null,
5
+ "setup": [],
6
+ "subscribe": {
7
+ "omitAppId": true
8
+ },
9
+ "inputEnvelope": {
10
+ "type": "handshake",
11
+ "sessionId": "ck-absent-appid-1"
12
+ },
13
+ "expectedBehavior": {
14
+ "kind": "session-state",
15
+ "field": "appId",
16
+ "expected": "conformance"
17
+ }
18
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "app-mismatch",
3
+ "description": "The GguiSession exists but is bound to a DIFFERENT app than the subscriber claims: `create-session` binds appId 'conformance-other', while the kit's runner always subscribes with appId 'conformance'. SPEC §12.2's subscribe-payload table makes the tenancy check a MUST — appId 'MUST match the GguiSession's bound appId or subscribe fails APP_MISMATCH' — and §12.2.3 keeps the code distinct from SESSION_NOT_FOUND (the GguiSession exists; it is reachable only from a different app), so clients route 'fix your appId / API key' differently from 're-handshake'. The runner-owned subscribe frame IS the probe (the inputEnvelope is descriptive, not dispatched); expected: an `error` frame with `payload.code === 'APP_MISMATCH'`.",
4
+ "skipReason": null,
5
+ "setup": [
6
+ {
7
+ "type": "create-session",
8
+ "sessionId": "ck-app-mismatch-1",
9
+ "appId": "conformance-other"
10
+ }
11
+ ],
12
+ "inputEnvelope": {
13
+ "type": "handshake",
14
+ "sessionId": "ck-app-mismatch-1"
15
+ },
16
+ "expectedBehavior": {
17
+ "kind": "error-frame",
18
+ "code": "APP_MISMATCH"
19
+ }
20
+ }
@@ -0,0 +1,6 @@
1
+ import type { TestCase } from '../../types.js';
2
+ /** All fixtures asserting subscribe-time tenancy (SPEC §12.2 field
3
+ * table — identity-default resolution on absent `appId` — and
4
+ * §12.2.3 `APP_MISMATCH`). */
5
+ export declare const subscribeTenancyFixtures: readonly TestCase[];
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fixtures/subscribe-tenancy/index.ts"],"names":[],"mappings":"AAwDA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;+BAE+B;AAC/B,eAAO,MAAM,wBAAwB,EAAE,SAAS,QAAQ,EAGvD,CAAC"}