@kumwe/studio-testkit 0.1.0-alpha.8 → 0.1.0-rc.1

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 (42) hide show
  1. package/README.md +48 -14
  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 +47 -0
  5. package/conformance/renderer-web/chart-fallback.json +39 -0
  6. package/conformance/renderer-web/complete-catalog.json +634 -0
  7. package/conformance/renderer-web/escaped-heading.json +28 -0
  8. package/conformance/renderer-web/interactive-behaviors.json +226 -0
  9. package/conformance/renderer-web/presentation-capabilities.json +76 -0
  10. package/conformance/renderer-web/responsive-grid.json +33 -0
  11. package/conformance/renderer-web/security-fallbacks.json +169 -0
  12. package/conformance/rich-text/advanced.first-party.json +67 -0
  13. package/corpus-manifest.json +106 -0
  14. package/dist/host-testbed.d.ts +3 -4
  15. package/dist/host-testbed.d.ts.map +1 -1
  16. package/dist/host-testbed.js +46 -6
  17. package/dist/host-testbed.js.map +1 -1
  18. package/dist/http-host-adapter.d.ts.map +1 -1
  19. package/dist/http-host-adapter.js +8 -0
  20. package/dist/http-host-adapter.js.map +1 -1
  21. package/dist/index.d.ts +44 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +38 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/web-conformance.d.ts +105 -0
  26. package/dist/web-conformance.d.ts.map +1 -0
  27. package/dist/web-conformance.js +72 -0
  28. package/dist/web-conformance.js.map +1 -0
  29. package/fixtures/authoring-message-catalog.en.json +649 -0
  30. package/invalid/binding-projection-vector.unknown-status.json +85 -0
  31. package/invalid/studio-chart.script-config.json +10 -0
  32. package/invalid/studio-drawing.svg-payload.json +10 -0
  33. package/invalid/studio-money.float.json +8 -0
  34. package/invalid/studio-presentation.css-injection.json +8 -0
  35. package/invalid/studio-table.html-cell.json +8 -0
  36. package/package.json +7 -3
  37. package/studio-release.json +28 -0
  38. package/vectors/binding-projection/app-content-fields.resolved.json +286 -0
  39. package/vectors/binding-projection/field-removed.diagnostic.json +135 -0
  40. package/vectors/binding-projection/model-revision-mismatch.diagnostic.json +124 -0
  41. package/vectors/host/model.get.stored.json +37 -0
  42. package/vectors/host/model.list.authorized.json +31 -0
package/README.md CHANGED
@@ -2,30 +2,39 @@
2
2
 
3
3
  Status: pre-Gate-A foundation alpha. Its conformance helpers do not by themselves constitute gate evidence.
4
4
 
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.
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.
10
11
 
11
12
  Package subpaths under `@kumwe/studio-testkit/fixtures/<filename>` contain byte-identical copies of the
12
13
  canonical valid examples, including separate MediaAsset and persisted MediaReference examples. There
13
14
  is no aggregate runtime `fixtures` export. The helpers do not depend on Vitest or another test runner,
14
15
  so consumers may call the current assertion from any JavaScript test environment.
15
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
+
16
21
  ## Host testbed
17
22
 
18
23
  `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
24
+ for conformance and failure testing. Every standard port is implemented against
20
25
  seeded fixtures (`documents`, `resources`, `mediaAssets`, `messages`, `permissions`, and an
21
26
  optional asynchronous preview `render` callback). Each operation first validates connectivity and the
22
27
  `HostRequestContext`, including exact operation-capability matching, wire protocol, and current session
23
28
  generation. Every failure rejects with `TestbedHostError`, whose `error` document satisfies
24
- `isHostPortError`; `not-found` messages never disclose which identifiers exist. Seed artifact kinds,
25
- revisions, and the optional initial `sessionGeneration` are retained exactly; subsequent revisions
26
- advance as deterministic counters (`<id>-r<n>`). Optimistic-concurrency conflicts return the safe
27
- current revision without changing
28
- stored state, and search/media pagination uses opaque cursors. The returned `controls` drive
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
29
38
  failure scenarios: `disconnect()`/`reconnect()` for retryable `unavailable` outages,
30
39
  `failNext(port, operation, category)` for exactly one injected failure (retryable only for
31
40
  `unavailable` and `rate-limited`), and `setPermissions(...)`, which replaces the permission list
@@ -65,6 +74,11 @@ TypeScript replay is `test/host-sequence-vectors.test.ts`; other runtimes consum
65
74
  schema directly. The exact assertion list and deliberately recorded limits live in
66
75
  `docs/contracts/conformance-profiles.md`.
67
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
+
68
82
  `@kumwe/studio-testkit/vectors/canonical/<filename>` publishes the canonical serialization corpus:
69
83
  each vector carries a bounded value and either the exact canonical string with the SRI-style digest of
70
84
  its UTF-8 bytes, or the stable reason the canonical form refuses it. Its expectations were produced by
@@ -91,14 +105,34 @@ duplicate an otherwise identical keyword, instance pointer, and message diagnost
91
105
  Competing-failure vectors also pin one admission order across root invariants, local-reference
92
106
  resolution, recursion, and structural keyword checks.
93
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
+
94
114
  `@kumwe/studio-testkit/corpus-manifest.json` carries the sha256 digest of every file in the published
95
115
  corpus, grouped by the directory it ships in. A host that vendors the corpus verifies its copy against
96
116
  this manifest, so a stale or altered fixture is detected before it silently changes what a conformance
97
117
  claim means. The schema manifest in `@kumwe/studio-protocol` covers the schemas; this covers everything
98
118
  replayed against them.
99
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
+
100
133
  Gate A requires valid and invalid fixture corpora plus runner-neutral assertions for block, theme,
101
134
  plugin, host-port, command, preview, media, compatibility, migration, lifecycle, security,
102
- accessibility, localization, and TypeScript/Dart equivalence. The host-port and narrow preview-identity
103
- corpora are executable increments; the remaining profiles are target deliverables, and this foundation
104
- alpha must not be cited as gate evidence.
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
+ }