@ggui-ai/mcp-server-handlers 0.25.0 → 0.26.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 (101) hide show
  1. package/README.md +2 -2
  2. package/dist/credits/index.d.ts +2 -2
  3. package/dist/credits/index.d.ts.map +1 -1
  4. package/dist/credits/index.js +1 -1
  5. package/dist/credits/list-credit-transactions.d.ts +21 -7
  6. package/dist/credits/list-credit-transactions.d.ts.map +1 -1
  7. package/dist/credits/list-credit-transactions.js +12 -2
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/ops-blueprint/cache-mirror.d.ts +41 -0
  12. package/dist/ops-blueprint/cache-mirror.d.ts.map +1 -0
  13. package/dist/ops-blueprint/cache-mirror.js +19 -0
  14. package/dist/ops-blueprint/delete.d.ts +18 -0
  15. package/dist/ops-blueprint/delete.d.ts.map +1 -1
  16. package/dist/ops-blueprint/delete.js +21 -2
  17. package/dist/ops-blueprint/errors.d.ts +11 -0
  18. package/dist/ops-blueprint/errors.d.ts.map +1 -1
  19. package/dist/ops-blueprint/errors.js +14 -0
  20. package/dist/ops-blueprint/generate.d.ts +1 -3
  21. package/dist/ops-blueprint/generate.d.ts.map +1 -1
  22. package/dist/ops-blueprint/generate.js +47 -58
  23. package/dist/ops-blueprint/list.d.ts.map +1 -1
  24. package/dist/ops-blueprint/list.js +1 -2
  25. package/dist/ops-blueprint/register.d.ts +17 -6
  26. package/dist/ops-blueprint/register.d.ts.map +1 -1
  27. package/dist/ops-blueprint/register.js +77 -45
  28. package/dist/ops-blueprint/update.d.ts +3 -2
  29. package/dist/ops-blueprint/update.d.ts.map +1 -1
  30. package/dist/ops-blueprint/update.js +4 -3
  31. package/dist/renders/blueprint-coverage.d.ts +23 -4
  32. package/dist/renders/blueprint-coverage.d.ts.map +1 -1
  33. package/dist/renders/blueprint-coverage.js +45 -5
  34. package/dist/renders/blueprint-durability.d.ts.map +1 -1
  35. package/dist/renders/blueprint-durability.js +5 -0
  36. package/dist/renders/blueprint-matcher.d.ts +28 -0
  37. package/dist/renders/blueprint-matcher.d.ts.map +1 -1
  38. package/dist/renders/blueprint-matcher.js +39 -7
  39. package/dist/renders/blueprint-registry.d.ts +52 -1
  40. package/dist/renders/blueprint-registry.d.ts.map +1 -1
  41. package/dist/renders/blueprint-registry.js +137 -10
  42. package/dist/renders/build-seed-pool.d.ts.map +1 -1
  43. package/dist/renders/build-seed-pool.js +6 -0
  44. package/dist/renders/consume.d.ts +3 -2
  45. package/dist/renders/consume.d.ts.map +1 -1
  46. package/dist/renders/consume.js +23 -14
  47. package/dist/renders/cross-app-refused.d.ts +3 -2
  48. package/dist/renders/cross-app-refused.d.ts.map +1 -1
  49. package/dist/renders/cross-app-refused.js +5 -3
  50. package/dist/renders/decide-handshake.d.ts +28 -0
  51. package/dist/renders/decide-handshake.d.ts.map +1 -1
  52. package/dist/renders/decide-handshake.js +39 -4
  53. package/dist/renders/export-registry.d.ts +8 -1
  54. package/dist/renders/export-registry.d.ts.map +1 -1
  55. package/dist/renders/export-registry.js +3 -0
  56. package/dist/renders/fits.d.ts.map +1 -1
  57. package/dist/renders/fits.js +23 -1
  58. package/dist/renders/handshake.d.ts +6 -42
  59. package/dist/renders/handshake.d.ts.map +1 -1
  60. package/dist/renders/handshake.js +1 -1
  61. package/dist/renders/index.d.ts +5 -4
  62. package/dist/renders/index.d.ts.map +1 -1
  63. package/dist/renders/index.js +4 -3
  64. package/dist/renders/installed-blueprints-provider.d.ts.map +1 -1
  65. package/dist/renders/installed-blueprints-provider.js +3 -1
  66. package/dist/renders/match-precision/pairs.d.ts +5 -4
  67. package/dist/renders/match-precision/pairs.d.ts.map +1 -1
  68. package/dist/renders/match-precision/topk-probe.js +13 -8
  69. package/dist/renders/record-committed-one-shot.d.ts +18 -3
  70. package/dist/renders/record-committed-one-shot.d.ts.map +1 -1
  71. package/dist/renders/record-committed-one-shot.js +14 -7
  72. package/dist/renders/refresh-ws-token.d.ts +9 -12
  73. package/dist/renders/refresh-ws-token.d.ts.map +1 -1
  74. package/dist/renders/refresh-ws-token.js +13 -10
  75. package/dist/renders/render-identity.d.ts +14 -5
  76. package/dist/renders/render-identity.d.ts.map +1 -1
  77. package/dist/renders/render-identity.js +25 -12
  78. package/dist/renders/render-read-gate.d.ts +27 -1
  79. package/dist/renders/render-read-gate.d.ts.map +1 -1
  80. package/dist/renders/render-read-gate.js +17 -5
  81. package/dist/renders/render.d.ts +36 -19
  82. package/dist/renders/render.d.ts.map +1 -1
  83. package/dist/renders/render.js +174 -17
  84. package/dist/renders/report-render-failure.d.ts +69 -0
  85. package/dist/renders/report-render-failure.d.ts.map +1 -0
  86. package/dist/renders/report-render-failure.js +83 -0
  87. package/dist/renders/runtime-pull.d.ts.map +1 -1
  88. package/dist/renders/runtime-pull.js +6 -0
  89. package/dist/renders/slice-meta-derivation.d.ts +8 -1
  90. package/dist/renders/slice-meta-derivation.d.ts.map +1 -1
  91. package/dist/renders/slice-meta-derivation.js +1 -0
  92. package/dist/renders/submit-action.d.ts +41 -71
  93. package/dist/renders/submit-action.d.ts.map +1 -1
  94. package/dist/renders/submit-action.js +225 -78
  95. package/dist/renders/sync-context.d.ts +3 -1
  96. package/dist/renders/sync-context.d.ts.map +1 -1
  97. package/dist/renders/sync-context.js +38 -8
  98. package/dist/types.d.ts +71 -1
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js +32 -0
  101. package/package.json +8 -8
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Sibling of `ggui_ops_generate_blueprint`. Same persistence seams +
6
6
  * dual-write (BlueprintStore + cache vectorStore via registerBlueprint),
