@ggui-ai/protocol 0.15.0 → 0.16.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 (75) hide show
  1. package/dist/errors/domain-error.d.ts +70 -0
  2. package/dist/errors/domain-error.d.ts.map +1 -0
  3. package/dist/errors/domain-error.js +118 -0
  4. package/dist/gadgets/stdlib-gadgets.d.ts +1 -1
  5. package/dist/gadgets/stdlib-gadgets.js +1 -1
  6. package/dist/index.d.ts +3 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +4 -2
  9. package/dist/integrations/mcp-apps.d.ts +33 -7
  10. package/dist/integrations/mcp-apps.d.ts.map +1 -1
  11. package/dist/integrations/mcp-apps.js +13 -13
  12. package/dist/integrations/overlay-hash.d.ts +19 -0
  13. package/dist/integrations/overlay-hash.d.ts.map +1 -0
  14. package/dist/integrations/overlay-hash.js +29 -0
  15. package/dist/integrations/theme-binding.d.ts +14 -12
  16. package/dist/integrations/theme-binding.d.ts.map +1 -1
  17. package/dist/integrations/theme-binding.js +10 -6
  18. package/dist/registry/blueprint-key.d.ts.map +1 -1
  19. package/dist/registry/blueprint-key.js +4 -3
  20. package/dist/schemas/app-theme.d.ts +46 -10
  21. package/dist/schemas/app-theme.d.ts.map +1 -1
  22. package/dist/schemas/app-theme.js +108 -40
  23. package/dist/schemas/blueprint.d.ts +2 -1
  24. package/dist/schemas/blueprint.d.ts.map +1 -1
  25. package/dist/schemas/blueprint.js +15 -3
  26. package/dist/schemas/data-contract.d.ts +1 -1
  27. package/dist/schemas/data-contract.js +1 -1
  28. package/dist/schemas/handshake-suggestion.d.ts.map +1 -1
  29. package/dist/schemas/handshake-suggestion.js +8 -1
  30. package/dist/schemas/mcp.d.ts +48 -22
  31. package/dist/schemas/mcp.d.ts.map +1 -1
  32. package/dist/schemas/mcp.js +44 -15
  33. package/dist/schemas/ops-blueprint.d.ts +4 -4
  34. package/dist/schemas/ops-blueprint.d.ts.map +1 -1
  35. package/dist/schemas/ops-blueprint.js +13 -8
  36. package/dist/schemas/render-input-envelope.js +1 -1
  37. package/dist/types/blueprint-source.d.ts +27 -7
  38. package/dist/types/blueprint-source.d.ts.map +1 -1
  39. package/dist/types/blueprint-source.js +19 -3
  40. package/dist/types/blueprint.d.ts +2 -2
  41. package/dist/types/blueprint.d.ts.map +1 -1
  42. package/dist/types/data-contract.d.ts +3 -3
  43. package/dist/types/domain-error-codes.d.ts +167 -0
  44. package/dist/types/domain-error-codes.d.ts.map +1 -0
  45. package/dist/types/domain-error-codes.js +170 -0
  46. package/dist/types/handshake-suggestion.d.ts +2 -2
  47. package/dist/types/live-channel.d.ts +1 -1
  48. package/dist/types/llm-route.d.ts +59 -2
  49. package/dist/types/llm-route.d.ts.map +1 -1
  50. package/dist/types/llm-route.js +62 -16
  51. package/dist/types/llm.d.ts +22 -2
  52. package/dist/types/llm.d.ts.map +1 -1
  53. package/dist/types/llm.js +29 -2
  54. package/dist/types/mcp.d.ts +31 -39
  55. package/dist/types/mcp.d.ts.map +1 -1
  56. package/dist/types/mcp.js +22 -10
  57. package/dist/types/refusal-codes.d.ts +31 -93
  58. package/dist/types/refusal-codes.d.ts.map +1 -1
  59. package/dist/types/refusal-codes.js +41 -96
  60. package/dist/types/render.d.ts +3 -3
  61. package/dist/types/render.d.ts.map +1 -1
  62. package/dist/validation/contract-validator.d.ts +8 -2
  63. package/dist/validation/contract-validator.d.ts.map +1 -1
  64. package/dist/validation/contract-validator.js +12 -4
  65. package/dist/validation/lint-contract.d.ts +2 -2
  66. package/dist/validation/lint-contract.d.ts.map +1 -1
  67. package/dist/validation/lint-contract.js +6 -4
  68. package/dist/validation/schema-subset.d.ts +3 -3
  69. package/dist/version.d.ts +357 -6
  70. package/dist/version.d.ts.map +1 -1
  71. package/dist/version.js +356 -5
  72. package/package.json +1 -1
  73. package/dist/envelope-adapters.d.ts +0 -12
  74. package/dist/envelope-adapters.d.ts.map +0 -1
  75. package/dist/envelope-adapters.js +0 -30
