@kumwe/studio-testkit 0.1.0-alpha.7 → 0.1.0-beta.2

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 (189) hide show
  1. package/README.md +122 -23
  2. package/THIRD_PARTY_NOTICES.md +9 -0
  3. package/conformance/authoring-web/non-drag-move-equivalence.json +199 -0
  4. package/conformance/renderer-web/blob-default-deny.json +62 -0
  5. package/conformance/renderer-web/chart-fallback.json +54 -0
  6. package/conformance/renderer-web/complete-catalog.json +649 -0
  7. package/conformance/renderer-web/escaped-heading.json +43 -0
  8. package/conformance/renderer-web/interactive-behaviors.json +284 -0
  9. package/conformance/renderer-web/presentation-capabilities.json +104 -0
  10. package/conformance/renderer-web/responsive-grid.json +48 -0
  11. package/conformance/renderer-web/security-fallbacks.json +184 -0
  12. package/conformance/rich-text/advanced.first-party.json +67 -0
  13. package/corpus-manifest.json +571 -37
  14. package/dist/contextual-conformance.d.ts +81 -0
  15. package/dist/contextual-conformance.d.ts.map +1 -0
  16. package/dist/contextual-conformance.js +1 -0
  17. package/dist/host-testbed.d.ts +68 -5
  18. package/dist/host-testbed.d.ts.map +1 -1
  19. package/dist/host-testbed.js +1 -547
  20. package/dist/http-authoring-contract.d.ts +3 -0
  21. package/dist/http-authoring-contract.d.ts.map +1 -0
  22. package/dist/http-authoring-contract.js +1 -0
  23. package/dist/http-host-adapter.d.ts +12 -64
  24. package/dist/http-host-adapter.d.ts.map +1 -1
  25. package/dist/http-host-adapter.js +1 -256
  26. package/dist/http-host-responder.d.ts +58 -0
  27. package/dist/http-host-responder.d.ts.map +1 -0
  28. package/dist/http-host-responder.js +1 -0
  29. package/dist/index.d.ts +88 -3
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -140
  32. package/dist/web-conformance.d.ts +112 -0
  33. package/dist/web-conformance.d.ts.map +1 -0
  34. package/dist/web-conformance.js +1 -0
  35. package/fixtures/authoring-message-catalog.en.json +1093 -0
  36. package/fixtures/authoring-save.plan.example.json +48 -0
  37. package/fixtures/authoring-session.example.json +212 -0
  38. package/fixtures/authoring-target.example.json +34 -0
  39. package/fixtures/host-capabilities.example.json +2 -2
  40. package/fixtures/host-operations.example.json +77 -0
  41. package/fixtures/plugin.example.json +12 -0
  42. package/fixtures/preview.render.example.json +1 -0
  43. package/fixtures/reusable-content-type.example.json +26 -0
  44. package/fixtures/studio-config.example.json +3 -3
  45. package/fixtures/studio-deployment.hosted.example.json +152 -0
  46. package/fixtures/studio-deployment.standalone.example.json +9 -0
  47. package/invalid/authoring-save.plan-missing-coordinates.json +16 -0
  48. package/invalid/authoring-save.plan-missing-successor-context.json +28 -0
  49. package/invalid/authoring-save.request-plan-missing-successor-context.json +26 -0
  50. package/invalid/authoring-session.missing-entry-state.json +9 -0
  51. package/invalid/authoring-target.missing-resource-types.json +24 -0
  52. package/invalid/binding-projection-vector.unknown-status.json +85 -0
  53. package/invalid/host-capabilities.invalid-protocol-version.json +1 -1
  54. package/invalid/host-error.retry-delay-without-retry.json +16 -0
  55. package/invalid/host-error.retry-delay-wrong-category.json +16 -0
  56. package/invalid/host-error.revision-without-conflict.json +16 -0
  57. package/invalid/host-sequence.pending-expectation.json +52 -0
  58. package/invalid/host-sequence.preview-render-missing-request-id.json +50 -0
  59. package/invalid/preview-message.activated-unknown-interaction.json +1 -1
  60. package/invalid/preview-message.duplicate-marker.json +24 -0
  61. package/invalid/preview-message.invalid-digest.json +1 -0
  62. package/invalid/preview-message.invalid-marker-grammar.json +19 -0
  63. package/invalid/preview-message.missing-marker-map.json +20 -0
  64. package/invalid/preview-message.missing-render-request-id.json +18 -0
  65. package/invalid/preview-message.unknown-type.json +13 -0
  66. package/invalid/preview-message.viewport-height-too-small.json +13 -0
  67. package/invalid/preview-message.viewport-unsafe-role.json +13 -0
  68. package/invalid/reusable-content-type.entry-values.json +32 -0
  69. package/invalid/studio-chart.script-config.json +10 -0
  70. package/invalid/studio-deployment.long-lived-token.json +24 -0
  71. package/invalid/studio-deployment.missing-required.json +5 -0
  72. package/invalid/studio-deployment.unknown-member.json +15 -0
  73. package/invalid/studio-drawing.svg-payload.json +10 -0
  74. package/invalid/studio-money.float.json +8 -0
  75. package/invalid/studio-presentation.css-injection.json +8 -0
  76. package/invalid/studio-table.html-cell.json +8 -0
  77. package/package.json +8 -4
  78. package/studio-release.json +35 -0
  79. package/vectors/authoring-http/transport-matrix.json +237 -0
  80. package/vectors/binding-projection/app-content-fields.resolved.json +286 -0
  81. package/vectors/binding-projection/field-removed.diagnostic.json +135 -0
  82. package/vectors/binding-projection/model-revision-mismatch.diagnostic.json +124 -0
  83. package/vectors/host/artifact.dependencies.result.json +2 -2
  84. package/vectors/host/artifact.load.stored.json +2 -2
  85. package/vectors/host/artifact.load.unknown.error.json +2 -2
  86. package/vectors/host/artifact.publish.accepted.json +2 -2
  87. package/vectors/host/artifact.publish.forbidden.error.json +1 -1
  88. package/vectors/host/artifact.publish.stale.error.json +2 -2
  89. package/vectors/host/artifact.save.accepted.json +2 -2
  90. package/vectors/host/artifact.save.forbidden.error.json +1 -1
  91. package/vectors/host/artifact.save.stale.error.json +2 -2
  92. package/vectors/host/artifact.unpublish.stale.error.json +2 -2
  93. package/vectors/host/envelope.malformed-context.error.json +2 -2
  94. package/vectors/host/envelope.protocol-version.error.json +1 -1
  95. package/vectors/host/envelope.stale-generation.error.json +2 -2
  96. package/vectors/host/localization.messages.unknown-locale.error.json +2 -2
  97. package/vectors/host/media.abort-upload.unknown.error.json +1 -1
  98. package/vectors/host/media.authorize-upload.granted.json +1 -1
  99. package/vectors/host/media.authorize-upload.path-filename.error.json +1 -1
  100. package/vectors/host/media.authorize-upload.too-large.error.json +1 -1
  101. package/vectors/host/media.complete-upload.unknown.error.json +1 -1
  102. package/vectors/host/media.get.unknown.json +2 -2
  103. package/vectors/host/media.import-external.private-host.error.json +1 -1
  104. package/vectors/host/media.list.cursor.error.json +2 -2
  105. package/vectors/host/media.list.limit.error.json +2 -2
  106. package/vectors/host/media.upload-status.unknown.error.json +1 -1
  107. package/vectors/host/model.get.stored.json +37 -0
  108. package/vectors/host/model.list.authorized.json +31 -0
  109. package/vectors/host/permission.explain.withheld.json +2 -2
  110. package/vectors/host/permission.refresh.snapshot.json +2 -2
  111. package/vectors/host/recovery.load.absent.json +2 -2
  112. package/vectors/host/telemetry.emit.accepted.json +2 -2
  113. package/vectors/host/telemetry.emit.non-primitive.error.json +2 -2
  114. package/vectors/host-sequence/artifact.publish.changed-intent.sequence.json +75 -0
  115. package/vectors/host-sequence/artifact.publish.idempotent-replay.sequence.json +111 -0
  116. package/vectors/host-sequence/preview.cancel.cross-context.sequence.json +78 -0
  117. package/vectors/host-sequence/preview.render.cancelled.sequence.json +75 -0
  118. package/vectors/host-sequence/recovery.store.canonical-number.sequence.json +72 -0
  119. package/vectors/host-sequence/recovery.store.changed-context.sequence.json +61 -0
  120. package/vectors/host-sequence/recovery.store.rate-limited.sequence.json +93 -0
  121. package/vectors/host-sequence/recovery.store.resource-scope.sequence.json +61 -0
  122. package/vectors/host-sequence/recovery.store.wrong-operation-id.sequence.json +56 -0
  123. package/vectors/preview/canonical-preorder.json +102 -0
  124. package/vectors/preview/empty-draft.json +36 -0
  125. package/vectors/schema-profile/alternative-limit.accepted.json +95 -0
  126. package/vectors/schema-profile/alternative-limit.rejected.json +92 -0
  127. package/vectors/schema-profile/array-composition.accepted.json +35 -0
  128. package/vectors/schema-profile/byte-limit.accepted.json +30 -0
  129. package/vectors/schema-profile/byte-limit.rejected.json +26 -0
  130. package/vectors/schema-profile/closed-object.accepted.json +38 -0
  131. package/vectors/schema-profile/decimal-multiple.accepted.json +54 -0
  132. package/vectors/schema-profile/depth-limit.accepted.json +90 -0
  133. package/vectors/schema-profile/depth-limit.rejected.json +88 -0
  134. package/vectors/schema-profile/description-limit.accepted.json +29 -0
  135. package/vectors/schema-profile/description-limit.rejected.json +25 -0
  136. package/vectors/schema-profile/diagnostic-precedence.rejected.json +26 -0
  137. package/vectors/schema-profile/duplicate-dependent-required.rejected.json +21 -0
  138. package/vectors/schema-profile/duplicate-required.rejected.json +18 -0
  139. package/vectors/schema-profile/empty-combinator.rejected.json +17 -0
  140. package/vectors/schema-profile/empty-enum.rejected.json +17 -0
  141. package/vectors/schema-profile/enum-limit.accepted.json +89 -0
  142. package/vectors/schema-profile/enum-limit.rejected.json +84 -0
  143. package/vectors/schema-profile/examples-limit.accepted.json +35 -0
  144. package/vectors/schema-profile/examples-limit.rejected.json +31 -0
  145. package/vectors/schema-profile/format-keyword.rejected.json +17 -0
  146. package/vectors/schema-profile/forward-reference-path-precedence.rejected.json +20 -0
  147. package/vectors/schema-profile/invalid-pointer.rejected.json +18 -0
  148. package/vectors/schema-profile/json-depth-limit.accepted.json +278 -0
  149. package/vectors/schema-profile/json-depth-limit.rejected.json +276 -0
  150. package/vectors/schema-profile/json-item-limit.accepted.json +686 -0
  151. package/vectors/schema-profile/json-item-limit.rejected.json +682 -0
  152. package/vectors/schema-profile/json-property-limit.accepted.json +1031 -0
  153. package/vectors/schema-profile/json-property-limit.rejected.json +1028 -0
  154. package/vectors/schema-profile/local-reference.accepted.json +28 -0
  155. package/vectors/schema-profile/memoized-diagnostic.accepted.json +31 -0
  156. package/vectors/schema-profile/node-limit.accepted.json +1097 -0
  157. package/vectors/schema-profile/node-limit.rejected.json +1094 -0
  158. package/vectors/schema-profile/non-object-root.rejected.json +9 -0
  159. package/vectors/schema-profile/non-schema-reference.rejected.json +21 -0
  160. package/vectors/schema-profile/object-key-limit.accepted.json +32 -0
  161. package/vectors/schema-profile/object-key-limit.rejected.json +28 -0
  162. package/vectors/schema-profile/open-root.rejected.json +13 -0
  163. package/vectors/schema-profile/percent-encoded-pointer.rejected.json +26 -0
  164. package/vectors/schema-profile/property-name-limit.accepted.json +543 -0
  165. package/vectors/schema-profile/property-name-limit.rejected.json +536 -0
  166. package/vectors/schema-profile/recursive-diagnostic-precedence.rejected.json +30 -0
  167. package/vectors/schema-profile/recursive-reference.rejected.json +24 -0
  168. package/vectors/schema-profile/reference-fanout.accepted.json +662 -0
  169. package/vectors/schema-profile/reference-length-limit.accepted.json +45 -0
  170. package/vectors/schema-profile/reference-length-limit.rejected.json +39 -0
  171. package/vectors/schema-profile/reference-limit.accepted.json +416 -0
  172. package/vectors/schema-profile/reference-limit.rejected.json +415 -0
  173. package/vectors/schema-profile/reference-vs-keyword-precedence.rejected.json +22 -0
  174. package/vectors/schema-profile/reserved-pointer.rejected.json +26 -0
  175. package/vectors/schema-profile/root-diagnostic-precedence.rejected.json +16 -0
  176. package/vectors/schema-profile/root-vs-reference-precedence.rejected.json +19 -0
  177. package/vectors/schema-profile/schema-map-limit.accepted.json +539 -0
  178. package/vectors/schema-profile/schema-map-limit.rejected.json +536 -0
  179. package/vectors/schema-profile/semantic-recursion-precedence.rejected.json +21 -0
  180. package/vectors/schema-profile/semantic-reference-precedence.rejected.json +21 -0
  181. package/vectors/schema-profile/title-limit.accepted.json +29 -0
  182. package/vectors/schema-profile/title-limit.rejected.json +25 -0
  183. package/vectors/schema-profile/unresolved-reference.rejected.json +17 -0
  184. package/vectors/schema-profile/unsafe-dependent-required.rejected.json +24 -0
  185. package/vectors/schema-profile/unsafe-member.rejected.json +17 -0
  186. package/vectors/schema-profile/unsafe-required.rejected.json +17 -0
  187. package/dist/host-testbed.js.map +0 -1
  188. package/dist/http-host-adapter.js.map +0 -1
  189. package/dist/index.js.map +0 -1