7
- * same variance + default-pin semantics. The only difference is the
7
+ * same variance + operator-default mark semantics. The only difference is the
8
8
  * code body: instead of dispatching through `generator.generate(...)`
9
9
  * to produce componentCode, the operator supplies the bytes directly
10
10
  * and the handler persists them verbatim.
@@ -36,7 +36,7 @@
36
36
  * ops_generate — schema-compat + hygiene-3 lint live elsewhere.
37
37
  */
38
38
  import type { AppMetadataStore, BlueprintStore, TelemetrySink } from "@ggui-ai/mcp-server-core";
39
- import { type Blueprint, type DataContract, type LlmBlueprintSource, type UserBlueprintSource } from "@ggui-ai/protocol";
39
+ import { type Blueprint, type DataContract, type GeneratorBuild, type LlmBlueprintSource, type UserBlueprintSource } from "@ggui-ai/protocol";
40
40
  import { z } from "zod";
41
41
  import { type BlueprintRegistryDeps } from "../renders/index.js";
42
42
  import { type HandlerContext } from "../types.js";
@@ -132,6 +132,7 @@ export declare function createGguiOpsRegisterBlueprintHandler(deps: GguiOpsRegis
132
132
  request: "request";
133
133
  }>>;
134
134
  setAsOperatorDefault: z.ZodOptional<z.ZodBoolean>;
