@ggui-ai/protocol-conformance 0.20.0 → 0.22.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.
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "forward-render-meta-unknown-member",
3
+ "description": "FORWARD tolerance (ggui#1178, VERSION-POLICY §3.6): the `_meta[\"ai.ggui/render\"]` slice a LATER release may write — a top-level member this release does not name (`futureMember`), and an `actionSpec` whose entry carries a member this release does not name (`futureEntryMember`). Both are synthetic by construction: the payload is the NEXT release's, so it carries no landed sha. The read door MUST accept the slice and KEEP the action contract (stripping the unknown entry member and naming it). Dropping the whole `actionSpec` is the violation: a runtime left with no contract has no one-shot guard and validates gestures permissively, which is the fail-open ggui#1178 closes.",
4
+ "direction": "forward",
5
+ "release": {
6
+ "label": "a later ggui release (synthetic): a render slice plus a synthetic top-level member and a synthetic action-entry member",
7
+ "sha": "synthetic"
8
+ },
9
+ "wire": "render-meta",
10
+ "payload": {
11
+ "ai.ggui/render": {
12
+ "sessionId": "r-1",
13
+ "appId": "app-1",
14
+ "runtimeUrl": "/_ggui/iframe-runtime.js",
15
+ "propsJson": "{}",
16
+ "epoch": 0,
17
+ "actionSpec": {
18
+ "submit": {
19
+ "label": "Submit",
20
+ "oneShot": true,
21
+ "futureEntryMember": 1
22
+ },
23
+ "cancel": {
24
+ "label": "Cancel"
25
+ }
26
+ },
27
+ "futureMember": {
28
+ "any": "value"
29
+ }
30
+ }
31
+ },
32
+ "expect": "accepted"
33
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/n1-compat-conformance/index.ts"],"names":[],"mappings":"AA6BA,sDAAsD;AACtD,eAAO,MAAM,eAAe,4HAA6H,CAAC;AAE1J,yIAAyI;AACzI,eAAO,MAAM,oBAAoB,kCAAmC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iKAAiK;IACjK,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,gGAAgG;IAChG,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAgDD,eAAO,MAAM,eAAe,EAAE,SAAS,YAAY,EAOhC,CAAC;AAkEpB,4DAA4D;AAC5D,wBAAgB,sBAAsB,IAAI,SAAS,cAAc,EAAE,CAgBlE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/n1-compat-conformance/index.ts"],"names":[],"mappings":"AA8BA,sDAAsD;AACtD,eAAO,MAAM,eAAe,4HAA6H,CAAC;AAE1J,yIAAyI;AACzI,eAAO,MAAM,oBAAoB,kCAAmC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iKAAiK;IACjK,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,gGAAgG;IAChG,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAgDD,eAAO,MAAM,eAAe,EAAE,SAAS,YAAY,EAQhC,CAAC;AA+EpB,4DAA4D;AAC5D,wBAAgB,sBAAsB,IAAI,SAAS,cAAc,EAAE,CAgBlE"}
@@ -22,6 +22,7 @@ import release2GenerationProfile from './cases/release-2-generation-profile.json
22
22
  import release2OpsGenerateBlueprint from './cases/release-2-ops-generate-blueprint.json' with { type: 'json' };
23
23
  import forwardAppThemeUnknownMember from './cases/forward-app-theme-unknown-member.json' with { type: 'json' };
24
24
  import forwardAppThemeCarryUnknownMember from './cases/forward-app-theme-carry-unknown-member.json' with { type: 'json' };
25
+ import forwardRenderMetaUnknownMember from './cases/forward-render-meta-unknown-member.json' with { type: 'json' };
25
26
  /** The protocol-owned wires the catalog can grade. */
26
27
  export const N1_COMPAT_WIRES = ['app-theme', 'app-theme-read', 'app-theme-carry', 'render-meta', 'generation-profile', 'ops-generate-blueprint'];
27
28
  /** `backward`: the previous release's payload against today's parser. `forward`: a later release's payload against today's READ door. */
@@ -81,6 +82,7 @@ export const N1_COMPAT_CASES = [
81
82
  release2OpsGenerateBlueprint,
82
83
  forwardAppThemeUnknownMember,
83
84
  forwardAppThemeCarryUnknownMember,
85
+ forwardRenderMetaUnknownMember,
84
86
  ].map(n1CompatCase);
85
87
  function gradeAppTheme(payload) {
86
88
  const r = appThemeSchema.safeParse(payload);
@@ -138,7 +140,11 @@ function gradeOpsGenerateBlueprint(payload) {
138
140
  }
139
141
  function gradeRenderMeta(payload) {
140
142
  const themeIssues = [];
141
- const r = parseMcpAppAiGguiRenderMeta(payload, { onInvalidTheme: (issues) => themeIssues.push(...issues) });
143
+ const actionIssues = [];
144
+ const r = parseMcpAppAiGguiRenderMeta(payload, {
145
+ onInvalidTheme: (issues) => themeIssues.push(...issues),
146
+ onInvalidActionSpec: (issues) => actionIssues.push(...issues),
147
+ });
142
148
  if (!r.ok)
143
149
  return { pass: false, detail: `parseMcpAppAiGguiRenderMeta refused the previous release's slice: ${r.reason}` };
144
150
  if (r.meta === undefined)
@@ -148,7 +154,16 @@ function gradeRenderMeta(payload) {
148
154
  if (sentTheme && (themeIssues.length > 0 || r.meta.theme === undefined)) {
149
155
  return { pass: false, detail: `the previous release's theme was dropped at the read door: ${themeIssues.join('; ') || 'theme absent on the parsed meta'}` };
150
156
  }
151
- return { pass: true, detail: 'parseMcpAppAiGguiRenderMeta: accepted' + (sentTheme ? ', theme preserved' : '') };
157
+ // ggui#1178 — an action contract the slice carried must survive the read door (unknown entry
158
+ // members stripped, never the whole spec dropped).
159
+ const sentActionSpec = isRecord(sent) && sent['actionSpec'] !== undefined;
160
+ if (sentActionSpec && (actionIssues.length > 0 || r.meta.actionSpec === undefined)) {
161
+ return { pass: false, detail: `the slice's action contract was dropped at the read door: ${actionIssues.join('; ') || 'actionSpec absent on the parsed meta'}` };
162
+ }
163
+ return {
164
+ pass: true,
165
+ detail: 'parseMcpAppAiGguiRenderMeta: accepted' + (sentTheme ? ', theme preserved' : '') + (sentActionSpec ? ', actionSpec preserved' : ''),
166
+ };
152
167
  }
153
168
  /** Grade every N−1 case against the protocol as shipped. */
154
169
  export function runN1CompatConformance() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/protocol-conformance",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Conformance test kit for the ggui protocol. Drives a behavioral fixture catalog against a live implementation over WebSocket, a resources/read catalog against a live MCP server, and nine pure-function catalogs (schema, registration, resolution, binding, props-schema, host-helper, refusal-envelope, registry-completeness, transport-refusal) for the gadget, tool-binding, schema-precise-render, host-helper and pre-generation-refusal obligations, reporting a scorecard-style pass / fail / skip. MCP builders adopt this kit to prove their implementation is protocol-conformant.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -99,7 +99,7 @@
99
99
  },
100
100
  "dependencies": {
101
101
  "ws": "^8.20.1",
102
- "@ggui-ai/protocol": "0.20.0"
102
+ "@ggui-ai/protocol": "0.22.0"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@types/node": "^22.0.0",