package/README.md CHANGED
@@ -1,38 +1,75 @@
1
1
  # `@kumwe/studio-testkit`
2
2
 
3
- Status: pre-Gate-A foundation alpha. Its conformance helpers do not by themselves constitute gate evidence.
3
+ Status: governed beta development, still pre-Gate-A and not production-supported. The exact coordinated
4
+ version is in the workspace `studio-release.json`; these conformance helpers do not by themselves constitute
5
+ gate evidence.
4
6
 
5
- The current alpha exports three builders—`createBlueprintFixture`, `defineTestBlock`, and
6
- `createStudioConfigurationFixture`—plus `assertBlueprintConforms` and its structured
7
- `StudioConformanceError`. The assertion checks a Blueprint against supplied block definitions through
8
- the current core validator. It does not yet prove host, plugin, theme, preview, media, accessibility,
9
- security, lifecycle, or cross-language conformance.
7
+ The current candidate combines fixture builders and `assertBlueprintConforms` with deterministic host and HTTP
8
+ testbeds plus executable command, canonical, host, host-sequence, media, preview, property-schema,
9
+ binding-projection, renderer-web, rich-text, and authoring-web corpus runners. Those helpers let another
10
+ implementation replay the same portable assertions without adopting Studio internals. A green repository
11
+ replay is implementation evidence, not an accepted gate or support claim; every advertised profile still
12
+ needs exact-candidate evidence and independent review.
10
13
 