135
+ clonedFrom: z.ZodOptional<z.ZodString>;
135
136
  }, {
136
137
  blueprintId: z.ZodString;
137
138
  codeHash: z.ZodString;
@@ -165,6 +166,14 @@ export interface GeneratedBlueprintBytes {
165
166
  * claim nobody made. Validated against the protocol's schema.
166
167
  */
167
168
  readonly source: LlmBlueprintSource;
169
+ /**
170
+ * ggui#1280 — the build the generation reported (`metadata.build`),
171
+ * verbatim. Admitted by the registry's one rule (`admitGeneratorBuild`):
172
+ * a stamp that fails the protocol's `generatorBuildSchema` is dropped
173
+ * with a `blueprint_build_stamp_dropped` line and the row registers
174
+ * unstamped, so a bad stamp never refuses a registration.
175
+ */
176
+ readonly build?: GeneratorBuild;
168
177
  }
169
178
  /** What {@link createRegisterGeneratedBlueprint}'s entry returns. */
170
179
  export interface RegisterGeneratedBlueprintOutput {
@@ -184,10 +193,12 @@ export type RegisterGeneratedBlueprint = (input: Record<string, unknown>, genera
184
193
  * with the authored source they were compiled from, in-process.
185
194
  *
186
195
  * Same body as `ggui_ops_register_blueprint` (one durable row, one cache
187
- * mirror, the same gates and variance), with two differences: provenance
188
- * is the generation's `llm` arm, and the authored source reaches the
189
- * cache registry, so a render that reuses the registration serves it
190
- * (`ggui_get_render_source`, save-to-library). It is NOT an MCP tool and
196
+ * mirror, the same gates and variance), with three differences: provenance
197
+ * is the generation's `llm` arm; the authored source reaches the cache
198
+ * registry, so a render that reuses the registration serves it
199
+ * (`ggui_get_render_source`, save-to-library); and the generation's build,
200
+ * when the caller passes one, is stamped on the durable rows (ggui#1280).
201
+ * It is NOT an MCP tool and
191
202
  * is on no wire: the public operator door stays source-free, because it
192
203
  * cannot verify that supplied source compiles to the supplied code.
193
204
  *
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,SAAS,EAEd,KAAK,YAAY,EACjB,KAAK,kBAAkB,EAGvB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAqB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAkBjD;;;;;;;GAOG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;OAEG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AA0OD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BnC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED,qEAAqE;AACrE,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,uBAAuB,EAClC,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,gCAAgC,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,4BAA4B,GACjC,0BAA0B,CAgB5B"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,SAAS,EAEd,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAGvB,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEtF,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAkBjD;;;;;;;GAOG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IAC1E;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;OAEG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AA0QD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BnC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,qEAAqE;AACrE,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,uBAAuB,EAClC,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,gCAAgC,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,4BAA4B,GACjC,0BAA0B,CAkB5B"}
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Sibling of `ggui_ops_generate_blueprint`. Same persistence seams +
6
6
  * dual-write (BlueprintStore + cache vectorStore via registerBlueprint),
7
- * same variance + default-pin semantics. The only difference is the
7
+ * same variance + operator-default mark semantics. The only difference is the
8
8
  * code body: instead of dispatching through `generator.generate(...)`
9
9
  * to produce componentCode, the operator supplies the bytes directly
10
10
  * and the handler persists them verbatim.
@@ -41,10 +41,11 @@ import { createHash, randomUUID } from "node:crypto";
41
41
  import { z } from "zod";
42
42
  import { assertContractNoRetiredFields } from "../renders/assert-contract-no-retired-fields.js";
43
43
  import { assertGadgetsRegistered } from "../renders/assert-gadgets.js";
44
- import { registerBlueprint } from "../renders/index.js";
44
+ import { admitGeneratorBuild } from "../renders/index.js";
45
+ import { mirrorIntoCache } from "./cache-mirror.js";
45
46
  import { defineHandler } from "../types.js";
46
47
  import { resolveEffectiveAppId } from "./app-access.js";
47
- import { DirectionScopeWithoutDigestError } from "./errors.js";
48
+ import { ClonedFromRefusedError, DirectionScopeWithoutDigestError } from "./errors.js";
48
49
  import { findNearDuplicatePersona, normalizePersona } from "./persona-normalization.js";
49
50
  const opsInputSchema = opsRegisterBlueprintInputSchema.shape;
50
51
  const opsOutputSchema = z.object({
@@ -60,7 +61,7 @@ const opsOutputSchema = z.object({
60
61
  const USER_SOURCE = { kind: "user" };
61
62
  /**
62
63
  * The registration body both entries share: app resolution, the
63
- * contract gates, the durable row, the cache mirror, the default pin and
64
+ * contract gates, the durable row, the cache mirror, the operator-default mark and
64
65
  * the event. The two entries differ only in the provenance they pass.
65
66
  */
66
67
  function makeRegisterCore(deps) {
@@ -134,6 +135,18 @@ function makeRegisterCore(deps) {
134
135
  throw new DirectionScopeWithoutDigestError();
135
136
  }
136
137
  const blueprintId = mintBlueprintId();
138
+ // ggui#1570 — a copy (`clonedFrom`, the door's input member, which the
139
+ // in-process generated-bytes entry parses too) names another row of this
140
+ // app that the store holds. Checked after the id is minted (a copy never
141
+ // names itself) and before anything is persisted. The cache mirror's own
142
+ // durable write-through, when it writes to a store other than this one,
143
+ // does not carry it: that copy serves re-mint, which ignores provenance.
144
+ if (parsed.clonedFrom !== undefined) {
145
+ const parentId = parsed.clonedFrom;
146
+ const parent = parentId.length > 0 && parentId !== blueprintId ? await deps.blueprintStore.get(parentId) : null;
147
+ if (parent === null || parent.appId !== appId)
148
+ throw new ClonedFromRefusedError(parentId);
149
+ }
137
150
  // ONE variance for BOTH stores. The cache row's exact key is
138
151
  // `variantKey(variance)`; omitting it on the cache call filed every
139
152
  // variant under the default-variant key, where an earlier registration
@@ -155,6 +168,10 @@ function makeRegisterCore(deps) {
155
168
  // row here, cache mirror below): the user arm for operator-
156
169
  // supplied bytes, the llm arm for engine-generated ones.
157
170
  source: provenance.source,
171
+ // ggui#1280 — the minting build, on a generation mint's bytes only.
172
+ ...(provenance.build !== undefined ? { build: provenance.build } : {}),
173
+ // ggui#1570 — provenance about the row: the row whose bytes it copies.
174
+ ...(parsed.clonedFrom !== undefined ? { clonedFrom: parsed.clonedFrom } : {}),
158
175
  variance,
159
176
  createdAt: now(),
160
177
  createdBy: "operator",
@@ -178,41 +195,52 @@ function makeRegisterCore(deps) {
178
195
  parsed.seedPrompt ??
179
196
  normalizedPersona ??
180
197
  `operator-registered blueprint (${blueprintId})`;
181
- await registerBlueprint(deps.cacheRegistry, appId, {
182
- kind: "template",
183
- contract,
184
- intent: intentForCache,
185
- // ggui#1275 — an explicit intent or a seed prompt states the
186
- // UI's task. A persona describes the agent and the placeholder
187
- // describes nothing: both are stand-ins the matcher's judge
188
- // never sees.
189
- intentSource: parsed.intent !== undefined || parsed.seedPrompt !== undefined
190
- ? "authored"
191
- : "fallback",
192
- // ggui#1427 — the fit facts `fits()` reads before the judge
193
- // ranks this row. Absent inputs write nothing (not-evaluated).
194
- ...(parsed.judgedCanvases !== undefined ? { judgedCanvases: parsed.judgedCanvases } : {}),
195
- ...(parsed.aestheticPreset !== undefined ? { aestheticPreset: parsed.aestheticPreset } : {}),
196
- ...(parsed.directionDigest !== undefined ? { directionDigest: parsed.directionDigest } : {}),
197
- ...(parsed.directionDigest !== undefined && parsed.directionScope !== undefined
198
- ? { directionScope: parsed.directionScope }
199
- : {}),
200
- componentCode,
201
- // ggui#1493 — the authored form of `componentCode`, when the
202
- // caller has one (the in-process generated-bytes path only).
203
- // The registry persists its hash and body only when a code
204
- // store is bound and the pair is not byte-identical.
205
- ...(provenance.sourceCode !== undefined ? { sourceCode: provenance.sourceCode } : {}),
206
- // Same provenance as the MVB row above — one call, one
207
- // provenance claim across both stores.
208
- source: provenance.source,
209
- // The cache row MUST carry the same variance as the MVB row —
210
- // its exact key is `variantKey(variance)`.
211
- variance,
212
- // An operator invoked this tool. Without it the durable
213
- // record would claim the standard agent flow minted a row
214
- // that is retained permanently.
215
- createdBy: "operator",
198
+ // ggui#1497 — ONE id per registration: the cache row serves the
199
+ // durable row's id (see `mirrorIntoCache` for what else it writes).
200
+ await mirrorIntoCache({
201
+ cacheRegistry: deps.cacheRegistry,
202
+ writerStore: deps.blueprintStore,
203
+ appId,
204
+ blueprintId,
205
+ input: {
206
+ kind: "template",
207
+ contract,
208
+ intent: intentForCache,
209
+ // ggui#1275 — an explicit intent or a seed prompt states the
210
+ // UI's task. A persona describes the agent and the placeholder
211
+ // describes nothing: both are stand-ins the matcher's judge
212
+ // never sees.
213
+ intentSource: parsed.intent !== undefined || parsed.seedPrompt !== undefined
214
+ ? "authored"
215
+ : "fallback",
216
+ // ggui#1427 — the fit facts `fits()` reads before the judge
217
+ // ranks this row. Absent inputs write nothing (not-evaluated).
218
+ ...(parsed.judgedCanvases !== undefined ? { judgedCanvases: parsed.judgedCanvases } : {}),
219
+ ...(parsed.aestheticPreset !== undefined ? { aestheticPreset: parsed.aestheticPreset } : {}),
220
+ ...(parsed.directionDigest !== undefined ? { directionDigest: parsed.directionDigest } : {}),
221
+ ...(parsed.directionDigest !== undefined && parsed.directionScope !== undefined
222
+ ? { directionScope: parsed.directionScope }
223
+ : {}),
224
+ componentCode,
225
+ // ggui#1493 — the authored form of `componentCode`, when the
226
+ // caller has one (the in-process generated-bytes path only).
227
+ // The registry persists its hash and body only when a code
228
+ // store is bound and the pair is not byte-identical.
229
+ ...(provenance.sourceCode !== undefined ? { sourceCode: provenance.sourceCode } : {}),
230
+ // Same provenance as the MVB row above — one call, one
231
+ // provenance claim across both stores.
232
+ source: provenance.source,
233
+ // ggui#1280 — the same stamp, onto the durable row a mirror
234
+ // writes through to (never onto its vector-store row).
235
+ ...(provenance.build !== undefined ? { build: provenance.build } : {}),
236
+ // The cache row MUST carry the same variance as the MVB row —
237
+ // its exact key is `variantKey(variance)`.
238
+ variance,
239
+ // An operator invoked this tool. Without it the durable
240
+ // record would claim the standard agent flow minted a row
241
+ // that is retained permanently.
242
+ createdBy: "operator",
243
+ },
216
244
  });
217
245
  }
218
246
  catch (err) {
@@ -235,7 +263,7 @@ function makeRegisterCore(deps) {
235
263
  }
236
264
  }
237
265
  }
238
- // 4. Pin as operator default when requested.
266
+ // 4. Mark as operator default when requested.
239
267
  if (parsed.setAsOperatorDefault === true) {
240
268
  await deps.blueprintStore.setOperatorDefault(blueprintId);
241
269
  }
@@ -268,7 +296,7 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
268
296
  name: "ggui_ops_register_blueprint",
269
297
  title: "Register blueprint",
270
298
  audience: ["ops"],
271
- description: "Register a pre-built blueprint variant (operator-supplied componentCode bytes, no LLM dispatch). Sibling of `ggui_ops_generate_blueprint` — same persistence + dual-write semantics, same variance + default-pin behavior. Use for fixture seeding, export/reimport round-trips, and manual recovery. Returns `{blueprintId, codeHash, source}` where `source` is always `{kind: 'user'}` — hand-supplied bytes carry no engine claim, so none is recorded. App-scoped variant curation for an app you operate — distinct from the personal saved-blueprint library (the _my_ tools).",
299
+ description: "Register a pre-built blueprint variant (operator-supplied componentCode bytes, no LLM dispatch). Sibling of `ggui_ops_generate_blueprint` — same persistence + dual-write semantics, same variance + operator-default mark behavior (the mark orders blueprint listings; it does not decide which blueprint serves a render). Use for fixture seeding, export/reimport round-trips, and manual recovery. Returns `{blueprintId, codeHash, source}` where `source` is always `{kind: 'user'}` — hand-supplied bytes carry no engine claim, so none is recorded. App-scoped variant curation for an app you operate — distinct from the personal saved-blueprint library (the _my_ tools).",
272
300
  inputSchema: opsInputSchema,
273
301
  outputSchema: opsOutputSchema,
274
302
  async handler(rawInput, ctx) {
@@ -289,10 +317,12 @@ export function createGguiOpsRegisterBlueprintHandler(deps) {
289
317
  * with the authored source they were compiled from, in-process.
290
318
  *
291
319
  * Same body as `ggui_ops_register_blueprint` (one durable row, one cache
292
- * mirror, the same gates and variance), with two differences: provenance
293
- * is the generation's `llm` arm, and the authored source reaches the
294
- * cache registry, so a render that reuses the registration serves it
295
- * (`ggui_get_render_source`, save-to-library). It is NOT an MCP tool and
320
+ * mirror, the same gates and variance), with three differences: provenance
321
+ * is the generation's `llm` arm; the authored source reaches the cache
322
+ * registry, so a render that reuses the registration serves it
323
+ * (`ggui_get_render_source`, save-to-library); and the generation's build,
324
+ * when the caller passes one, is stamped on the durable rows (ggui#1280).
325
+ * It is NOT an MCP tool and
296
326
  * is on no wire: the public operator door stays source-free, because it
297
327
  * cannot verify that supplied source compiles to the supplied code.
298
328
  *
@@ -307,9 +337,11 @@ export function createRegisterGeneratedBlueprint(deps) {
307
337
  if (generated.sourceCode.length === 0) {
308
338
  throw new Error("registerGeneratedBlueprint: sourceCode must be the non-empty authored source componentCode was compiled from");
309
339
  }
340
+ const build = admitGeneratorBuild(source, generated.build);
310
341
  const { blueprintId, codeHash } = await registerVariant(parsed, ctx, {
311
342
  source,
312
343
  sourceCode: generated.sourceCode,
344
+ ...(build !== undefined ? { build } : {}),
313
345
  });
314
346
  return { blueprintId, codeHash, source };
315
347
  };
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * Patches the two mutable surfaces of a blueprint:
5
5
  *
6
- * 1. `isOperatorDefault` — pin as the operator default for the
7
- * blueprint's `(appId, contractHash)` group. The store
6
+ * 1. `isOperatorDefault` — mark as the operator default for the
7
+ * blueprint's `(appId, contractHash)` group (orders listings; no
8
+ * render path reads it to choose what serves). The store
8
9
  * automatically clears any prior default in the same group
9
10
  * (see `BlueprintStore.setOperatorDefault`).
10
11
  * 2. `variance` — partial merge into the persisted variance. Keys
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,cAAc,EACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AASxF;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAG,wBAAwB,CAAU;gBACtC,WAAW,EAAE,MAAM;CAMhC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AAuCD,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,0BAA0B;;;;;;;;;;;GAwEjC"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/ops-blueprint/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,cAAc,EACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AASxF;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAG,wBAAwB,CAAU;gBACtC,WAAW,EAAE,MAAM;CAMhC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CACzD;AAuCD,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,0BAA0B;;;;;;;;;;;GAwEjC"}
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * Patches the two mutable surfaces of a blueprint:
5
5
  *
6
- * 1. `isOperatorDefault` — pin as the operator default for the
7
- * blueprint's `(appId, contractHash)` group. The store
6
+ * 1. `isOperatorDefault` — mark as the operator default for the
7
+ * blueprint's `(appId, contractHash)` group (orders listings; no
8
+ * render path reads it to choose what serves). The store
8
9
  * automatically clears any prior default in the same group
9
10
  * (see `BlueprintStore.setOperatorDefault`).
10
11
  * 2. `variance` — partial merge into the persisted variance. Keys
@@ -91,7 +92,7 @@ export function createGguiOpsUpdateBlueprintHandler(deps) {
91
92
  name: 'ggui_ops_update_blueprint',
92
93
  title: 'Update blueprint',
93
94
  audience: ['ops'],
94
- description: 'Patch the mutable surface of an existing blueprint: pin/unpin operator-default + merge variance tags. Immutable fields (contractHash, appId, codeS3Url, codeHash, source, createdAt, createdBy) are absent from the schema — to "replace" a row, delete + re-generate. Partial-merge semantics: supplied variance keys overwrite, omitted keys preserve. Empty-string persona is removal. App-scoped variant curation for an app you operate — distinct from the personal saved-blueprint library (the _my_ tools).',
95
+ description: 'Patch the mutable surface of an existing blueprint: set the operator-default mark (it orders blueprint listings and is shown to operators; it does not decide which blueprint serves a render) + merge variance tags. Immutable fields (contractHash, appId, codeS3Url, codeHash, source, createdAt, createdBy) are absent from the schema — to "replace" a row, delete + re-generate. Partial-merge semantics: supplied variance keys overwrite, omitted keys preserve. Empty-string persona is removal. App-scoped variant curation for an app you operate — distinct from the personal saved-blueprint library (the _my_ tools).',
95
96
  inputSchema: opsInputSchema,
96
97
  outputSchema: opsOutputSchema,
97
98
  async handler(rawInput, ctx) {
@@ -23,10 +23,13 @@
23
23
  * proposed contract is the safety valve when a flagged surface is one
24
24
  * the user must directly see or act on.
25
25
  *
26
- * Pure — no store, no LLM. Compares only declared key-SETS; differences
27
- * WITHIN a shared surface (a relabeled action, an `id` vs `id+done`
28
- * payload schema) are tolerated, because atomic reuse hands the agent
29
- * the cached contract and it drives that contract, not its own draft.
26
+ * Pure — no store, no LLM. Compares declared key-SETS, plus ONE thing
27
+ * inside a shared action: the members that change what the runtime does
28
+ * with a gesture ({@link LOAD_BEARING_ACTION_MEMBERS}). Every other
29
+ * difference WITHIN a shared surface (a relabeled action, an `id` vs
30
+ * `id+done` payload schema) is tolerated, because atomic reuse hands the
31
+ * agent the cached contract and it drives that contract, not its own
32
+ * draft.
30
33
  */
31
34
  import type { DataContract } from '@ggui-ai/protocol';
32
35
  /** The request-declared surfaces a candidate fails to cover. Empty
@@ -37,7 +40,23 @@ export interface CoverageGap {
37
40
  readonly context: readonly string[];
38
41
  readonly streams: readonly string[];
39
42
  readonly gadgets: readonly string[];
43
+ /**
44
+ * `<action>.<member>` for every load-bearing member the request declares
45
+ * on an action BOTH contracts carry, where the candidate's entry does not
46
+ * say the same (ggui#1428). An action the candidate lacks altogether is in
47
+ * {@link actions}, never here.
48
+ */
49
+ readonly actionMembers: readonly string[];
40
50
  }
51
+ /**
52
+ * The action-entry members that change what the runtime DOES with a gesture,
53
+ * as opposed to how the action reads: `oneShot` arms the single-dispatch
54
+ * guard, `confirm` asks before firing, `nextStep` names the tool the agent is
55
+ * routed to. A stored card that lacks one the draft declares serves a card
56
+ * without that behaviour, so the agent is told. `label`, `description`,
57
+ * `icon`, `example` and `schema` stay tolerated differences.
58
+ */
59
+ export declare const LOAD_BEARING_ACTION_MEMBERS: readonly ["oneShot", "confirm", "nextStep"];
41
60
  /**
42
61
  * Compute the surfaces the request declares that the candidate does NOT.
43
62
  * A wholly-empty gap means the candidate covers the request.
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint-coverage.d.ts","sourceRoot":"","sources":["../../src/renders/blueprint-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD;4DAC4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAmBD;;;GAGG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,YAAY,GACpB,WAAW,CAWb;AAED;2DAC2D;AAC3D,wBAAgB,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAS9E"}
1
+ {"version":3,"file":"blueprint-coverage.d.ts","sourceRoot":"","sources":["../../src/renders/blueprint-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD;4DAC4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,6CAA8C,CAAC;AA6CvF;;;GAGG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,YAAY,GACpB,WAAW,CAYb;AAED;2DAC2D;AAC3D,wBAAgB,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAU9E"}
@@ -23,12 +23,50 @@
23
23
  * proposed contract is the safety valve when a flagged surface is one
24
24
  * the user must directly see or act on.
25
25
  *
26
- * Pure — no store, no LLM. Compares only declared key-SETS; differences
27
- * WITHIN a shared surface (a relabeled action, an `id` vs `id+done`
28
- * payload schema) are tolerated, because atomic reuse hands the agent
29
- * the cached contract and it drives that contract, not its own draft.
26
+ * Pure — no store, no LLM. Compares declared key-SETS, plus ONE thing
27
+ * inside a shared action: the members that change what the runtime does
28
+ * with a gesture ({@link LOAD_BEARING_ACTION_MEMBERS}). Every other
29
+ * difference WITHIN a shared surface (a relabeled action, an `id` vs
30
+ * `id+done` payload schema) is tolerated, because atomic reuse hands the
31
+ * agent the cached contract and it drives that contract, not its own
32
+ * draft.
30
33
  */
31
34
  import { listContractGadgets } from '@ggui-ai/protocol';
35
+ /**
36
+ * The action-entry members that change what the runtime DOES with a gesture,
37
+ * as opposed to how the action reads: `oneShot` arms the single-dispatch
38
+ * guard, `confirm` asks before firing, `nextStep` names the tool the agent is
39
+ * routed to. A stored card that lacks one the draft declares serves a card
40
+ * without that behaviour, so the agent is told. `label`, `description`,
41
+ * `icon`, `example` and `schema` stay tolerated differences.
42
+ */
43
+ export const LOAD_BEARING_ACTION_MEMBERS = ['oneShot', 'confirm', 'nextStep'];
44
+ /**
45
+ * Members the request DECLARES on `name` that the candidate's entry does not
46
+ * match. One direction, like the rest of coverage: a boolean member counts as
47
+ * declared only when `true` (`false` and absent both mean "off"), `nextStep`
48
+ * when present. A candidate that is stricter than the request (it carries a
49
+ * member the request does not) is not a gap. That holds for `nextStep` too,
50
+ * because the case that would matter there is already refused elsewhere: a
51
+ * stored `nextStep` naming a tool the requesting agent does not declare makes
52
+ * the candidate unfulfillable, and `isFulfillable` declines it before it is
53
+ * ever proposed (`blueprint-fulfillability.ts`).
54
+ */
55
+ function mismatchedActionMembers(request, candidate) {
56
+ const out = [];
57
+ for (const [name, wanted] of Object.entries(request.actionSpec ?? {})) {
58
+ const stored = candidate.actionSpec?.[name];
59
+ if (stored === undefined)
60
+ continue;
61
+ if (wanted.oneShot === true && stored.oneShot !== true)
62
+ out.push(`${name}.oneShot`);
63
+ if (wanted.confirm === true && stored.confirm !== true)
64
+ out.push(`${name}.confirm`);
65
+ if (wanted.nextStep !== undefined && stored.nextStep !== wanted.nextStep)
66
+ out.push(`${name}.nextStep`);
67
+ }
68
+ return out.sort();
69
+ }
32
70
  function keySet(map) {
33
71
  return new Set(Object.keys(map ?? {}));
34
72
  }
@@ -51,6 +89,7 @@ export function coverageGap(candidate, request) {
51
89
  context: missing(keySet(request.contextSpec), keySet(candidate.contextSpec)),
52
90
  streams: missing(keySet(request.streamSpec), keySet(candidate.streamSpec)),
53
91
  gadgets: missing(gadgetIdSet(request), gadgetIdSet(candidate)),
92
+ actionMembers: mismatchedActionMembers(request, candidate),
54
93
  };
55
94
  }
56
95
  /** True iff `candidate` declares every surface `request` declares —
@@ -61,5 +100,6 @@ export function covers(candidate, request) {
61
100
  gap.props.length === 0 &&
62
101
  gap.context.length === 0 &&
63
102
  gap.streams.length === 0 &&
64
- gap.gadgets.length === 0);
103
+ gap.gadgets.length === 0 &&
104
+ gap.actionMembers.length === 0);
65
105
  }
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint-durability.d.ts","sourceRoot":"","sources":["../../src/renders/blueprint-durability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,IAAI,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAChC,gCAAgC,GAChC,6BAA6B,GAC7B,+BAA+B,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,2BAA2B;IACtC,sEAAsE;;IAEtE,gEAAgE;;IAEhE;;;;;;;OAOG;;CAEwD,CAAC;AAW9D;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,GAAE,gBAAgB,CAAC,WAAW,CAAW,GACjD,gBAAgB,CA4BlB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,uBAAuB,GAAG,SAAS,EACzC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,iBAAiB,EAC5B,SAAS,GAAE,gBAAgB,CAAC,WAAW,CAAW,GACjD,OAAO,CAAC,IAAI,CAAC,CA0Df"}
1
+ {"version":3,"file":"blueprint-durability.d.ts","sourceRoot":"","sources":["../../src/renders/blueprint-durability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,IAAI,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAChC,gCAAgC,GAChC,6BAA6B,GAC7B,+BAA+B,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,2BAA2B;IACtC,sEAAsE;;IAEtE,gEAAgE;;IAEhE;;;;;;;OAOG;;CAEwD,CAAC;AAW9D;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,GAAE,gBAAgB,CAAC,WAAW,CAAW,GACjD,gBAAgB,CAiClB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,uBAAuB,GAAG,SAAS,EACzC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,iBAAiB,EAC5B,SAAS,GAAE,gBAAgB,CAAC,WAAW,CAAW,GACjD,OAAO,CAAC,IAAI,CAAC,CA0Df"}
@@ -56,6 +56,11 @@ export function projectDurableBlueprint(blueprint, appId, codeHash, createdBy =
56
56
  ...(blueprint.sourceCodeHash !== undefined
57
57
  ? { sourceCodeHash: blueprint.sourceCodeHash }
58
58
  : {}),
59
+ // ggui#1280 — the minting engine's build, admitted at registration.
60
+ // Written once here at mint (a dedup never reaches this projection) and
61
+ // never rewritten. The registry's vector-store row carries the same
62
+ // value (ggui#1476).
63
+ ...(blueprint.build !== undefined ? { build: blueprint.build } : {}),
59
64
  };
60
65
  }
61
66
  /**
@@ -180,7 +180,35 @@ export interface MatchBlueprintOptions {
180
180
  * stability-sensitive caller cannot afford (ggui#607).
181
181
  */
182
182
  readonly disableSemantic?: boolean;
183
+ /**
184
+ * ggui#1568 — WHY `disableSemantic` is set, so the trace never names a
185
+ * cause that did not hold. `'exact-only-policy'` (the default) is the
186
+ * ggui#607 reuse policy. `'exclusion-unavailable'` means the deployment
187
+ * could not say which rows are reserved from the semantic tier
188
+ * ({@link excludeFromSemantic}), so it turned the tier off rather than
189
+ * risk offering one. Read only when `disableSemantic` is true.
190
+ */
191
+ readonly disableSemanticCause?: 'exact-only-policy' | 'exclusion-unavailable';
192
+ /**
193
+ * ggui#1568 — rows the deployment reserves from the semantic tier, each
194
+ * named by {@link semanticExclusionKey}. A named row is dropped straight
195
+ * after retrieval, so it is never offered to the judge, never returned as
196
+ * a candidate and never reused by similarity. It stays reachable by its
197
+ * exact key: exclusion governs how a row is FOUND, never whether it can be
198
+ * served to a request that names it. Retrieval over-fetches by the set's
199
+ * size, so the pool the judge ranks is still `topK` deep. A vector store
200
+ * that clamps its `topK` returns fewer rows than asked, and the pool is
201
+ * then shallower: fewer reuses, never a reserved row.
202
+ */
203
+ readonly excludeFromSemantic?: ReadonlySet<string>;
183
204
  }
205
+ /**
206
+ * ggui#1568 — the key {@link MatchBlueprintOptions.excludeFromSemantic}
207
+ * names a row by: its `(contractKey, variantKey)` pair, the same pair the
208
+ * exact tier resolves. Unambiguous by construction (JSON array), so no two
209
+ * different pairs share a key.
210
+ */
211
+ export declare function semanticExclusionKey(contractKey: string, variantKey: string): string;
184
212
  /**
185
213
  * Walk the matcher and return the decision.
186
214
  *
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint-matcher.d.ts","sourceRoot":"","sources":["../../src/renders/blueprint-matcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blueprint-matcher.d.ts","sourceRoot":"","sources":["../../src/renders/blueprint-matcher.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,17 @@ const EMPTY_GAP = {
14
14
  context: [],
15
15
  streams: [],
16
16
  gadgets: [],
17
+ actionMembers: [],
17
18
  };
19
+ /**
20
+ * ggui#1568 — the key {@link MatchBlueprintOptions.excludeFromSemantic}
21
+ * names a row by: its `(contractKey, variantKey)` pair, the same pair the
22
+ * exact tier resolves. Unambiguous by construction (JSON array), so no two
23
+ * different pairs share a key.
24
+ */
25
+ export function semanticExclusionKey(contractKey, variantKey) {
26
+ return JSON.stringify([contractKey, variantKey]);
27
+ }
18
28
  const DEFAULT_TOP_K = 20;
19
29
  // The cosine gate before the judge — ONE FLOOR PER QUERY KIND, because the
20
30
  // two kinds of query sit on two scales (ggui#606).
@@ -221,10 +231,13 @@ export async function matchBlueprint(deps, scope, query, options = {}) {
221
231
  await ensured;
222
232
  }
223
233
  if (options.disableSemantic === true) {
224
- // Exact-only reuse policy (ggui#607): the semantic tier is
225
- // switched off for this request — report the miss without
226
- // spending the retrieval or the judge call.
227
- const reason = 'exact-only policy: no canonical match — a new interface will be generated';
234
+ // The semantic tier is switched off for this request: the exact-only
235
+ // reuse policy (ggui#607), or a deployment that cannot say which rows
236
+ // are reserved from it (ggui#1568). Report the miss, naming which,
237
+ // without spending the retrieval or the judge call.
238
+ const reason = options.disableSemanticCause === 'exclusion-unavailable'
239
+ ? 'no-match: no canonical match, and similar-interface reuse is unavailable for this request — a new interface will be generated'
240
+ : 'exact-only policy: no canonical match — a new interface will be generated';
228
241
  emit({ decision: 'no-match', strategy: 'semantic', reason, candidates: [] });
229
242
  return { strategy: 'no-match', reason, candidates: [] };
230
243
  }
@@ -236,6 +249,9 @@ export async function matchBlueprint(deps, scope, query, options = {}) {
236
249
  // Miss buckets distinguish cosine-gate, no-LLM, judge-declined,
237
250
  // low-confidence, defense.
238
251
  let candidates = [];
252
+ const excluded = options.excludeFromSemantic;
253
+ const excludedCount = excluded?.size ?? 0;
254
+ let droppedByExclusion = 0;
239
255
  try {
240
256
  // ggui#606: compose the query the way stored vectors are composed
241
257
  // (`composeEmbeddingInput(contract, intent)`), so a candidate is scored
@@ -244,7 +260,14 @@ export async function matchBlueprint(deps, scope, query, options = {}) {
244
260
  const ragArg = query.contract !== undefined
245
261
  ? { intent: trimmedIntent, contract: query.contract }
246
262
  : { intent: trimmedIntent };
247
- candidates = await findBlueprintsByEmbedding(deps.registry, scope, ragArg, { kind, topK });
263
+ const retrieved = await findBlueprintsByEmbedding(deps.registry, scope, ragArg, { kind, topK: topK + excludedCount });
264
+ // ggui#1568 — a reserved row leaves here, before the cosine gate, the
265
+ // judge, the trace and the result: nothing downstream ever sees it.
266
+ const kept = excluded === undefined || excludedCount === 0
267
+ ? retrieved
268
+ : retrieved.filter((c) => !excluded.has(semanticExclusionKey(c.blueprint.contractKey, c.blueprint.variantKey)));
269
+ droppedByExclusion = retrieved.length - kept.length;
270
+ candidates = kept.slice(0, topK);
248
271
  }
249
272
  catch (err) {
250
273
  const msg = err instanceof Error ? err.message : String(err);
@@ -258,11 +281,18 @@ export async function matchBlueprint(deps, scope, query, options = {}) {
258
281
  return { strategy: 'no-match', reason, candidates: [] };
259
282
  }
260
283
  if (candidates.length === 0) {
261
- const reason = 'no-match: no candidates in scope — first registration of this kind';
284
+ // ggui#1568 — "first registration" is false when rows were retrieved and
285
+ // every one was reserved; the reason says which it was.
286
+ const reason = droppedByExclusion > 0
287
+ ? 'no-match: no saved interface is available for reuse — a new one will be generated'
288
+ : 'no-match: no candidates in scope — first registration of this kind';
289
+ const traceReason = droppedByExclusion > 0
290
+ ? `no-match: ${droppedByExclusion} candidates retrieved, every one reserved from the semantic tier by the deployment`
291
+ : reason;
262
292
  emit({
263
293
  decision: 'no-match',
264
294
  strategy: 'semantic',
265
- reason,
295
+ reason: traceReason,
266
296
  candidates: [],
267
297
  });
268
298
  return { strategy: 'no-match', reason, candidates: [] };
@@ -463,6 +493,8 @@ function coverageGapNote(gap) {
463
493
  parts.push(`streams: ${gap.streams.join(', ')}`);
464
494
  if (gap.gadgets.length > 0)
465
495
  parts.push(`gadgets: ${gap.gadgets.join(', ')}`);
496
+ if (gap.actionMembers.length > 0)
497
+ parts.push(`action members: ${gap.actionMembers.join(', ')}`);
466
498
  if (parts.length === 0)
467
499
  return '';
468
500
  return ` [coverage gap — the request declares surfaces this cached UI lacks (${parts.join('; ')}); agent override is the safety valve]`;