@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.
- package/README.md +32 -13
- package/dist/cli.d.ts +11 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +48 -20
- package/dist/conformance-host.d.ts +81 -76
- package/dist/conformance-host.d.ts.map +1 -1
- package/dist/conformance-host.js +0 -44
- package/dist/fixtures/bootstrap-protocol/bootstrap-bundle-fetch-failed.json +3 -3
- package/dist/fixtures/bootstrap-protocol/bootstrap-meta-missing.json +3 -3
- package/dist/fixtures/bootstrap-protocol/bootstrap-success.json +3 -3
- package/dist/fixtures/consume-buffer/action-ack-sequence.json +28 -0
- package/dist/fixtures/consume-buffer/action-payload-schema-violation.json +37 -0
- package/dist/fixtures/consume-buffer/index.d.ts +6 -0
- package/dist/fixtures/consume-buffer/index.d.ts.map +1 -0
- package/dist/fixtures/consume-buffer/index.js +41 -0
- package/dist/fixtures/consume-buffer/undeclared-action-rejected.json +29 -0
- package/dist/fixtures/host-context/host-context-observed-persists.json +34 -0
- package/dist/fixtures/host-context/index.d.ts +5 -0
- package/dist/fixtures/host-context/index.d.ts.map +1 -0
- package/dist/fixtures/host-context/index.js +40 -0
- package/dist/fixtures/index.d.ts +28 -9
- package/dist/fixtures/index.d.ts.map +1 -1
- package/dist/fixtures/index.js +33 -14
- package/dist/fixtures/reserved-channel-authority/index.d.ts.map +1 -1
- package/dist/fixtures/reserved-channel-authority/index.js +17 -7
- package/dist/fixtures/reserved-channel-authority/props-update-roundtrip.json +4 -4
- package/dist/fixtures/schema-version-handshake/index.d.ts.map +1 -1
- package/dist/fixtures/schema-version-handshake/index.js +12 -4
- package/dist/fixtures/schema-version-handshake/version-match.json +7 -5
- package/dist/fixtures/schema-version-handshake/version-mismatch.json +9 -10
- package/dist/fixtures/subscribe-tenancy/absent-appid-defaults.json +18 -0
- package/dist/fixtures/subscribe-tenancy/app-mismatch.json +20 -0
- package/dist/fixtures/subscribe-tenancy/index.d.ts +6 -0
- package/dist/fixtures/subscribe-tenancy/index.d.ts.map +1 -0
- package/dist/fixtures/subscribe-tenancy/index.js +62 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/match-behavior.d.ts +19 -100
- package/dist/match-behavior.d.ts.map +1 -1
- package/dist/match-behavior.js +289 -246
- package/dist/registration-conformance/cases/gate-duplicate-hook.json +26 -0
- package/dist/registration-conformance/cases/gate-export-not-registered.json +1 -0
- package/dist/registration-conformance/cases/gate-multi-package-distinct-names-accept.json +26 -0
- package/dist/registration-conformance/cases/gate-no-gadgets-accept.json +1 -0
- package/dist/registration-conformance/cases/gate-package-mismatch.json +1 -0
- package/dist/registration-conformance/cases/gate-priority-not-registered-outranks-mismatch.json +1 -0
- package/dist/registration-conformance/cases/gate-priority-registry-outranks-public-env.json +22 -0
- package/dist/registration-conformance/cases/gate-public-env-missing.json +21 -0
- package/dist/registration-conformance/cases/gate-public-env-satisfied-accept.json +21 -0
- package/dist/registration-conformance/cases/gate-public-env-undeclared-wrapper-accept.json +26 -0
- package/dist/registration-conformance/cases/gate-registered-resolves-accept.json +1 -0
- package/dist/registration-conformance/cases/gate-stdlib-hook-accept.json +1 -0
- package/dist/registration-conformance/cases/gate-typo-classifies-as-not-registered.json +1 -0
- package/dist/registration-conformance/index.d.ts +64 -33
- package/dist/registration-conformance/index.d.ts.map +1 -1
- package/dist/registration-conformance/index.js +24 -8
- package/dist/run-conformance.d.ts +145 -6
- package/dist/run-conformance.d.ts.map +1 -1
- package/dist/run-conformance.js +531 -93
- package/dist/types.d.ts +319 -165
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +27 -23
- package/dist/ws-transport.d.ts.map +1 -1
- package/dist/ws-transport.js +3 -2
- package/package.json +3 -3
- package/dist/fixtures/observability-events/index.d.ts +0 -5
- package/dist/fixtures/observability-events/index.d.ts.map +0 -1
- package/dist/fixtures/observability-events/index.js +0 -22
- package/dist/fixtures/observability-events/observability-contract-error-emitted.json +0 -28
- package/dist/fixtures/observability-events/observability-wired-tool-invoked.json +0 -27
- package/dist/fixtures/refresh-semantics/index.d.ts +0 -5
- package/dist/fixtures/refresh-semantics/index.d.ts.map +0 -1
- package/dist/fixtures/refresh-semantics/index.js +0 -19
- package/dist/fixtures/refresh-semantics/stream-refresh-success.json +0 -39
- package/dist/fixtures/reserved-channel-authority/stream-schema-violation.json +0 -44
- package/dist/fixtures/wired-action-dispatch/index.d.ts +0 -5
- package/dist/fixtures/wired-action-dispatch/index.d.ts.map +0 -1
- package/dist/fixtures/wired-action-dispatch/index.js +0 -29
- package/dist/fixtures/wired-action-dispatch/wired-action-success.json +0 -35
- package/dist/fixtures/wired-action-dispatch/wired-action-tool-not-found.json +0 -30
- package/dist/fixtures/wired-action-dispatch/wired-action-tool-threw.json +0 -31
- 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 @@
|
|
|
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
|
+
];
|
package/dist/fixtures/index.d.ts
CHANGED
|
@@ -20,11 +20,10 @@
|
|
|
20
20
|
*
|
|
21
21
|
* ## Current coverage
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
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 {
|
|
42
|
-
export {
|
|
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 {
|
|
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' | '
|
|
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
|
|
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"}
|
package/dist/fixtures/index.js
CHANGED
|
@@ -20,11 +20,10 @@
|
|
|
20
20
|
*
|
|
21
21
|
* ## Current coverage
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
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 {
|
|
42
|
-
export {
|
|
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 {
|
|
64
|
+
export { subscribeTenancyFixtures } from './subscribe-tenancy/index.js';
|
|
46
65
|
import { bootstrapProtocolFixtures } from './bootstrap-protocol/index.js';
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
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 {
|
|
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
|
-
'
|
|
63
|
-
'
|
|
81
|
+
'consume-buffer': consumeBufferFixtures,
|
|
82
|
+
'host-context': hostContextFixtures,
|
|
64
83
|
'reserved-channel-authority': reservedChannelAuthorityFixtures,
|
|
65
84
|
'schema-version-handshake': schemaVersionHandshakeFixtures,
|
|
66
|
-
'
|
|
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":"
|
|
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
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
|
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-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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":"
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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:
|
|
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-
|
|
5
|
+
"setup": [{ "type": "create-session", "sessionId": "ck-version-match-1" }],
|
|
6
|
+
"subscribe": {
|
|
7
|
+
"supportedVersions": "current"
|
|
8
|
+
},
|
|
6
9
|
"inputEnvelope": {
|
|
7
10
|
"type": "handshake",
|
|
8
|
-
"
|
|
9
|
-
"clientAccepts": ["1.1"]
|
|
11
|
+
"sessionId": "ck-version-match-1"
|
|
10
12
|
},
|
|
11
13
|
"expectedBehavior": {
|
|
12
14
|
"kind": "bootstrap-success",
|
|
13
|
-
"
|
|
15
|
+
"serverVersion": "current"
|
|
14
16
|
}
|
|
15
17
|
}
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "version-mismatch",
|
|
3
|
-
"description": "
|
|
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-
|
|
6
|
+
{ "type": "create-session", "sessionId": "ck-version-mismatch-1" },
|
|
7
7
|
{
|
|
8
8
|
"type": "server-version-override",
|
|
9
|
-
"
|
|
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": "
|
|
15
|
-
"
|
|
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"}
|