11
14
  Package subpaths under `@kumwe/studio-testkit/fixtures/<filename>` contain byte-identical copies of the
12
15
  canonical valid examples, including separate MediaAsset and persisted MediaReference examples. There
13
16
  is no aggregate runtime `fixtures` export. The helpers do not depend on Vitest or another test runner,
14
17
  so consumers may call the current assertion from any JavaScript test environment.
15
18
 
19
+ `fixtures/authoring-message-catalog.en.json` is the byte-identical canonical English shell catalog.
20
+ It lets hosts validate localization imports and parameter declarations without importing the Lit
21
+ runtime. Its schema ships with `@kumwe/studio-protocol`.
22
+
16
23
  ## Host testbed
17
24
 
18
25
  `createTestbedHost(options)` builds a deterministic, fully in-memory `HostAdapter` reference host
19
- for conformance and failure testing. Every standard port except `model` is implemented against
26
+ for conformance and failure testing. Every standard port is implemented against
20
27
  seeded fixtures (`documents`, `resources`, `mediaAssets`, `messages`, `permissions`, and an
21
- optional preview `render` callback). Each operation first checks connectivity and injected
22
- failures, then validates the `HostRequestContext` envelope structurally (wrong wire protocol
23
- versions reject as `incompatible`), then enforces the current session generation. Every failure
24
- rejects with `TestbedHostError`, whose `error` document satisfies `isHostPortError`; `not-found`
25
- messages never disclose which identifiers exist. Revisions advance as deterministic counters
26
- (`<id>-r<n>`), optimistic-concurrency conflicts return the safe current revision without changing
27
- stored state, and search/media pagination uses opaque cursors. The returned `controls` drive
28
+ optional asynchronous preview `render` callback). Each operation first validates connectivity and the
29
+ `HostRequestContext`, including exact operation-capability matching, wire protocol, and current session
30
+ generation. Every failure rejects with `TestbedHostError`, whose `error` document satisfies
31
+ `isHostPortError`. `TestbedHostError` extends the protocol's public `HostPortFailure`, so the same
32
+ rejection satisfies `isHostPortFailure` without consumers depending on the testbed-specific class.
33
+ Stale-generation rejection is `invalid-request` with the exact
34
+ `studio.host/stale-session-generation` diagnostic used for whole-handle invalidation; unrelated
35
+ invalid requests do not carry that meaning. `not-found` messages never disclose which identifiers
36
+ exist. Seed artifact kinds, revisions, and the optional initial `sessionGeneration` are retained
37
+ exactly; subsequent revisions advance as deterministic counters (`<id>-r<n>`).
38
+ Optimistic-concurrency conflicts return the safe current revision without changing stored state, and
39
+ search/media pagination uses opaque cursors. The returned `controls` drive
28
40
  failure scenarios: `disconnect()`/`reconnect()` for retryable `unavailable` outages,