package/dist/version.js CHANGED
@@ -6,6 +6,343 @@
6
6
  * schema change; the most recent change anchors {@link PROTOCOL_VERSION}.
7
7
  *
8
8
  * --------------------------------------------------------------------
9
+ * Theming revision — the overlay is the projection, the host owns runtime
10
+ * mode (2026-09-10, ggui#987 — **BREAKING on the draft wave**, named by the
11
+ * conformance kit: `protocol-conformance/src/theme-binding-conformance`
12
+ * promoted today's pins in the prior commit, and this change fails them —
13
+ * VERSION-POLICY §1.1; shipped under §1.4's `draft-` clause, §3.5's window
14
+ * waived pre-v1.0). Founder rulings D1–D7 (2026-09-09/10), joint spec
15
+ * `docs/superpowers/specs/2026-09-09-theming-revision-protocol-half.md`.
16
+ * `appThemeSchema` v2: `overlays: { light, dark }` REQUIRED (the derived
17
+ * projection for both modes — one producer, `@ggui-ai/design`'s
18
+ * `deriveThemeVariables`), `overlayHash` REQUIRED (`canonicalOverlayHash`,
19
+ * recomputed at every write door), `mode` optional and a DEFAULT only,
20
+ * `name` a label; `base` DELETED with the registration tier (D2 = B). The
21
+ * client projection of `themeMode` flips — `hostAnnounced ?? stamped ??
22
+ * sessionSidecar` (D4 = A: M1 + M2, "follow the widget") — the server stamp
23
+ * is unchanged; `themeId` loses its `sidecarName` leg. `AppThemeRefusalBody`
24
+ * is the one write-door refusal shape. `parseMcpAppAiGguiRenderMeta` gains
25
+ * `onInvalidTheme` so the read door is never silent. The render shell paints
26
+ * `--ggui-color-ground` (the surface-layering roles of §2.1).
27
+ * --------------------------------------------------------------------
28
+ * Model registry: `openai/gpt-6-astra` (2026-09-09, additive, ggui#977 —
29
+ * MINOR; Exp 008's founder-ruled second arm, ggui#972). One new `ModelId`
30
+ * union member and one `MODELS.openai` allowlist entry; premium, active,
31
+ * not in the lineup; costs 10 / 50 / 12.5 / 1.0 per 1M (input / output /
32
+ * cache write / cache read), `maxTokens` 922000, tools — every field a
33
+ * receipt on the issue; `retireNotBefore` unset (none published).
34
+ * --------------------------------------------------------------------
35
+ * Refusal registry v11 — the retail plan model retired (2026-09-08,
36
+ * wire-code, pre-launch, ggui#960 — MINOR on the 0.16.0 draft wave; the
37
+ * protocol half of the pricing publication ggui#949, WITH cloud's arm
38
+ * deletion). Founder's ruling: one product, prepaid pay-as-you-go at flat
39
+ * rates, trial and tiers retired, the welcome credit as the free entry.
40
+ * Eleven codes lose their emitting arms and retire in the same slice —
41
+ * render-gate `trial_exhausted`, `trial_expired`, `app_canceled`
42
+ * (`RENDER_GATE_REFUSAL_CODES` 14 → 11); owner-api `subscription_exists`,
43
+ * `no_subscription`, `subscription_unchanged`, `portal_unavailable`,
44
+ * `card_update_unavailable`, `managed_app_no_portal`,
45
+ * `managed_app_no_card_update`, `managed_app_no_checkout` (9 → 1: the
46
+ * prepaid wallet's one Stripe surface is the top-up, user-scoped). Four
47
+ * rows re-described in the new model's words: `billing_path_missing`,
48
+ * `model_not_allowed` (per-account grant), `checkout_unavailable`
49
+ * (top-ups), `insufficient_credit` (pool or BYOK). New typed exports
50
+ * `OWNER_API_REFUSAL_CODES` + `OwnerApiRefusalCode`. Not breaking under
51
+ * §2: pre-launch draft wave, every retired code had lost its emitter in
52
+ * the same publication; the kit's non-render-surface case re-aims to the
53
+ * surviving owner-api code. `managed_default_cap_exceeded` stays (ggui#965).
54
+ * --------------------------------------------------------------------
55
+ * Blueprint provenance de-modeled (2026-09-06, wire-tightening, pre-launch,
56
+ * ggui#924 — MINOR; half of ggui#923, one WITH publication across six
57
+ * lanes). `LlmBlueprintSource.generator` is the identity `ui-gen-<tier>`
58
+ * (one tier token — `ui-gen-default` / `ui-gen-advanced` / an operator
59
+ * tier; `GENERATOR_ID_PATTERN`, `isGeneratorId`) and `model` is the run's route
60
+ * in the registry's spelling (`ModelRef` = `<prefix>/<model>`, composed only
61
+ * by `modelRefOfRoute`, recovered by `parseModelRef`; registry `ModelId`s
62
+ * are the subset — a self-hoster's bedrock/OpenRouter route is a ref the
63
+ * registry does not list; `MODEL_IDS`, `isModelId` narrow to the subset).
64
+ * Before: both were `string`, and the identity embedded the model
65
+ * (`ui-gen-default-haiku-4-5`) — a model retirement (Haiku 4.5,
66
+ * 2026-10-15) would rename the identity against every stored record.
67
+ * `parseBlueprintSource` and `llmBlueprintSourceSchema` refuse a modeled
68
+ * identity and a bare model name; the handshake draft's `generator` hint
69
+ * and the operator tools' `generator` inputs take the same grammar. No
70
+ * alias, no dual-read (pre-launch): a row written before the rename reads
71
+ * as no provenance; stores reseed. Not breaking under VERSION-POLICY §2
72
+ * (no kit fixture asserts a modeled id or a bare model); MINOR under §1.2
73
+ * as a schema tightening on the 0.16.0 draft wave. Post-launch this would
74
+ * be a MAJOR with a migration doc and a dual-read shim — the reason it
75
+ * ships now.
76
+ * --------------------------------------------------------------------
77
+ * Five phantom numeric codes retired-reserved + the emitter census
78
+ * (2026-09-06, wire-code, pre-launch, ggui#910 — PATCH). `CAPABILITY_DENIED`
79
+ * (-32005), `GENERATION_QUOTA_EXCEEDED` (-32010), `APP_LIMIT_EXCEEDED`
80
+ * (-32011), `CONCURRENT_SESSION_LIMIT` (-32012) and the numeric
81
+ * `CONTRACT_VIOLATION` (-32020 — the census found it once the gate
82
+ * existed; the live `CONTRACT_VIOLATION` is a string on the channel and
83
+ * the Plane-3 render error, and tools/call has Plane-2
84
+ * `contract_violation`) were declared,
85
+ * SPEC-fenced and mirrored into four tables, and emitted by nothing
86
+ * first-party — a census by constant and by number over oss/packages,
87
+ * cloud and backend. The constants leave; the numbers stay reserved
88
+ * (SPEC §7.9); an unauthorised key is a bare 403 carrying -32007; quota,
89
+ * app-limit and concurrency states are refusals or implementation-range
90
+ * codes. Cheap only before launch: after the `draft-` rule flips each
91
+ * removal would be a MAJOR with a migration doc. The mirrors gate now
92
+ * also asserts the inverse — every declared non-standard code has a
93
+ * first-party emitter (one `git grep` per code; seeded self-test) — so a
94
+ * phantom cannot be declared again silently. Pinned by
95
+ * `types/__tests__/retired-error-codes.test.ts` (eight retired numbers).
96
+ * Not breaking under VERSION-POLICY §2; PATCH under §1.3.
97
+ * --------------------------------------------------------------------
98
+ *
99
+ * --------------------------------------------------------------------
100
+ * `-32013 RATE_LIMIT_EXCEEDED` retired-reserved (2026-09-06, wire-code,
101
+ * pre-launch, ggui#890 — PATCH). After ggui#886 (the per-app cap denies as
102
+ * the registry's `app_rate_limited` refusal) and the `RateLimitedError`
103
+ * deletion, no first-party implementation emits the number: the reference
104
+ * server refuses in-band, the hosted transport's only 429 is a per-IP
105
+ * backstop with no JSON-RPC body. The constant leaves
106
+ * `PLATFORM_ERROR_CODES` and SPEC §7.9's platform fence; the number stays
107
+ * reserved (the `-32001` / `-32004` convention) so no future canonical code
108
+ * reuses it. Not breaking under VERSION-POLICY §2 — no kit fixture asserts
109
+ * it; PATCH under §1.3. Pinned by `types/__tests__/retired-error-codes.test.ts`
110
+ * (no constant declares a retired number; no tracked source emits one) and
111
+ * by the mirrors gate, which reds the docs tables' rows until they leave
112
+ * in the same publication.
113
+ *
114
+ * --------------------------------------------------------------------
115
+ * The registries export their literal-typed rows (2026-09-06, types-only,
116
+ * pre-launch, ggui#889 — PATCH). `PRE_GENERATION_REFUSAL_CODES` and
117
+ * `DOMAIN_ERROR_REGISTRY` are the normalized views (`Record<Code, Row>`),
118
+ * which erase the per-key literal the `const` definers preserve — so a
119
+ * producer that must satisfy a wire enum from a row had to parse it
120
+ * through the enum (ggui#886). `PRE_GENERATION_REFUSAL_ROWS` and
121
+ * `DOMAIN_ERROR_ROWS` are the SAME objects with the literal types kept:
122
+ * each row's `code` is typed as its own key. No wire change;
123
+ * the kit's registry-completeness catalog reads the normalized view as
124
+ * before. Not breaking under VERSION-POLICY §2; PATCH under §1.3.
125
+ *
126
+ * --------------------------------------------------------------------
127
+ * Plane-2 slugs lead the wire text (2026-09-06, wire-text, pre-launch,
128
+ * ggui#880 — MINOR). SPEC
129
+ * §7.9 promised "the `code` field on each class is the wire literal"
130
+ * while the MCP SDK ships every thrown handler error to the agent as
131
+ * `{content: [{type: 'text', text: error.message}], isError: true}` and
132
+ * nothing else — executed against the built server: `session_not_found`
133
+ * and `handshake_not_found` reached neither a field nor the text, and
134
+ * descriptions, presets and the SPEC taught agents to branch on them.
135
+ *
136
+ * de1. **`DomainError` base** (`errors/domain-error.ts`) — the ONLY
137
+ * composer of a Plane-2 error's `message`: `${code}: ${detail}`.
138
+ * Refuses an empty detail and a detail that begins with any
139
+ * registered domain OR refusal code + `': '`
140
+ * (`DomainErrorDetailCollisionError`, a `TypeError` the emitter's
141
+ * own suite sees — never the wire); a tool-name prefix is prose.
142
+ * `isDomainError` detects by `Symbol.for('ai.ggui.domainError')`
143
+ * marker + shape, never `instanceof`; `parseDomainErrorText` is
144
+ * the reader side.
145
+ * de2. **`DOMAIN_ERROR_CODES` registry** (`types/domain-error-codes.ts`)
146
+ * — the CLOSED Plane-2 set, fifteen rows from the executed census,
147
+ * each with the data-plane `tools` that emit it, a `recovery` class
148
+ * (`retry-same-id` | `re-mint` | `later`), an `emitter` and a
149
+ * self-hoster `description`. Pinned disjoint from
150
+ * `PRE_GENERATION_REFUSAL_CODES` (one code, one plane). SPEC §7.9's
151
+ * Plane-2 table is its mirror (pinned from the registry's own suite):
152
+ * the four phantom classes the table listed (`ContractRequiredError`,
153
+ * `ContractHashMismatchError`, `UnknownActionToolError`,
154
+ * `EventNotAllowedError`) are gone; `cross_reference_unresolved` /
155
+ * `contract_schema_invalid` are not wire codes (no caller throws
156
+ * them — the lint gate throws `contract_validation_failed`).
157
+ * de3. **The two protocol-owned emitters extend the base** —
158
+ * `ContractViolationError` (`contract_violation`; `toErrorData()`
159
+ * keeps its `{error, tool, violations, hint, propsSchemaHash?}`
160
+ * shape) and `ContractValidationError` (`contract_validation_failed`,
161
+ * phase + issues kept). Consumers detecting them by `instanceof`
162
+ * are unchanged; their message now leads with the slug.
163
+ * de4. **The wire plane is the MCP spec's** — a Plane-2 failure is a
164
+ * tool RESULT with `isError: true`, never a JSON-RPC error frame;
165
+ * no `structuredContent` (the SDK client validates it against the
166
+ * tool's `outputSchema` whenever present, so a typed envelope would
167
+ * demote every success field to optional — refused). SPEC §7.9.1:
168
+ * `SESSION_NOT_FOUND` (-32002) is the live-channel / runtime Plane-1
169
+ * code; on `tools/call` the same state is `session_not_found`.
170
+ * de5. **The conformance kit's first `tools/call` driver** — catalog
171
+ * `domain-error`: six no-setup scenarios (unknown `handshakeId` on
172
+ * `ggui_render`; unknown `sessionId` on `ggui_consume` /
173
+ * `ggui_get_session` / `ggui_update` / `ggui_amend` / `ggui_emit`)
174
+ * graded on the raw result via `runConformance({ toolCallDriver })`
175
+ * / `--tool-call-driver <module>`. Before this wave every first-party
176
+ * server failed all six on `slug-leads`.
177
+ *
178
+ * Conformance-kit verdict: not breaking under VERSION-POLICY §2 — no
179
+ * prior fixture asserts Plane-2 text; the leading slug is additive to
180
+ * prose and the new catalog is an addition. MINOR under §1.2 (new
181
+ * exported base, registry and kit catalog); rides the 0.16.0 wave. The
182
+ * adoption of the base by the handler / core / mcp-server classes lands
183
+ * WITH this entry (oss's half of ggui#880); until both are on a server,
184
+ * that server fails the catalog — which is the point.
185
+ *
186
+ * --------------------------------------------------------------------
187
+ * The pending-event row is a schema (2026-09-06, store-boundary, pre-launch,
188
+ * ggui#839 — the #817 C2 follower; cite `3f3d86b86`). The consume pipe's
189
+ * stored row — what `submit_action` / the WS ingress append and
190
+ * `PendingEventConsumer.consumeAndClear` drains — was a hand-written
191
+ * interface the adapters typed as `Record<string, unknown>` and the consume
192
+ * handler coerced with defaults; nothing validated it. A store-boundary
193
+ * contract (producers ↔ adapters ↔ the consume handler), never wire:
194
+ * `ggui_consume` returns the entries, never the wrapper.
195
+ *
196
+ * pe1. **`pendingEventSchema` + `PendingEvent` derived** —
197
+ * `{ id: string.min(1), envelope: consumeEventEntrySchema, createdAt:
198
+ * string }`; `createdAt` stays a string (the relay copies a client
199
+ * `firedAt` the ingress accepts as a diagnostic).
200
+ * pe2. **`sequence` deleted** — zero writers (both producers append
201
+ * `{id, envelope, createdAt}`; sqlite's `seq` never joined the row;
202
+ * the pod stores the literal), zero readers (the only read was the
203
+ * handler's own default-to-0), named in neither SPEC nor the kit.
204
+ * pe3. **`id` required and non-empty** — the drain_ack key and the
205
+ * idempotency key per `(sessionId, id)`; the id-less append branches
206
+ * (core docstring, in-memory, sqlite, the pod's `ddb.ts`) deleted in
207
+ * the same publication.
208
+ * pe4. **No string envelope arm** — every writer passes the object; a
209
+ * store that serializes the whole row. `parsePendingEnvelope`
210
+ * collapsed into the row parse (`envelope-adapters.ts` deleted).
211
+ * pe5. **`PendingEventMalformedError` + the per-adapter failure mode** —
212
+ * `consumeAndClear` MUST NOT return a row that fails the schema and
213
+ * MUST NOT drop a well-formed row because a sibling failed: a
214
+ * transactional drain (sqlite) refuses whole and rolls back; a
215
+ * destructive drain (DynamoDB) quarantines per row with a
216
+ * `pending_event_malformed` structured log; in-memory holds the typed
217
+ * struct it validated on append. `append` refuses a malformed row
218
+ * before storing it. The consume handler maps the error to a
219
+ * `HandlerFailure` carrying `{ events: [], status }`, never a JSON-RPC
220
+ * error, and the parse runs before any `drain_ack` fires.
221
+ *
222
+ * Conformance-kit verdict: not breaking under VERSION-POLICY §2 — the kit
223
+ * never names the wrapper (`git grep PendingEvent -- oss/packages/protocol-conformance`
224
+ * = 0); its only `sequence` is the `action-ack-sequence` fixture's WS ack
225
+ * `payload.sequence`, the ledger's `appendEvent` seq, never the pipe row's
226
+ * deleted field. The observable
227
+ * violation is `@ggui-ai/mcp-server-core`'s published contract-tests suite
228
+ * (a seeded malformed row is refused or quarantined per form). PATCH-class
229
+ * under §1.3 for `@ggui-ai/protocol`; rides the 0.16.0 wave.
230
+ *
231
+ * --------------------------------------------------------------------
232
+ * The endpoint-level refusal carries the app as DATA (2026-09-05, wire
233
+ * field, pre-launch, ggui#870 — the ggui#782 ↔ guuey#708 re-sitting's
234
+ * D6, guuey#836's blocker). `transportRefusalSchema` — what rides
235
+ * `error.data.refusal` on a per-app endpoint's typed 403 (ggui#825/#836)
236
+ * — was strict `{ code, message, fix, retry }` with the app named only
237
+ * in `message`; a tenant's repair loop cannot parse prose safely.
238
+ *
239
+ * ai1. **`data.refusal.appId: string` — REQUIRED** — the app id the
240
+ * refused endpoint serves, equal to the endpoint path's `{appId}`.
241
+ * The ggui id the bound caller already holds, never the tenant's
242
+ * own `ownerRef`; the tenant maps it to its own id from the
243
+ * `gguiAppId` it stored at create. Required, not optional: a field
244
+ * a repair loop cannot rely on is a hope, not a contract.
245
+ *
246
+ * ai2. **Who receives the typed face** (the fact from the pod's code,
247
+ * ggui#812 identity-first): a correctly bound federated identity
248
+ * only — an anonymous request is refused by the auth adapter as
249
+ * 401 before this arm and learns nothing about the app; a native
250
+ * key mismatch gets the bare default-deny 403. SPEC §7.1's
251
+ * endpoint paragraph says so now; the anonymous typed face is
252
+ * deliberately not a contract (it would trade disclosure).
253
+ *
254
+ * Conformance-kit verdict: BREAKING by the letter of VERSION-POLICY §2 —
255
+ * the kit's `transport-refusal` cases now carry `appId` and the strict
256
+ * schema refuses a projection without it, so an emitter built against
257
+ * 0.15.0 fails the 0.16.0 kit — and, the wire being `z.strictObject`, a
258
+ * 0.15.0 STRICT reader of the body is failed by a 0.16.0 emitter too
259
+ * (zero such readers exist today; guuey's is step 3, not started). Shipped under §1.4's `draft-` clause in
260
+ * the 0.16.0 wave; the pod's emitter (cloud, ggui#870's other half)
261
+ * lands WITH this change, after the tombstone fix for ggui#785/G26.
262
+ *
263
+ * Package version — classification MADE here: MAJOR-class change carried
264
+ * by a MINOR wave under `draft-` (§1.4) for `@ggui-ai/protocol` and
265
+ * `@ggui-ai/protocol-conformance`. PROTOCOL_VERSION unchanged — no WS
266
+ * envelope moved.
267
+ *
268
+ * --------------------------------------------------------------------
269
+ * Two refusal codes lose the word "tier" (2026-09-05, rename, pre-launch,
270
+ * ggui#802 — #786 review finding F6). A code name ships to npm and, for a
271
+ * render-gate code, reaches every self-hoster's LLM as JSON-Schema enum
272
+ * metadata on `tools/list`; "tier" names a plan ladder a self-hoster does
273
+ * not have (docs/principles/oss-purity.md, the type-literal class). Ruled
274
+ * by a three-lens judge panel under the registry's naming rules:
275
+ *
276
+ * rt1. **`model_not_in_tier` → `model_not_allowed`** (render-gate,
277
+ * after-fix, fixBy caller) — the state the row's own description,
278
+ * the kit case's `fix` and SPEC §7.9 already name ("not among those
279
+ * the app is allowed to use"); subject-first like the rest of the
280
+ * registry; true on a deployment with one allow-list per app and no
281
+ * prices. Not `model_not_available`: `*_unavailable` is this
282
+ * registry's `later` / operator class, the wrong retry class for the
283
+ * one code an agent may act on itself.
284
+ *
285
+ * rt2. **`already_on_tier` → `subscription_unchanged`** (owner-api,
286
+ * after-fix, fixBy owner) — the owner-api noun the registry already
287
+ * uses (`subscription_exists`, `no_subscription`); the state is
288
+ * "requested == held", no ladder word.
289
+ *
290
+ * rt3. `tier_unrecognized` is NOT a registry code (deleted from the
291
+ * wire at registry v9): a backend allowance state read by the
292
+ * console, whose column is literally `tier`. Unchanged.
293
+ *
294
+ * Conformance-kit verdict: BREAKING by the letter of VERSION-POLICY §2 —
295
+ * the kit's `refuse-after-fix-caller` case pinned the old name, so an
296
+ * emitter built against 0.15.0 fails the 0.16.0 kit's `renderRefusalSchema`
297
+ * enum. Shipped under §1.4's `draft-` clause (semver describes intent
298
+ * pre-v1) in the 0.16.0 wave, with the changelog's Unreleased section
299
+ * naming the move; every mirror moves in one change (the kit case, SPEC,
300
+ * the docs, the console's copy, the backend's owner-api refusals, the pod's
301
+ * emitter, cs macros). The registry's purity pin now allows NO code name to
302
+ * carry plan-tier vocabulary — the grandfather list is gone.
303
+ *
304
+ * Package version — classification MADE here: MAJOR-class change carried
305
+ * by a MINOR wave under `draft-` (§1.4) for `@ggui-ai/protocol` and
306
+ * `@ggui-ai/protocol-conformance`, pre-1.0 and pre-launch.
307
+ * PROTOCOL_VERSION unchanged — no WS envelope moved.
308
+ *
309
+ * --------------------------------------------------------------------
310
+ * `UNAUTHORIZED` moves from `-32001` to `-32007` (2026-09-05, renumber,
311
+ * pre-launch, ggui#853; found by ggui-main in the prod skew-gate log).
312
+ * `-32001` is the MCP SDK client's own `ErrorCode.RequestTimeout`
313
+ * (`@modelcontextprotocol/sdk` types.js, beside `ConnectionClosed`
314
+ * -32000) — minted LOCALLY, never sent by a server — so a client reading
315
+ * the number could not tell a server's UNAUTHORIZED from its own
316
+ * timeout: the class ggui#836 closed for -32000, on a number ggui had
317
+ * chosen long before #836 (0.14.0 and earlier).
318
+ *
319
+ * uc1. **`MCP_ERROR_CODES.UNAUTHORIZED = -32007`** — the next free
320
+ * canonical slot per this table's own note; `-32001` joins
321
+ * `-32004` as retired-reserved. Every mirror moves in this one
322
+ * change (SPEC §7.9 + its table, the gated doc mirrors, the
323
+ * endpoint routes' tests, the kit's transport-refusal wording, the
324
+ * pod's auth arm, the live journeys). HTTP status and message are
325
+ * unchanged: 401/403 + the same text.
326
+ *
327
+ * uc2. **The guard #836 lacked** — `types/error-codes-vs-sdk.test.ts`
328
+ * pins every ggui-chosen code (`MCP_ERROR_CODES` minus the five
329
+ * JSON-RPC standard codes, plus `PLATFORM_ERROR_CODES`) disjoint
330
+ * from every code the SDK's `ErrorCode` enum owns, and ggui's
331
+ * copies of the standard five equal to the SDK's. It was RED on
332
+ * -32001 before uc1 and is what reds the next collision.
333
+ *
334
+ * Conformance-kit verdict: no fixture on 0.15.0 pinned `-32001` (the
335
+ * transport-refusal catalog grades `-32003 + data.refusal` and `null`;
336
+ * its prose named -32001 and now names -32007) — a renumbered
337
+ * canonical code with no kit regression; guuey's clients branch on
338
+ * -32002/-32006 only (ggui#836 record). Bytes on the wire: one number.
339
+ *
340
+ * Package version — classification MADE here: MINOR for
341
+ * `@ggui-ai/protocol` and `@ggui-ai/mcp-server` (a canonical code
342
+ * renumbered, `draft-` intent per VERSION-POLICY §1.4), pre-1.0 and
343
+ * pre-launch. PROTOCOL_VERSION unchanged — no WS envelope moved.
344
+ *
345
+ * --------------------------------------------------------------------
9
346
  * SPEC §7.1's refused arm is ONE primitive (2026-09-05, additive,
10
347
  * pre-launch, ggui#803 leg 9). The tool result a render gate answers a
11
348
  * pre-generation refusal with was built by hand in
@@ -3145,6 +3482,19 @@
3145
3482
  * 2026-08-19 out-of-vocabulary enum incident as a permanent
3146
3483
  * sample).
3147
3484
  *
3485
+ * draft-2026-09-10 — THEMING REVISION (ggui#987 protocol half, ggui#989
3486
+ * OSS half, ggui#985 cloud half; BREAKING on the draft wave under
3487
+ * VERSION-POLICY §1.1, shipped under §1.4's `draft-` clause — the
3488
+ * substantive entry is the "Theming revision" block at the top of
3489
+ * this changelog). The wire: `appThemeSchema` v2 (`overlays` +
3490
+ * `overlayHash` required, `base` deleted), the client mode
3491
+ * projection `hostAnnounced ?? stamped ?? sessionSidecar`, `themeId`
3492
+ * without its sidecar-name leg, `AppThemeRefusalBody` at every write
3493
+ * door, `parseMcpAppAiGguiRenderMeta`'s `onInvalidTheme`, the render
3494
+ * shell on `--ggui-color-ground`. The 0.16.0 lockstep wave carries
3495
+ * it; the samples, the e2e fixtures and the docs' draft strings move
3496
+ * in this same commit.
3497
+ *
3148
3498
  * draft-2026-09-04 — PRE-GENERATION REFUSAL ENVELOPE (ggui#786;
3149
3499
  * BREAKING IN INTENT, pre-launch so no shim and no `@deprecated`
3150
3500
  * — see `docs/protocol/migrations/2026-09-04-pre-generation-refusal-envelope.md`):
@@ -3221,9 +3571,10 @@
3221
3571
  * derive (`ConsumeEventEntry`, `GguiConsumeOutput`, `GguiEmitOutput`,
3222
3572
  * `GguiListSessionsOutput`, `GguiSessionStatus`). `tools/list` now
3223
3573
  * advertises the entry vocabulary and the status enum for
3224
- * `ggui_consume`; `parsePendingEnvelope` parses a drained row instead
3225
- * of casting it, so a malformed pipe entry refuses at the seam. The
3226
- * wire bytes of a well-formed row are unchanged. Additive.
3574
+ * `ggui_consume`; `parsePendingEnvelope` parsed a drained row instead
3575
+ * of casting it, so a malformed pipe entry refused at the seam
3576
+ * (follower: collapsed into `pendingEventSchema`'s row parse, pe4
3577
+ * above). The wire bytes of a well-formed row are unchanged. Additive.
3227
3578
  * r11. **Endpoint refusal codes (ggui#836):** the per-app endpoint speaks
3228
3579
  * §7.9 Plane-1 rows — the typed deprovisioned arm is `-32003`
3229
3580
  * (`APP_NOT_FOUND`, `App not found`) with `data.refusal`; untyped
@@ -3245,7 +3596,7 @@
3245
3596
  * `CLIENT_SUPPORTED_VERSIONS`, enforced by the loader (`UPGRADE_REQUIRED`
3246
3597
  * on a non-member); the two coincide only while the set is a singleton.
3247
3598
  */
3248
- export const PROTOCOL_VERSION = "draft-2026-09-04";
3599
+ export const PROTOCOL_VERSION = "draft-2026-09-10";
3249
3600
  /**
3250
3601
  * The shipped `@ggui-ai/*` WAVE version — bare semver, identical to
3251
3602
  * `package.json#version` on every published package (the lockstep
@@ -3286,7 +3637,7 @@ export const PROTOCOL_VERSION = "draft-2026-09-04";
3286
3637
  * PATCH under §1.3); it cannot be cut from main, whose delta since
3287
3638
  * 0.14.0 is minor-class.
3288
3639
  */
3289
- export const GGUI_WAVE_VERSION = "0.15.0";
3640
+ export const GGUI_WAVE_VERSION = "0.16.0";
3290
3641
  /**
3291
3642
  * Schema version stamped onto wire envelopes that opt into the
3292
3643
  * `schemaVersion` forward-compat field (see {@link ActionEnvelope},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/protocol",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "sideEffects": [
5
5
  "./dist/schemas/sync-check.js",
6
6
  "./dist/validation/ajv-runtime.js"
@@ -1,12 +0,0 @@
1
- import type { ConsumeEventEntry } from './types/mcp.js';
2
- /**
3
- * Parse a {@link PendingEvent.envelope} that may arrive as either a raw
4
- * object or a JSON-stringified object, depending on how the
5
- * deployment's storage layer serializes rows. Returns the parsed entry
6
- * unchanged when already an object.
7
- *
8
- * Throws `SyntaxError` when a string input is malformed JSON. Does NOT
9
- * validate the entry shape — that's the caller's job.
10
- */
11
- export declare function parsePendingEnvelope(stored: ConsumeEventEntry | string): ConsumeEventEntry;
12
- //# sourceMappingURL=envelope-adapters.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"envelope-adapters.d.ts","sourceRoot":"","sources":["../src/envelope-adapters.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,iBAAiB,GAAG,MAAM,GACjC,iBAAiB,CAKnB"}
@@ -1,30 +0,0 @@
1
- /**
2
- * Envelope adapters — storage-side helpers for the consume pipe.
3
- *
4
- * `PendingEvent.envelope` carries the per-gesture {@link ConsumeEventEntry}
5
- * row written by `submit_action`'s `kind:"dispatch"` branch. Storage is
6
- * single-shaped (the same shape `ggui_consume` returns verbatim on drain).
7
- *
8
- * The only bounded adapter that lives here now is
9
- * {@link parsePendingEnvelope} — a shape-neutral reader for stored
10
- * `PendingEvent.envelope` values that may arrive as raw objects or as
11
- * JSON strings, depending on how the deployment's storage layer
12
- * serializes rows.
13
- */
14
- import { consumeEventEntrySchema } from './schemas/mcp.js';
15
- /**
16
- * Parse a {@link PendingEvent.envelope} that may arrive as either a raw
17
- * object or a JSON-stringified object, depending on how the
18
- * deployment's storage layer serializes rows. Returns the parsed entry
19
- * unchanged when already an object.
20
- *
21
- * Throws `SyntaxError` when a string input is malformed JSON. Does NOT
22
- * validate the entry shape — that's the caller's job.
23
- */
24
- export function parsePendingEnvelope(stored) {
25
- if (typeof stored !== 'string')
26
- return stored;
27
- // Parsed, never cast (ggui#817 part C2): a malformed pipe entry refuses
28
- // here, at the seam, instead of shipping to the agent typed as good.
29
- return consumeEventEntrySchema.parse(JSON.parse(stored));
30
- }