@kumwe/studio-testkit 0.1.0-alpha.10

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 (304) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/THIRD_PARTY_NOTICES.md +9 -0
  4. package/conformance/authoring-web/non-drag-move-equivalence.json +199 -0
  5. package/conformance/renderer-web/blob-default-deny.json +47 -0
  6. package/conformance/renderer-web/chart-fallback.json +39 -0
  7. package/conformance/renderer-web/complete-catalog.json +634 -0
  8. package/conformance/renderer-web/escaped-heading.json +28 -0
  9. package/conformance/renderer-web/interactive-behaviors.json +226 -0
  10. package/conformance/renderer-web/presentation-capabilities.json +76 -0
  11. package/conformance/renderer-web/responsive-grid.json +33 -0
  12. package/conformance/renderer-web/security-fallbacks.json +169 -0
  13. package/conformance/rich-text/advanced.first-party.json +67 -0
  14. package/conformance/rich-text/blocks.structural.json +57 -0
  15. package/conformance/rich-text/document.multi-block.json +74 -0
  16. package/conformance/rich-text/embed.hard-break.json +24 -0
  17. package/conformance/rich-text/marks.nested.json +29 -0
  18. package/conformance/rich-text/offsets.astral.json +24 -0
  19. package/conformance/rich-text/paragraph.plain.json +20 -0
  20. package/conformance/rich-text/spans.adjacent.json +27 -0
  21. package/corpus-manifest.json +1212 -0
  22. package/dist/host-testbed.d.ts +71 -0
  23. package/dist/host-testbed.d.ts.map +1 -0
  24. package/dist/host-testbed.js +782 -0
  25. package/dist/host-testbed.js.map +1 -0
  26. package/dist/http-host-adapter.d.ts +74 -0
  27. package/dist/http-host-adapter.d.ts.map +1 -0
  28. package/dist/http-host-adapter.js +264 -0
  29. package/dist/http-host-adapter.js.map +1 -0
  30. package/dist/index.d.ts +112 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +211 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/web-conformance.d.ts +105 -0
  35. package/dist/web-conformance.d.ts.map +1 -0
  36. package/dist/web-conformance.js +72 -0
  37. package/dist/web-conformance.js.map +1 -0
  38. package/fixtures/authoring-message-catalog.en.json +649 -0
  39. package/fixtures/block.grid.example.json +76 -0
  40. package/fixtures/block.price.example.json +69 -0
  41. package/fixtures/blueprint.product.example.json +92 -0
  42. package/fixtures/command.move-node.example.json +18 -0
  43. package/fixtures/content-model.product.example.json +141 -0
  44. package/fixtures/design-vocabulary.example.json +85 -0
  45. package/fixtures/entry.product.example.json +55 -0
  46. package/fixtures/field-adapter.example.json +27 -0
  47. package/fixtures/host-capabilities.example.json +42 -0
  48. package/fixtures/host-error.conflict.example.json +23 -0
  49. package/fixtures/host-operations.example.json +270 -0
  50. package/fixtures/inspector.example.json +17 -0
  51. package/fixtures/media-asset.example.json +29 -0
  52. package/fixtures/media-asset.processing.example.json +15 -0
  53. package/fixtures/media-reference.example.json +26 -0
  54. package/fixtures/media-upload-grant.example.json +14 -0
  55. package/fixtures/media-upload-session.transferring.example.json +22 -0
  56. package/fixtures/migration.example.json +22 -0
  57. package/fixtures/pattern.example.json +49 -0
  58. package/fixtures/plugin.example.json +49 -0
  59. package/fixtures/preview.render.example.json +15 -0
  60. package/fixtures/provenance.example.json +38 -0
  61. package/fixtures/rich-text.example.json +48 -0
  62. package/fixtures/studio-config.example.json +139 -0
  63. package/fixtures/theme.example.json +123 -0
  64. package/fixtures/unresolved-contribution.example.json +23 -0
  65. package/invalid/binding-projection-vector.unknown-status.json +85 -0
  66. package/invalid/blueprint.control-character-member.json +59 -0
  67. package/invalid/blueprint.forbidden-property-member.json +61 -0
  68. package/invalid/blueprint.invalid-node-id.json +57 -0
  69. package/invalid/blueprint.invalid-slot-name.json +59 -0
  70. package/invalid/blueprint.published-empty-roots.json +45 -0
  71. package/invalid/blueprint.revoking-slot-marker.json +57 -0
  72. package/invalid/blueprint.unknown-member.json +58 -0
  73. package/invalid/command-vector.unknown-error-code.json +103 -0
  74. package/invalid/command.empty-batch.json +17 -0
  75. package/invalid/command.forbidden-id-map-member.json +20 -0
  76. package/invalid/command.malformed-size-role.json +18 -0
  77. package/invalid/command.negative-position.json +20 -0
  78. package/invalid/command.nested-batch.json +24 -0
  79. package/invalid/command.pattern-in-batch.json +40 -0
  80. package/invalid/command.reset-inherited-property-in-batch.json +24 -0
  81. package/invalid/command.unknown-member.json +23 -0
  82. package/invalid/command.wrong-contract-version.json +22 -0
  83. package/invalid/content-model.published-empty.json +22 -0
  84. package/invalid/design-vocabulary.unknown-control-kind.json +38 -0
  85. package/invalid/entry.forbidden-value-member.json +23 -0
  86. package/invalid/entry.invalid-locale.json +59 -0
  87. package/invalid/host-capabilities.invalid-protocol-version.json +40 -0
  88. package/invalid/host-sequence.pending-expectation.json +52 -0
  89. package/invalid/host-sequence.preview-render-missing-request-id.json +50 -0
  90. package/invalid/inspector.empty-block-types.json +20 -0
  91. package/invalid/media-reference.missing-accessibility.json +25 -0
  92. package/invalid/media-upload-grant.insecure-url.json +14 -0
  93. package/invalid/media-upload-session.complete-without-asset.json +20 -0
  94. package/invalid/migration.empty-artifact-kinds.json +22 -0
  95. package/invalid/preview-message.activated-unknown-interaction.json +16 -0
  96. package/invalid/preview-message.duplicate-marker.json +24 -0
  97. package/invalid/preview-message.invalid-digest.json +19 -0
  98. package/invalid/preview-message.invalid-marker-grammar.json +19 -0
  99. package/invalid/preview-message.missing-marker-map.json +20 -0
  100. package/invalid/preview-message.missing-render-request-id.json +18 -0
  101. package/invalid/preview-message.unknown-type.json +13 -0
  102. package/invalid/preview-message.viewport-height-too-small.json +13 -0
  103. package/invalid/preview-message.viewport-role-and-size.json +16 -0
  104. package/invalid/preview-message.viewport-unsafe-role.json +13 -0
  105. package/invalid/rich-text.embedded-html.json +13 -0
  106. package/invalid/rich-text.unknown-mark.json +19 -0
  107. package/invalid/studio-chart.script-config.json +10 -0
  108. package/invalid/studio-drawing.svg-payload.json +10 -0
  109. package/invalid/studio-money.float.json +8 -0
  110. package/invalid/studio-presentation.css-injection.json +8 -0
  111. package/invalid/studio-table.html-cell.json +8 -0
  112. package/invalid/theme.unknown-member.json +128 -0
  113. package/package.json +54 -0
  114. package/studio-release.json +18 -0
  115. package/vectors/binding-projection/app-content-fields.resolved.json +286 -0
  116. package/vectors/binding-projection/field-removed.diagnostic.json +135 -0
  117. package/vectors/binding-projection/model-revision-mismatch.diagnostic.json +124 -0
  118. package/vectors/canonical/array-order.json +13 -0
  119. package/vectors/canonical/control-characters.json +13 -0
  120. package/vectors/canonical/depth-exceeded.json +21 -0
  121. package/vectors/canonical/empty-containers.json +14 -0
  122. package/vectors/canonical/forbidden-member.json +14 -0
  123. package/vectors/canonical/member-order.json +16 -0
  124. package/vectors/canonical/negative-zero.json +13 -0
  125. package/vectors/canonical/nested-order.json +19 -0
  126. package/vectors/canonical/non-ascii.json +13 -0
  127. package/vectors/canonical/numbers.json +16 -0
  128. package/vectors/canonical/string-escapes.json +13 -0
  129. package/vectors/canonical/surrogate-pair.json +13 -0
  130. package/vectors/command/apply-pattern.colliding-id.error.json +97 -0
  131. package/vectors/command/apply-pattern.incomplete-id-map.error.json +111 -0
  132. package/vectors/command/apply-pattern.two-roots.json +259 -0
  133. package/vectors/command/batch.atomic-failure.error.json +100 -0
  134. package/vectors/command/batch.insert-and-configure.json +197 -0
  135. package/vectors/command/batch.size-roles.json +180 -0
  136. package/vectors/command/duplicate-node.existing-id.error.json +88 -0
  137. package/vectors/command/duplicate-node.explicit-destination.json +183 -0
  138. package/vectors/command/duplicate-node.incomplete-id-map.error.json +91 -0
  139. package/vectors/command/duplicate-node.subtree.json +201 -0
  140. package/vectors/command/insert-node.duplicate-id.error.json +87 -0
  141. package/vectors/command/insert-node.inner-duplicate-id.error.json +115 -0
  142. package/vectors/command/insert-node.invalid-index.error.json +87 -0
  143. package/vectors/command/insert-node.root.json +162 -0
  144. package/vectors/command/insert-node.slot.json +167 -0
  145. package/vectors/command/mode.blueprint.set-field-value.error.json +76 -0
  146. package/vectors/command/mode.blueprint.set-property.json +131 -0
  147. package/vectors/command/mode.content.insert-node.error.json +88 -0
  148. package/vectors/command/mode.hybrid.batch-atomic.error.json +158 -0
  149. package/vectors/command/mode.hybrid.insert-allowed.json +263 -0
  150. package/vectors/command/mode.hybrid.insert-designer-slot.error.json +145 -0
  151. package/vectors/command/mode.hybrid.insert-disallowed-type.error.json +145 -0
  152. package/vectors/command/mode.hybrid.insert-roots.error.json +143 -0
  153. package/vectors/command/mode.hybrid.remove-locked.error.json +130 -0
  154. package/vectors/command/mode.hybrid.reorder-with-locked.json +239 -0
  155. package/vectors/command/mode.hybrid.set-property.error.json +132 -0
  156. package/vectors/command/mode.hybrid.slot-marker-disallowed.error.json +125 -0
  157. package/vectors/command/mode.hybrid.slot-marker-insert.json +223 -0
  158. package/vectors/command/mode.hybrid.slot-marker-other-slot.error.json +125 -0
  159. package/vectors/command/mode.model.remove-node.error.json +75 -0
  160. package/vectors/command/mode.read-only.set-property.error.json +77 -0
  161. package/vectors/command/move-node.into-self.error.json +95 -0
  162. package/vectors/command/move-node.reparent.json +196 -0
  163. package/vectors/command/move-node.within-roots.json +188 -0
  164. package/vectors/command/remove-binding.base.json +159 -0
  165. package/vectors/command/remove-binding.missing.error.json +75 -0
  166. package/vectors/command/remove-node.empties-slot.json +167 -0
  167. package/vectors/command/remove-node.missing.error.json +74 -0
  168. package/vectors/command/remove-node.nested.json +192 -0
  169. package/vectors/command/reorder-children.not-permutation.error.json +85 -0
  170. package/vectors/command/reorder-children.roots.json +182 -0
  171. package/vectors/command/reorder-children.slot.json +192 -0
  172. package/vectors/command/reset-inherited-property.missing.error.json +82 -0
  173. package/vectors/command/reset-inherited-property.single-viewport.json +151 -0
  174. package/vectors/command/reset-inherited-property.two-viewports.json +168 -0
  175. package/vectors/command/restore-node.inner-duplicate-id.error.json +115 -0
  176. package/vectors/command/restore-node.subtree-into-slot.json +195 -0
  177. package/vectors/command/set-binding.add.json +159 -0
  178. package/vectors/command/set-binding.replace.json +178 -0
  179. package/vectors/command/set-property.add.json +143 -0
  180. package/vectors/command/set-property.replace.json +146 -0
  181. package/vectors/command/set-property.viewport-add.json +148 -0
  182. package/vectors/command/set-size-role.base.json +144 -0
  183. package/vectors/command/set-size-role.duplicate.json +148 -0
  184. package/vectors/command/set-size-role.viewport-add.json +154 -0
  185. package/vectors/command/unset-property.base.json +143 -0
  186. package/vectors/command/unset-property.missing.error.json +75 -0
  187. package/vectors/command/unset-property.viewport.json +154 -0
  188. package/vectors/command/unset-size-role.missing.error.json +78 -0
  189. package/vectors/command/unset-size-role.viewport.json +154 -0
  190. package/vectors/host/artifact.dependencies.result.json +35 -0
  191. package/vectors/host/artifact.load.stored.json +36 -0
  192. package/vectors/host/artifact.load.unknown.error.json +37 -0
  193. package/vectors/host/artifact.publish.accepted.json +37 -0
  194. package/vectors/host/artifact.publish.forbidden.error.json +37 -0
  195. package/vectors/host/artifact.publish.stale.error.json +38 -0
  196. package/vectors/host/artifact.save.accepted.json +38 -0
  197. package/vectors/host/artifact.save.forbidden.error.json +38 -0
  198. package/vectors/host/artifact.save.stale.error.json +39 -0
  199. package/vectors/host/artifact.unpublish.stale.error.json +38 -0
  200. package/vectors/host/envelope.malformed-context.error.json +36 -0
  201. package/vectors/host/envelope.protocol-version.error.json +36 -0
  202. package/vectors/host/envelope.stale-generation.error.json +36 -0
  203. package/vectors/host/localization.messages.unknown-locale.error.json +36 -0
  204. package/vectors/host/media.abort-upload.unknown.error.json +35 -0
  205. package/vectors/host/media.authorize-upload.granted.json +37 -0
  206. package/vectors/host/media.authorize-upload.path-filename.error.json +39 -0
  207. package/vectors/host/media.authorize-upload.too-large.error.json +38 -0
  208. package/vectors/host/media.complete-upload.unknown.error.json +36 -0
  209. package/vectors/host/media.get.unknown.json +34 -0
  210. package/vectors/host/media.import-external.private-host.error.json +36 -0
  211. package/vectors/host/media.list.cursor.error.json +36 -0
  212. package/vectors/host/media.list.limit.error.json +35 -0
  213. package/vectors/host/media.upload-status.unknown.error.json +35 -0
  214. package/vectors/host/model.get.stored.json +37 -0
  215. package/vectors/host/model.list.authorized.json +31 -0
  216. package/vectors/host/permission.explain.withheld.json +34 -0
  217. package/vectors/host/permission.refresh.snapshot.json +31 -0
  218. package/vectors/host/recovery.load.absent.json +31 -0
  219. package/vectors/host/telemetry.emit.accepted.json +37 -0
  220. package/vectors/host/telemetry.emit.non-primitive.error.json +40 -0
  221. package/vectors/host-sequence/artifact.publish.changed-intent.sequence.json +75 -0
  222. package/vectors/host-sequence/artifact.publish.idempotent-replay.sequence.json +111 -0
  223. package/vectors/host-sequence/preview.cancel.cross-context.sequence.json +78 -0
  224. package/vectors/host-sequence/preview.render.cancelled.sequence.json +75 -0
  225. package/vectors/host-sequence/recovery.store.canonical-number.sequence.json +72 -0
  226. package/vectors/host-sequence/recovery.store.changed-context.sequence.json +61 -0
  227. package/vectors/host-sequence/recovery.store.rate-limited.sequence.json +93 -0
  228. package/vectors/host-sequence/recovery.store.resource-scope.sequence.json +61 -0
  229. package/vectors/host-sequence/recovery.store.wrong-operation-id.sequence.json +56 -0
  230. package/vectors/media/accept.plan-deterministic.json +26 -0
  231. package/vectors/media/accept.size-at-boundary.json +26 -0
  232. package/vectors/media/cancel.complete-noop.json +30 -0
  233. package/vectors/media/cancel.requested.json +30 -0
  234. package/vectors/media/cancel.transferring.json +30 -0
  235. package/vectors/media/cancel.verifying.json +30 -0
  236. package/vectors/media/reject.disallowed-kind.json +23 -0
  237. package/vectors/media/reject.filename-empty.json +22 -0
  238. package/vectors/media/reject.filename-path.json +23 -0
  239. package/vectors/media/reject.size-one-byte-over.json +23 -0
  240. package/vectors/media/retry.fresh-session.json +26 -0
  241. package/vectors/preview/canonical-preorder.json +102 -0
  242. package/vectors/preview/empty-draft.json +36 -0
  243. package/vectors/schema-profile/alternative-limit.accepted.json +95 -0
  244. package/vectors/schema-profile/alternative-limit.rejected.json +92 -0
  245. package/vectors/schema-profile/array-composition.accepted.json +35 -0
  246. package/vectors/schema-profile/byte-limit.accepted.json +30 -0
  247. package/vectors/schema-profile/byte-limit.rejected.json +26 -0
  248. package/vectors/schema-profile/closed-object.accepted.json +38 -0
  249. package/vectors/schema-profile/decimal-multiple.accepted.json +54 -0
  250. package/vectors/schema-profile/depth-limit.accepted.json +90 -0
  251. package/vectors/schema-profile/depth-limit.rejected.json +88 -0
  252. package/vectors/schema-profile/description-limit.accepted.json +29 -0
  253. package/vectors/schema-profile/description-limit.rejected.json +25 -0
  254. package/vectors/schema-profile/diagnostic-precedence.rejected.json +26 -0
  255. package/vectors/schema-profile/duplicate-dependent-required.rejected.json +21 -0
  256. package/vectors/schema-profile/duplicate-required.rejected.json +18 -0
  257. package/vectors/schema-profile/empty-combinator.rejected.json +17 -0
  258. package/vectors/schema-profile/empty-enum.rejected.json +17 -0
  259. package/vectors/schema-profile/enum-limit.accepted.json +89 -0
  260. package/vectors/schema-profile/enum-limit.rejected.json +84 -0
  261. package/vectors/schema-profile/examples-limit.accepted.json +35 -0
  262. package/vectors/schema-profile/examples-limit.rejected.json +31 -0
  263. package/vectors/schema-profile/format-keyword.rejected.json +17 -0
  264. package/vectors/schema-profile/forward-reference-path-precedence.rejected.json +20 -0
  265. package/vectors/schema-profile/invalid-pointer.rejected.json +18 -0
  266. package/vectors/schema-profile/json-depth-limit.accepted.json +278 -0
  267. package/vectors/schema-profile/json-depth-limit.rejected.json +276 -0
  268. package/vectors/schema-profile/json-item-limit.accepted.json +686 -0
  269. package/vectors/schema-profile/json-item-limit.rejected.json +682 -0
  270. package/vectors/schema-profile/json-property-limit.accepted.json +1031 -0
  271. package/vectors/schema-profile/json-property-limit.rejected.json +1028 -0
  272. package/vectors/schema-profile/local-reference.accepted.json +28 -0
  273. package/vectors/schema-profile/memoized-diagnostic.accepted.json +31 -0
  274. package/vectors/schema-profile/node-limit.accepted.json +1097 -0
  275. package/vectors/schema-profile/node-limit.rejected.json +1094 -0
  276. package/vectors/schema-profile/non-object-root.rejected.json +9 -0
  277. package/vectors/schema-profile/non-schema-reference.rejected.json +21 -0
  278. package/vectors/schema-profile/object-key-limit.accepted.json +32 -0
  279. package/vectors/schema-profile/object-key-limit.rejected.json +28 -0
  280. package/vectors/schema-profile/open-root.rejected.json +13 -0
  281. package/vectors/schema-profile/percent-encoded-pointer.rejected.json +26 -0
  282. package/vectors/schema-profile/property-name-limit.accepted.json +543 -0
  283. package/vectors/schema-profile/property-name-limit.rejected.json +536 -0
  284. package/vectors/schema-profile/recursive-diagnostic-precedence.rejected.json +30 -0
  285. package/vectors/schema-profile/recursive-reference.rejected.json +24 -0
  286. package/vectors/schema-profile/reference-fanout.accepted.json +662 -0
  287. package/vectors/schema-profile/reference-length-limit.accepted.json +45 -0
  288. package/vectors/schema-profile/reference-length-limit.rejected.json +39 -0
  289. package/vectors/schema-profile/reference-limit.accepted.json +416 -0
  290. package/vectors/schema-profile/reference-limit.rejected.json +415 -0
  291. package/vectors/schema-profile/reference-vs-keyword-precedence.rejected.json +22 -0
  292. package/vectors/schema-profile/reserved-pointer.rejected.json +26 -0
  293. package/vectors/schema-profile/root-diagnostic-precedence.rejected.json +16 -0
  294. package/vectors/schema-profile/root-vs-reference-precedence.rejected.json +19 -0
  295. package/vectors/schema-profile/schema-map-limit.accepted.json +539 -0
  296. package/vectors/schema-profile/schema-map-limit.rejected.json +536 -0
  297. package/vectors/schema-profile/semantic-recursion-precedence.rejected.json +21 -0
  298. package/vectors/schema-profile/semantic-reference-precedence.rejected.json +21 -0
  299. package/vectors/schema-profile/title-limit.accepted.json +29 -0
  300. package/vectors/schema-profile/title-limit.rejected.json +25 -0
  301. package/vectors/schema-profile/unresolved-reference.rejected.json +17 -0
  302. package/vectors/schema-profile/unsafe-dependent-required.rejected.json +24 -0
  303. package/vectors/schema-profile/unsafe-member.rejected.json +17 -0
  304. package/vectors/schema-profile/unsafe-required.rejected.json +17 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kumwe Studio contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # `@kumwe/studio-testkit`