29
41
  `failNext(port, operation, category)` for exactly one injected failure (retryable only for
30
42
  `unavailable` and `rate-limited`), and `setPermissions(...)`, which replaces the permission list
31
43
  and bumps the session generation so stale contexts reject as `invalid-request`. `revisionOf(id)`,
32
- the `sessionGeneration` getter, and the recorded `telemetryEvents` support assertions.
33
- `createHostRequestContextFixture` builds conforming request envelopes. The testbed uses no clocks,
44
+ the `sessionGeneration` getter, and the recorded `telemetryEvents` support assertions. The logical
45
+ `advanceClock()` control and declared fixed-window policies make rate-limit tests deterministic.
46
+ Idempotency records use the published scope/preimage, coalesce matching accepted mutations, reject
47
+ changed intent, and remove failed attempts. Preview render controls expose pending and delivered
48
+ outcomes so cancellation proves that late output is discarded. An injected renderer must return the
49
+ originating draft digest and render `requestId`; an uncorrelated result fails as non-retryable
50
+ `internal` and is never recorded as delivered.
51
+ `createHostRequestContextFixture` builds request envelopes; callers provide the exact operation ID for
52
+ strict hosts. The `allowTestOperationId` option permits only the fixture wildcard for broad unit drills,
53
+ defaults off, and must never be enabled for conformance replay. The testbed uses no wall clock,
34
54
  randomness, or timers, so runs are fully reproducible.
35
55
 
56
+ The optional `authoring` fixtures add the canonical contextual target, reusable-type listing, exact start,
57
+ save-plan, and three distinct save operations to that same testbed. Resolve, list, and start reject a body/
58
+ envelope resource-context mismatch; start and the three saves share the deterministic idempotency boundary;
59
+ and `controls.authoringOperations` exposes detached observations for assertions. The compatibility HTTP adapter
60
+ reuses `@kumwe/studio-core`'s production transport and maps the seven operations to `/ports/authoring/*` without
61
+ introducing a server-side JavaScript runtime requirement. It preserves the historical `TestbedHostError`
62
+ subclass; production core and browser consumers receive the protocol's canonical `HostPortFailure`.
63
+ `runContextualAuthoringStrideVector(vector, adapter)` is a selector-neutral first-stride runner for exact blank,
64
+ from-type, and existing hydration; separately governed Model, Blueprint, and Entry commands; typed values;
65
+ item-local composition; and host-authoritative save boundaries. Its result always carries
66
+ `completeProfile: false`: presentation continuity, contribution lifecycle, real-shell accessibility, and the
67
+ remaining browser matrix still prevent a complete `studio.profile/authoring-web` claim.
68
+
69
+ The language-neutral `vectors/authoring-http/transport-matrix.json` additionally fixes accepted and mismatched
70
+ save-successor-context cases. A host replay must advance from the prior context to the plan reference's exact
71
+ `successorContext` on acceptance and reject a result carrying any other context.
72
+
36
73
  ## Host conformance corpus