2
+
3
+ Status: pre-Gate-A foundation alpha. Its conformance helpers do not by themselves constitute gate evidence.
4
+
5
+ The current alpha combines fixture builders and `assertBlueprintConforms` with deterministic host and HTTP
6
+ testbeds plus executable command, canonical, host, host-sequence, media, preview, property-schema,
7
+ binding-projection, renderer-web, rich-text, and authoring-web corpus runners. Those helpers let another
8
+ implementation replay the same portable assertions without adopting Studio internals. A green repository
9
+ replay is implementation evidence, not an accepted gate or support claim; every advertised profile still
10
+ needs exact-candidate evidence and independent review.
11
+
12
+ Package subpaths under `@kumwe/studio-testkit/fixtures/<filename>` contain byte-identical copies of the
13
+ canonical valid examples, including separate MediaAsset and persisted MediaReference examples. There
14
+ is no aggregate runtime `fixtures` export. The helpers do not depend on Vitest or another test runner,
15
+ so consumers may call the current assertion from any JavaScript test environment.
16
+
17
+ `fixtures/authoring-message-catalog.en.json` is the byte-identical canonical English shell catalog.
18
+ It lets hosts validate localization imports and parameter declarations without importing the Lit
19
+ runtime. Its schema ships with `@kumwe/studio-protocol`.
20
+
21
+ ## Host testbed
22
+
23
+ `createTestbedHost(options)` builds a deterministic, fully in-memory `HostAdapter` reference host
24
+ for conformance and failure testing. Every standard port is implemented against
25
+ seeded fixtures (`documents`, `resources`, `mediaAssets`, `messages`, `permissions`, and an
26
+ optional asynchronous preview `render` callback). Each operation first validates connectivity and the
27
+ `HostRequestContext`, including exact operation-capability matching, wire protocol, and current session
28
+ generation. Every failure rejects with `TestbedHostError`, whose `error` document satisfies
29
+ `isHostPortError`. `TestbedHostError` extends the protocol's public `HostPortFailure`, so the same
30
+ rejection satisfies `isHostPortFailure` without consumers depending on the testbed-specific class.
31
+ Stale-generation rejection is `invalid-request` with the exact
32
+ `studio.host/stale-session-generation` diagnostic used for whole-handle invalidation; unrelated
33
+ invalid requests do not carry that meaning. `not-found` messages never disclose which identifiers
34
+ exist. Seed artifact kinds, revisions, and the optional initial `sessionGeneration` are retained
35
+ exactly; subsequent revisions advance as deterministic counters (`<id>-r<n>`).
36
+ Optimistic-concurrency conflicts return the safe current revision without changing stored state, and
37
+ search/media pagination uses opaque cursors. The returned `controls` drive
38
+ failure scenarios: `disconnect()`/`reconnect()` for retryable `unavailable` outages,
39
+ `failNext(port, operation, category)` for exactly one injected failure (retryable only for
40
+ `unavailable` and `rate-limited`), and `setPermissions(...)`, which replaces the permission list
41
+ and bumps the session generation so stale contexts reject as `invalid-request`. `revisionOf(id)`,
42
+ the `sessionGeneration` getter, and the recorded `telemetryEvents` support assertions. The logical
43
+ `advanceClock()` control and declared fixed-window policies make rate-limit tests deterministic.
44
+ Idempotency records use the published scope/preimage, coalesce matching accepted mutations, reject
45
+ changed intent, and remove failed attempts. Preview render controls expose pending and delivered
46
+ outcomes so cancellation proves that late output is discarded. An injected renderer must return the
47
+ originating draft digest and render `requestId`; an uncorrelated result fails as non-retryable
48
+ `internal` and is never recorded as delivered.
49
+ `createHostRequestContextFixture` builds request envelopes; callers provide the exact operation ID for
50
+ strict hosts. The `allowTestOperationId` option permits only the fixture wildcard for broad unit drills,
51
+ defaults off, and must never be enabled for conformance replay. The testbed uses no wall clock,
52
+ randomness, or timers, so runs are fully reproducible.
53
+
54
+ ## Host conformance corpus
55
+
56
+ `@kumwe/studio-testkit/vectors/host/<filename>` publishes the executable assertion set for
57
+ `studio.profile/host-baseline`. Each vector is language-neutral JSON conforming to
58
+ `host-vector.schema.json`: it fixes the host state to seed (`given`), the request envelope and
59
+ argument to send (`context`, `argument`), and the required outcome (`expect`) — an accepted result
60
+ with its revision behaviour, or one category of the closed error taxonomy with its retry
61
+ classification and non-disclosure obligations. Every precondition is a condition a real host
62
+ reproduces, never a test double, so an adapter written in any language replays the corpus in its own
63
+ test suite without executing Studio code. The reference host's own claim against the profile is
64
+ `test/host-vectors.test.ts`. The profile records the obligations it does not yet assert; consult
65
+ `docs/contracts/conformance-profiles.md` before treating a green replay as complete coverage.
66
+
67
+ `@kumwe/studio-testkit/vectors/host-sequence/<filename>` publishes the additive assertion set for
68
+ `studio.profile/host-baseline-v2`. The bounded sequence shape expresses pending and settled operations,
69
+ fixed-window policies, explicit clock advances and renderer completions, and final state. Nine vectors
70
+ cover in-flight/completed replay, changed argument/context refusal, canonical numeric intent,
71
+ resource-scope separation, wrong-operation refusal, failed-attempt retry after a window reset, matching
72
+ preview cancellation with late-result discard, and cross-context cancellation isolation. The
73
+ TypeScript replay is `test/host-sequence-vectors.test.ts`; other runtimes consume the same JSON and
74
+ schema directly. The exact assertion list and deliberately recorded limits live in
75
+ `docs/contracts/conformance-profiles.md`.
76
+
77
+ The host corpus includes `model.get` and `model.list` exchanges over seeded content models. The testbed
78
+ resolves exact ID/version/revision coordinates and lists detached projections in deterministic coordinate
79
+ order. The injected HTTP adapter maps the same operations to `POST /ports/model/get` and
80
+ `POST /ports/model/list`.
81
+
82
+ `@kumwe/studio-testkit/vectors/canonical/<filename>` publishes the canonical serialization corpus:
83
+ each vector carries a bounded value and either the exact canonical string with the SRI-style digest of
84
+ its UTF-8 bytes, or the stable reason the canonical form refuses it. Its expectations were produced by
85
+ an independent canonicalizer rather than recorded from the reference implementation, so replaying it
86
+ is a cross-implementation check.
87
+
88
+ `@kumwe/studio-testkit/vectors/preview/<filename>` publishes the executable assertion set for
89
+ `studio.profile/preview-identity-v1`. Each complete Blueprint fixes the lowercase SHA-256 digest of
90
+ its canonical UTF-8 bytes, the artifact/revision/digest render tuple with a unique attempt ID, and the
91
+ exact marker preorder plus one-to-one marker map. The reference replay is
92
+ `test/preview-vectors.test.ts`; another runtime hashes and traverses the same JSON without executing
93
+ Studio code.
94
+
95
+ `@kumwe/studio-testkit/vectors/schema-profile/<filename>` publishes the executable assertion set for
96
+ `studio.profile/schema-property`. Accepted candidates carry instance verdicts and the first stable
97
+ keyword/pointer diagnostic; rejected candidates carry the closed admission code and schema pointer.
98
+ `runSchemaProfileVector(vector)` replays one vector through the TypeScript reference without consulting
99
+ its expected verdicts or diagnostics. Other runtimes consume the same JSON directly and do not execute
100
+ testkit code. Boundary vectors identify their published limit, exact value, and side of the ceiling;
101
+ the corpus contains exactly one at-limit and one exact-plus-one case for every advertised limit. Its
102
+ acyclic-reference fan-out case must complete without expanding the reference DAG exponentially. The
103
+ TypeScript reference exposes the full ordered set of distinct failures: repeated branches do not
104
+ duplicate an otherwise identical keyword, instance pointer, and message diagnostic.
105
+ Competing-failure vectors also pin one admission order across root invariants, local-reference
106
+ resolution, recursion, and structural keyword checks.
107
+
108
+ `@kumwe/studio-testkit/vectors/binding-projection/<filename>` publishes
109
+ `studio.profile/binding-projection-v1`. Each vector carries a complete Blueprint, authorized content model,
110
+ block definitions and exact normalized candidate/control/status/diagnostic output.
111
+ `runBindingProjectionVector(vector)` replays one vector without reading its expected result; another runtime
112
+ consumes the same JSON directly. The runner and reference projection never mutate vector input.
113
+
114
+ `@kumwe/studio-testkit/corpus-manifest.json` carries the sha256 digest of every file in the published
115
+ corpus, grouped by the directory it ships in. A host that vendors the corpus verifies its copy against
116
+ this manifest, so a stale or altered fixture is detected before it silently changes what a conformance
117
+ claim means. The schema manifest in `@kumwe/studio-protocol` covers the schemas; this covers everything
118
+ replayed against them.
119
+
120
+ `@kumwe/studio-testkit/conformance/authoring-web/<filename>` publishes selector-neutral authoring
121
+ lanes. `runAuthoringWebVector(vector, adapter)` opens a fresh adapter session for every lane, performs
122
+ only the vector actions, and compares the returned canonical document, command intents, focus,
123
+ selection, announcements and dirty state. The adapter is deliberately injected: a browser host maps
124
+ the semantic steps onto its real DOM without exposing Lit, Editor.js, drag-and-drop, or host types in
125
+ the corpus. The current runner test proves fixture isolation and comparison behavior; it is not a
126
+ claim that the production shell has completed the entire authoring-web profile.
127
+
128
+ `@kumwe/studio-testkit/studio-release.json` is byte-identical to the workspace and protocol copies. A
129
+ host can vendor this record with the corpus, verify `corpusManifestDigest`, and resolve the exact eight
130
+ package versions named by one Studio release coordinate. An empty `claimedProfiles` array is deliberate:
131
+ repository tests and declared targets are not evidence-backed release claims.
132
+
133
+ Gate A requires valid and invalid fixture corpora plus runner-neutral assertions for block, theme,
134
+ plugin, host-port, command, preview, media, compatibility, migration, lifecycle, security,
135
+ accessibility, localization, and the applicable Version 2 TypeScript profile. Eight Version 2 profiles are
136
+ declared executable in the repository; `studio.profile/authoring-web` alone remains a target until its complete
137
+ real-shell assertion set and manual matrix exist. None is claimed by the current release record, and this
138
+ foundation alpha must not be cited as accepted gate evidence. Dart/Flutter parity belongs to Version 3.
@@ -0,0 +1,9 @@
1
+ # Third-party notices
2
+
3
+ <!-- Generated by scripts/generate-third-party-notices.mjs. Do not edit by hand. -->
4
+
5
+ Package: `@kumwe/studio-testkit`
6
+
7
+ Production closure SHA-256: `4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945`
8
+
9
+ This package has no third-party runtime dependencies.
@@ -0,0 +1,199 @@
1
+ {
2
+ "contractVersion": "0.1-draft",
3
+ "kind": "authoring-web-vector",
4
+ "id": "studio.conformance/non-drag-move-equivalence",
5
+ "description": "Keyboard, explicit structural control, and pointer enhancement dispatch the same root move while keeping the moved node selected and focused.",
6
+ "requirements": ["SR-001", "SR-003", "SR-017", "SR-029"],
7
+ "given": {
8
+ "document": {
9
+ "contractVersion": "0.1-draft",
10
+ "kind": "blueprint",
11
+ "id": "studio.conformance/authoring-move",
12
+ "version": "1.0.0",
13
+ "revision": "authoring-move-r1",
14
+ "owner": { "id": "studio.conformance/suite", "version": "1.0.0" },
15
+ "status": "draft",
16
+ "label": {
17
+ "key": "studio.conformance/authoring-move-label",
18
+ "defaultMessage": "Authoring move vector"
19
+ },
20
+ "model": {
21
+ "id": "studio.conformance/model",
22
+ "version": "1.0.0",
23
+ "revision": "model-r1"
24
+ },
25
+ "dependencyLock": {
26
+ "theme": {
27
+ "id": "studio.conformance/theme",
28
+ "version": "1.0.0",
29
+ "revision": "theme-r1"
30
+ },
31
+ "blocks": [
32
+ {
33
+ "type": "studio.core/heading",
34
+ "version": "1.0.0",
35
+ "revision": "heading-r1"
36
+ }
37
+ ]
38
+ },
39
+ "roots": [
40
+ {
41
+ "id": "node-first",
42
+ "type": "studio.core/heading",
43
+ "version": "1.0.0",
44
+ "properties": { "level": 2 },
45
+ "bindings": {
46
+ "text": {
47
+ "source": { "kind": "static-value", "value": "First" },
48
+ "transforms": [],
49
+ "onNull": "empty",
50
+ "onError": "error"
51
+ }
52
+ },
53
+ "slots": {},
54
+ "authoring": { "mode": "content" }
55
+ },
56
+ {
57
+ "id": "node-second",
58
+ "type": "studio.core/heading",
59
+ "version": "1.0.0",
60
+ "properties": { "level": 2 },
61
+ "bindings": {
62
+ "text": {
63
+ "source": { "kind": "static-value", "value": "Second" },
64
+ "transforms": [],
65
+ "onNull": "empty",
66
+ "onError": "error"
67
+ }
68
+ },
69
+ "slots": {},
70
+ "authoring": { "mode": "content" }
71
+ }
72
+ ]
73
+ },
74
+ "direction": "ltr",
75
+ "locale": "en",
76
+ "readOnly": false,
77
+ "reducedMotion": false,
78
+ "selection": "node-first",
79
+ "viewport": { "height": 900, "width": 1440, "zoomPercent": 100 }
80
+ },
81
+ "lanes": [
82
+ {
83
+ "name": "keyboard-move-down",
84
+ "surface": "keyboard",
85
+ "steps": [
86
+ { "kind": "focus-node", "nodeId": "node-first", "region": "outline" },
87
+ {
88
+ "kind": "key",
89
+ "key": "ArrowDown",
90
+ "modifiers": ["Alt"],
91
+ "region": "outline"
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ "name": "explicit-move-control",
97
+ "surface": "structural-control",
98
+ "steps": [
99
+ { "kind": "focus-node", "nodeId": "node-first", "region": "outline" },
100
+ {
101
+ "kind": "activate-command",
102
+ "region": "command-palette",
103
+ "type": "studio.command/move-node",
104
+ "payload": { "nodeId": "node-first", "destination": { "position": 1 } }
105
+ }
106
+ ]
107
+ },
108
+ {
109
+ "name": "pointer-drag-enhancement",
110
+ "surface": "pointer",
111
+ "steps": [
112
+ { "kind": "focus-node", "nodeId": "node-first", "region": "canvas" },
113
+ {
114
+ "kind": "drag-node",
115
+ "nodeId": "node-first",
116
+ "destination": { "position": 1 }
117
+ }
118
+ ]
119
+ }
120
+ ],
121
+ "expect": {
122
+ "announcements": [{ "key": "studio.authoring/node-moved", "politeness": "polite" }],
123
+ "commands": [
124
+ {
125
+ "type": "studio.command/move-node",
126
+ "payload": { "nodeId": "node-first", "destination": { "position": 1 } }
127
+ }
128
+ ],
129
+ "dirty": true,
130
+ "document": {
131
+ "contractVersion": "0.1-draft",
132
+ "kind": "blueprint",
133
+ "id": "studio.conformance/authoring-move",
134
+ "version": "1.0.0",
135
+ "revision": "authoring-move-r1",
136
+ "owner": { "id": "studio.conformance/suite", "version": "1.0.0" },
137
+ "status": "draft",
138
+ "label": {
139
+ "key": "studio.conformance/authoring-move-label",
140
+ "defaultMessage": "Authoring move vector"
141
+ },
142
+ "model": {
143
+ "id": "studio.conformance/model",
144
+ "version": "1.0.0",
145
+ "revision": "model-r1"
146
+ },
147
+ "dependencyLock": {
148
+ "theme": {
149
+ "id": "studio.conformance/theme",
150
+ "version": "1.0.0",
151
+ "revision": "theme-r1"
152
+ },
153
+ "blocks": [
154
+ {
155
+ "type": "studio.core/heading",
156
+ "version": "1.0.0",
157
+ "revision": "heading-r1"
158
+ }
159
+ ]
160
+ },
161
+ "roots": [
162
+ {
163
+ "id": "node-second",
164
+ "type": "studio.core/heading",
165
+ "version": "1.0.0",
166
+ "properties": { "level": 2 },
167
+ "bindings": {
168
+ "text": {
169
+ "source": { "kind": "static-value", "value": "Second" },
170
+ "transforms": [],
171
+ "onNull": "empty",
172
+ "onError": "error"
173
+ }
174
+ },
175
+ "slots": {},
176
+ "authoring": { "mode": "content" }
177
+ },
178
+ {
179
+ "id": "node-first",
180
+ "type": "studio.core/heading",
181
+ "version": "1.0.0",
182
+ "properties": { "level": 2 },
183
+ "bindings": {
184
+ "text": {
185
+ "source": { "kind": "static-value", "value": "First" },
186
+ "transforms": [],
187
+ "onNull": "empty",
188
+ "onError": "error"
189
+ }
190
+ },
191
+ "slots": {},
192
+ "authoring": { "mode": "content" }
193
+ }
194
+ ]
195
+ },
196
+ "focus": { "region": "outline", "nodeId": "node-first" },
197
+ "selection": "node-first"
198
+ }
199
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "id": "renderer-web/blob-default-deny",
3
+ "coverage": {
4
+ "blockTypes": ["studio.core/image"],
5
+ "behaviors": [],
6
+ "presentation": [],
7
+ "security": ["blob-default-deny"]
8
+ },
9
+ "roots": [
10
+ {
11
+ "authoring": { "mode": "content" },
12
+ "bindings": {},
13
+ "id": "blob-default",
14
+ "properties": { "fit": "cover", "loading": "lazy" },
15
+ "slots": {},
16
+ "type": "studio.core/image",
17
+ "version": "1.0.0"
18
+ }
19
+ ],
20
+ "bindings": [
21
+ {
22
+ "nodeId": "blob-default",
23
+ "port": "asset",
24
+ "value": {
25
+ "contractVersion": "0.1-draft",
26
+ "kind": "media-reference",
27
+ "assetId": "local",
28
+ "usage": "studio.media/content",
29
+ "accessibility": { "mode": "informative", "altText": "Local" }
30
+ }
31
+ }
32
+ ],
33
+ "media": [
34
+ {
35
+ "assetId": "local",
36
+ "src": "blob:https://studio.example.test/323e4567-e89b-12d3-a456-426614174000",
37
+ "altText": "Local",
38
+ "mediaType": "image/png"
39
+ }
40
+ ],
41
+ "expect": {
42
+ "htmlContains": ["Image unavailable"],
43
+ "htmlExcludes": ["blob:https://"],
44
+ "cssContains": ["prefers-reduced-motion"],
45
+ "enhancements": []
46
+ }
47
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "id": "renderer-web/chart-fallback",
3
+ "coverage": {
4
+ "blockTypes": ["studio.core/chart"],
5
+ "behaviors": [],
6
+ "presentation": [],
7
+ "security": ["typed-data-fallback"]
8
+ },
9
+ "roots": [
10
+ {
11
+ "authoring": { "mode": "content" },
12
+ "bindings": {},
13
+ "id": "chart",
14
+ "properties": {},
15
+ "slots": {},
16
+ "type": "studio.core/chart",
17
+ "version": "1.0.0"
18
+ }
19
+ ],
20
+ "bindings": [
21
+ {
22
+ "nodeId": "chart",
23
+ "port": "chart",
24
+ "value": {
25
+ "type": "bar",
26
+ "title": "Revenue",
27
+ "labels": ["Q1", "Q2"],
28
+ "datasets": [{ "label": "NAD", "values": [10, 20] }]
29
+ }
30
+ }
31
+ ],
32
+ "media": [],
33
+ "expect": {
34
+ "htmlContains": ["<table data-studio-chart-table>", "Revenue", "Q1", "20"],
35
+ "htmlExcludes": ["<script", "onClick"],
36
+ "cssContains": ["data-studio-chart-table"],
37
+ "enhancements": ["chart"]
38
+ }
39
+ }