37
74
 
38
75
  `@kumwe/studio-testkit/vectors/host/<filename>` publishes the executable assertion set for
@@ -46,20 +83,82 @@ test suite without executing Studio code. The reference host's own claim against
46
83
  `test/host-vectors.test.ts`. The profile records the obligations it does not yet assert; consult
47
84
  `docs/contracts/conformance-profiles.md` before treating a green replay as complete coverage.
48
85
 
86
+ `@kumwe/studio-testkit/vectors/host-sequence/<filename>` publishes the additive assertion set for
87
+ `studio.profile/host-baseline-v2`. The bounded sequence shape expresses pending and settled operations,
88
+ fixed-window policies, explicit clock advances and renderer completions, and final state. Nine vectors
89
+ cover in-flight/completed replay, changed argument/context refusal, canonical numeric intent,
90
+ resource-scope separation, wrong-operation refusal, failed-attempt retry after a window reset, matching
91
+ preview cancellation with late-result discard, and cross-context cancellation isolation. The
92
+ TypeScript replay is `test/host-sequence-vectors.test.ts`; other runtimes consume the same JSON and
93
+ schema directly. The exact assertion list and deliberately recorded limits live in
94
+ `docs/contracts/conformance-profiles.md`.
95
+
96
+ `@kumwe/studio-testkit/vectors/authoring-http/transport-matrix.json` is the language-neutral authoring HTTP
97
+ matrix for PHP and independent hosts. It fixes all seven route/capability/schema bindings, mutation and
98
+ idempotency classification, resource-context equality requirements, success status, every canonical error
99
+ status, and authentication/CSRF/schema/context refusal cases. A host replays this JSON in its own test runner;
100
+ it does not execute TypeScript or require Node.js in production.
101
+
102
+ The host corpus includes `model.get` and `model.list` exchanges over seeded content models. The testbed
103
+ resolves exact ID/version/revision coordinates and lists detached projections in deterministic coordinate
104
+ order. The injected HTTP adapter maps the same operations to `POST /ports/model/get` and
105
+ `POST /ports/model/list`.
106
+
49
107
  `@kumwe/studio-testkit/vectors/canonical/<filename>` publishes the canonical serialization corpus:
50
108
  each vector carries a bounded value and either the exact canonical string with the SRI-style digest of
51
109
  its UTF-8 bytes, or the stable reason the canonical form refuses it. Its expectations were produced by
52
110
  an independent canonicalizer rather than recorded from the reference implementation, so replaying it
53
111
  is a cross-implementation check.
54
112
 
113
+ `@kumwe/studio-testkit/vectors/preview/<filename>` publishes the executable assertion set for
114
+ `studio.profile/preview-identity-v1`. Each complete Blueprint fixes the lowercase SHA-256 digest of
115
+ its canonical UTF-8 bytes, the artifact/revision/digest render tuple with a unique attempt ID, and the
116
+ exact marker preorder plus one-to-one marker map. The reference replay is
117
+ `test/preview-vectors.test.ts`; another runtime hashes and traverses the same JSON without executing
118
+ Studio code.
119
+
120
+ `@kumwe/studio-testkit/vectors/schema-profile/<filename>` publishes the executable assertion set for
121
+ `studio.profile/schema-property`. Accepted candidates carry instance verdicts and the first stable
122
+ keyword/pointer diagnostic; rejected candidates carry the closed admission code and schema pointer.
123
+ `runSchemaProfileVector(vector)` replays one vector through the TypeScript reference without consulting
124
+ its expected verdicts or diagnostics. Other runtimes consume the same JSON directly and do not execute
125
+ testkit code. Boundary vectors identify their published limit, exact value, and side of the ceiling;
126
+ the corpus contains exactly one at-limit and one exact-plus-one case for every advertised limit. Its
127
+ acyclic-reference fan-out case must complete without expanding the reference DAG exponentially. The
128
+ TypeScript reference exposes the full ordered set of distinct failures: repeated branches do not
129
+ duplicate an otherwise identical keyword, instance pointer, and message diagnostic.
130
+ Competing-failure vectors also pin one admission order across root invariants, local-reference
131
+ resolution, recursion, and structural keyword checks.
132
+
133
+ `@kumwe/studio-testkit/vectors/binding-projection/<filename>` publishes
134
+ `studio.profile/binding-projection-v1`. Each vector carries a complete Blueprint, authorized content model,
135
+ block definitions and exact normalized candidate/control/status/diagnostic output.
136
+ `runBindingProjectionVector(vector)` replays one vector without reading its expected result; another runtime
137
+ consumes the same JSON directly. The runner and reference projection never mutate vector input.
138
+
55
139
  `@kumwe/studio-testkit/corpus-manifest.json` carries the sha256 digest of every file in the published
56
- corpus, grouped by the directory it ships in. A host that vendors the corpus verifies its copy against
57
- this manifest, so a stale or altered fixture is detected before it silently changes what a conformance
58
- claim means. The schema manifest in `@kumwe/studio-protocol` covers the schemas; this covers everything
59
- replayed against them.
140
+ corpus, grouped by the directory it ships in. The current generated manifest inventories 297 files across 14
141
+ groups, including positive examples, invalid fixtures, portable vectors, and conformance lanes. A host that
142
+ vendors the corpus verifies its copy against this manifest, so a stale or altered fixture is detected before it
143
+ silently changes what a conformance claim means. The schema manifest in `@kumwe/studio-protocol` covers the
144
+ schemas; this covers everything replayed against them.
145
+
146
+ `@kumwe/studio-testkit/conformance/authoring-web/<filename>` publishes selector-neutral authoring
147
+ lanes. `runAuthoringWebVector(vector, adapter)` opens a fresh adapter session for every lane, performs
148
+ only the vector actions, and compares the returned canonical document, command intents, focus,
149
+ selection, announcements and dirty state. The adapter is deliberately injected: a browser host maps
150
+ the semantic steps onto its real DOM without exposing Lit, Editor.js, drag-and-drop, or host types in
151
+ the corpus. The current runner test proves fixture isolation and comparison behavior; it is not a
152
+ claim that the production shell has completed the entire authoring-web profile.
153
+
154
+ `@kumwe/studio-testkit/studio-release.json` is byte-identical to the workspace and protocol copies. A
155
+ host can vendor this record with the corpus, verify `corpusManifestDigest`, and resolve the exact eight
156
+ package versions named by one Studio release coordinate. An empty `claimedProfiles` array is deliberate:
157
+ repository tests and declared targets are not evidence-backed release claims.
60
158
 
61
159
  Gate A requires valid and invalid fixture corpora plus runner-neutral assertions for block, theme,
62
160
  plugin, host-port, command, preview, media, compatibility, migration, lifecycle, security,
63
- accessibility, localization, and TypeScript/Dart equivalence. The host-port corpus above is the first
64
- of those to land; the remainder are target deliverables and this foundation alpha must not be cited as
65
- their evidence.
161
+ accessibility, localization, and the applicable Version 2 TypeScript profile. Eight Version 2 profiles are
162
+ declared executable in the repository; `studio.profile/authoring-web` alone remains a target until its complete
163
+ real-shell assertion set and manual matrix exist. None is claimed by the current release record, and this beta
164
+ development tree 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,62 @@
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
+ "activationMarkers": [],
43
+ "cssBytes": 6320,
44
+ "cssSha256": "8d4d00dfa489396dc0a4207b3d1efa207d7658e325c9db4bba2e74b91a607649",
45
+ "htmlBytes": 153,
46
+ "htmlSha256": "c4bc7134b14028faf96ee6166f3925e0cbbbc0f17457a969fcbacf1d1f4dd79f",
47
+ "publicStyleAsset": {
48
+ "path": "assets/studio-public-8d4d00dfa489396d.min.css",
49
+ "role": "public-style",
50
+ "mediaType": "text/css",
51
+ "bytes": 6320,
52
+ "budgetBytes": 262144,
53
+ "contentHash": "8d4d00dfa489396dc0a4207b3d1efa207d7658e325c9db4bba2e74b91a607649",
54
+ "integrity": "sha256-jU0A36SJOW3ApCB7PR76IH12WOMlydtLui50uRpgdkk=",
55
+ "minified": true
56
+ },
57
+ "htmlContains": ["Image unavailable"],
58
+ "htmlExcludes": ["blob:https://"],
59
+ "cssContains": ["prefers-reduced-motion"],
60
+ "enhancements": []
61
+ }
62
+ }
@@ -0,0 +1,54 @@
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
+ "activationMarkers": [],
35
+ "cssBytes": 6320,
36
+ "cssSha256": "8d4d00dfa489396dc0a4207b3d1efa207d7658e325c9db4bba2e74b91a607649",
37
+ "htmlBytes": 398,
38
+ "htmlSha256": "5f95e47df5ec5ea95dfafd5c1c76cc3cb4e529f0ba80d307ba99d4fab6b73f9e",
39
+ "publicStyleAsset": {
40
+ "path": "assets/studio-public-8d4d00dfa489396d.min.css",
41
+ "role": "public-style",
42
+ "mediaType": "text/css",
43
+ "bytes": 6320,
44
+ "budgetBytes": 262144,
45
+ "contentHash": "8d4d00dfa489396dc0a4207b3d1efa207d7658e325c9db4bba2e74b91a607649",
46
+ "integrity": "sha256-jU0A36SJOW3ApCB7PR76IH12WOMlydtLui50uRpgdkk=",
47
+ "minified": true
48
+ },
49
+ "htmlContains": ["<table data-studio-chart-table>", "Revenue", "Q1", "20"],
50
+ "htmlExcludes": ["<script", "onClick"],
51
+ "cssContains": ["data-studio-chart-table"],
52
+ "enhancements": ["chart"]
53
+ }
54
+ }