@kumwe/studio-testkit 0.1.0-alpha.6 → 0.1.0-alpha.8

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 (150) hide show
  1. package/README.md +75 -10
  2. package/corpus-manifest.json +1106 -0
  3. package/dist/host-testbed.d.ts +22 -2
  4. package/dist/host-testbed.d.ts.map +1 -1
  5. package/dist/host-testbed.js +357 -31
  6. package/dist/host-testbed.js.map +1 -1
  7. package/dist/http-host-adapter.d.ts.map +1 -1
  8. package/dist/http-host-adapter.js +15 -0
  9. package/dist/http-host-adapter.js.map +1 -1
  10. package/dist/index.d.ts +40 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +36 -2
  13. package/dist/index.js.map +1 -1
  14. package/fixtures/field-adapter.example.json +27 -0
  15. package/fixtures/host-capabilities.example.json +11 -5
  16. package/fixtures/host-operations.example.json +270 -0
  17. package/fixtures/inspector.example.json +17 -0
  18. package/fixtures/media-upload-grant.example.json +14 -0
  19. package/fixtures/preview.render.example.json +1 -0
  20. package/fixtures/studio-config.example.json +4 -4
  21. package/invalid/host-capabilities.invalid-protocol-version.json +1 -1
  22. package/invalid/host-sequence.pending-expectation.json +52 -0
  23. package/invalid/host-sequence.preview-render-missing-request-id.json +50 -0
  24. package/invalid/inspector.empty-block-types.json +20 -0
  25. package/invalid/media-upload-grant.insecure-url.json +14 -0
  26. package/invalid/preview-message.activated-unknown-interaction.json +16 -0
  27. package/invalid/preview-message.duplicate-marker.json +24 -0
  28. package/invalid/preview-message.invalid-digest.json +1 -0
  29. package/invalid/preview-message.invalid-marker-grammar.json +19 -0
  30. package/invalid/preview-message.missing-marker-map.json +20 -0
  31. package/invalid/preview-message.missing-render-request-id.json +18 -0
  32. package/invalid/preview-message.unknown-type.json +13 -0
  33. package/invalid/preview-message.viewport-height-too-small.json +13 -0
  34. package/invalid/preview-message.viewport-role-and-size.json +16 -0
  35. package/invalid/preview-message.viewport-unsafe-role.json +13 -0
  36. package/package.json +6 -4
  37. package/vectors/canonical/array-order.json +13 -0
  38. package/vectors/canonical/control-characters.json +13 -0
  39. package/vectors/canonical/depth-exceeded.json +21 -0
  40. package/vectors/canonical/empty-containers.json +14 -0
  41. package/vectors/canonical/forbidden-member.json +14 -0
  42. package/vectors/canonical/member-order.json +16 -0
  43. package/vectors/canonical/negative-zero.json +13 -0
  44. package/vectors/canonical/nested-order.json +19 -0
  45. package/vectors/canonical/non-ascii.json +13 -0
  46. package/vectors/canonical/numbers.json +16 -0
  47. package/vectors/canonical/string-escapes.json +13 -0
  48. package/vectors/canonical/surrogate-pair.json +13 -0
  49. package/vectors/host/artifact.dependencies.result.json +35 -0
  50. package/vectors/host/artifact.load.stored.json +36 -0
  51. package/vectors/host/artifact.load.unknown.error.json +37 -0
  52. package/vectors/host/artifact.publish.accepted.json +37 -0
  53. package/vectors/host/artifact.publish.forbidden.error.json +37 -0
  54. package/vectors/host/artifact.publish.stale.error.json +38 -0
  55. package/vectors/host/artifact.save.accepted.json +38 -0
  56. package/vectors/host/artifact.save.forbidden.error.json +38 -0
  57. package/vectors/host/artifact.save.stale.error.json +39 -0
  58. package/vectors/host/artifact.unpublish.stale.error.json +38 -0
  59. package/vectors/host/envelope.malformed-context.error.json +36 -0
  60. package/vectors/host/envelope.protocol-version.error.json +36 -0
  61. package/vectors/host/envelope.stale-generation.error.json +36 -0
  62. package/vectors/host/localization.messages.unknown-locale.error.json +36 -0
  63. package/vectors/host/media.abort-upload.unknown.error.json +35 -0
  64. package/vectors/host/media.authorize-upload.granted.json +37 -0
  65. package/vectors/host/media.authorize-upload.path-filename.error.json +39 -0
  66. package/vectors/host/media.authorize-upload.too-large.error.json +38 -0
  67. package/vectors/host/media.complete-upload.unknown.error.json +36 -0
  68. package/vectors/host/media.get.unknown.json +34 -0
  69. package/vectors/host/media.import-external.private-host.error.json +36 -0
  70. package/vectors/host/media.list.cursor.error.json +36 -0
  71. package/vectors/host/media.list.limit.error.json +35 -0
  72. package/vectors/host/media.upload-status.unknown.error.json +35 -0
  73. package/vectors/host/permission.explain.withheld.json +34 -0
  74. package/vectors/host/permission.refresh.snapshot.json +31 -0
  75. package/vectors/host/recovery.load.absent.json +31 -0
  76. package/vectors/host/telemetry.emit.accepted.json +37 -0
  77. package/vectors/host/telemetry.emit.non-primitive.error.json +40 -0
  78. package/vectors/host-sequence/artifact.publish.changed-intent.sequence.json +75 -0
  79. package/vectors/host-sequence/artifact.publish.idempotent-replay.sequence.json +111 -0
  80. package/vectors/host-sequence/preview.cancel.cross-context.sequence.json +78 -0
  81. package/vectors/host-sequence/preview.render.cancelled.sequence.json +75 -0
  82. package/vectors/host-sequence/recovery.store.canonical-number.sequence.json +72 -0
  83. package/vectors/host-sequence/recovery.store.changed-context.sequence.json +61 -0
  84. package/vectors/host-sequence/recovery.store.rate-limited.sequence.json +93 -0
  85. package/vectors/host-sequence/recovery.store.resource-scope.sequence.json +61 -0
  86. package/vectors/host-sequence/recovery.store.wrong-operation-id.sequence.json +56 -0
  87. package/vectors/preview/canonical-preorder.json +102 -0
  88. package/vectors/preview/empty-draft.json +36 -0
  89. package/vectors/schema-profile/alternative-limit.accepted.json +95 -0
  90. package/vectors/schema-profile/alternative-limit.rejected.json +92 -0
  91. package/vectors/schema-profile/array-composition.accepted.json +35 -0
  92. package/vectors/schema-profile/byte-limit.accepted.json +30 -0
  93. package/vectors/schema-profile/byte-limit.rejected.json +26 -0
  94. package/vectors/schema-profile/closed-object.accepted.json +38 -0
  95. package/vectors/schema-profile/decimal-multiple.accepted.json +54 -0
  96. package/vectors/schema-profile/depth-limit.accepted.json +90 -0
  97. package/vectors/schema-profile/depth-limit.rejected.json +88 -0
  98. package/vectors/schema-profile/description-limit.accepted.json +29 -0
  99. package/vectors/schema-profile/description-limit.rejected.json +25 -0
  100. package/vectors/schema-profile/diagnostic-precedence.rejected.json +26 -0
  101. package/vectors/schema-profile/duplicate-dependent-required.rejected.json +21 -0
  102. package/vectors/schema-profile/duplicate-required.rejected.json +18 -0
  103. package/vectors/schema-profile/empty-combinator.rejected.json +17 -0
  104. package/vectors/schema-profile/empty-enum.rejected.json +17 -0
  105. package/vectors/schema-profile/enum-limit.accepted.json +89 -0
  106. package/vectors/schema-profile/enum-limit.rejected.json +84 -0
  107. package/vectors/schema-profile/examples-limit.accepted.json +35 -0
  108. package/vectors/schema-profile/examples-limit.rejected.json +31 -0
  109. package/vectors/schema-profile/format-keyword.rejected.json +17 -0
  110. package/vectors/schema-profile/forward-reference-path-precedence.rejected.json +20 -0
  111. package/vectors/schema-profile/invalid-pointer.rejected.json +18 -0
  112. package/vectors/schema-profile/json-depth-limit.accepted.json +278 -0
  113. package/vectors/schema-profile/json-depth-limit.rejected.json +276 -0
  114. package/vectors/schema-profile/json-item-limit.accepted.json +686 -0
  115. package/vectors/schema-profile/json-item-limit.rejected.json +682 -0
  116. package/vectors/schema-profile/json-property-limit.accepted.json +1031 -0
  117. package/vectors/schema-profile/json-property-limit.rejected.json +1028 -0
  118. package/vectors/schema-profile/local-reference.accepted.json +28 -0
  119. package/vectors/schema-profile/memoized-diagnostic.accepted.json +31 -0
  120. package/vectors/schema-profile/node-limit.accepted.json +1097 -0
  121. package/vectors/schema-profile/node-limit.rejected.json +1094 -0
  122. package/vectors/schema-profile/non-object-root.rejected.json +9 -0
  123. package/vectors/schema-profile/non-schema-reference.rejected.json +21 -0
  124. package/vectors/schema-profile/object-key-limit.accepted.json +32 -0
  125. package/vectors/schema-profile/object-key-limit.rejected.json +28 -0
  126. package/vectors/schema-profile/open-root.rejected.json +13 -0
  127. package/vectors/schema-profile/percent-encoded-pointer.rejected.json +26 -0
  128. package/vectors/schema-profile/property-name-limit.accepted.json +543 -0
  129. package/vectors/schema-profile/property-name-limit.rejected.json +536 -0
  130. package/vectors/schema-profile/recursive-diagnostic-precedence.rejected.json +30 -0
  131. package/vectors/schema-profile/recursive-reference.rejected.json +24 -0
  132. package/vectors/schema-profile/reference-fanout.accepted.json +662 -0
  133. package/vectors/schema-profile/reference-length-limit.accepted.json +45 -0
  134. package/vectors/schema-profile/reference-length-limit.rejected.json +39 -0
  135. package/vectors/schema-profile/reference-limit.accepted.json +416 -0
  136. package/vectors/schema-profile/reference-limit.rejected.json +415 -0
  137. package/vectors/schema-profile/reference-vs-keyword-precedence.rejected.json +22 -0
  138. package/vectors/schema-profile/reserved-pointer.rejected.json +26 -0
  139. package/vectors/schema-profile/root-diagnostic-precedence.rejected.json +16 -0
  140. package/vectors/schema-profile/root-vs-reference-precedence.rejected.json +19 -0
  141. package/vectors/schema-profile/schema-map-limit.accepted.json +539 -0
  142. package/vectors/schema-profile/schema-map-limit.rejected.json +536 -0
  143. package/vectors/schema-profile/semantic-recursion-precedence.rejected.json +21 -0
  144. package/vectors/schema-profile/semantic-reference-precedence.rejected.json +21 -0
  145. package/vectors/schema-profile/title-limit.accepted.json +29 -0
  146. package/vectors/schema-profile/title-limit.rejected.json +25 -0
  147. package/vectors/schema-profile/unresolved-reference.rejected.json +17 -0
  148. package/vectors/schema-profile/unsafe-dependent-required.rejected.json +24 -0
  149. package/vectors/schema-profile/unsafe-member.rejected.json +17 -0
  150. package/vectors/schema-profile/unsafe-required.rejected.json +17 -0
package/README.md CHANGED
@@ -18,22 +18,87 @@ so consumers may call the current assertion from any JavaScript test environment
18
18
  `createTestbedHost(options)` builds a deterministic, fully in-memory `HostAdapter` reference host
19
19
  for conformance and failure testing. Every standard port except `model` is implemented against
20
20
  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
21
+ optional asynchronous preview `render` callback). Each operation first validates connectivity and the
22
+ `HostRequestContext`, including exact operation-capability matching, wire protocol, and current session
23
+ 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
27
28
  stored state, and search/media pagination uses opaque cursors. The returned `controls` drive
28
29
  failure scenarios: `disconnect()`/`reconnect()` for retryable `unavailable` outages,
29
30
  `failNext(port, operation, category)` for exactly one injected failure (retryable only for
30
31
  `unavailable` and `rate-limited`), and `setPermissions(...)`, which replaces the permission list
31
32
  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,
33
+ the `sessionGeneration` getter, and the recorded `telemetryEvents` support assertions. The logical
34
+ `advanceClock()` control and declared fixed-window policies make rate-limit tests deterministic.
35
+ Idempotency records use the published scope/preimage, coalesce matching accepted mutations, reject
36
+ changed intent, and remove failed attempts. Preview render controls expose pending and delivered
37
+ outcomes so cancellation proves that late output is discarded. An injected renderer must return the
38
+ originating draft digest and render `requestId`; an uncorrelated result fails as non-retryable
39
+ `internal` and is never recorded as delivered.
40
+ `createHostRequestContextFixture` builds request envelopes; callers provide the exact operation ID for
41
+ strict hosts. The `allowTestOperationId` option permits only the fixture wildcard for broad unit drills,
42
+ defaults off, and must never be enabled for conformance replay. The testbed uses no wall clock,
34
43
  randomness, or timers, so runs are fully reproducible.
35
44
 
45
+ ## Host conformance corpus
46
+
47
+ `@kumwe/studio-testkit/vectors/host/<filename>` publishes the executable assertion set for
48
+ `studio.profile/host-baseline`. Each vector is language-neutral JSON conforming to
49
+ `host-vector.schema.json`: it fixes the host state to seed (`given`), the request envelope and
50
+ argument to send (`context`, `argument`), and the required outcome (`expect`) — an accepted result
51
+ with its revision behaviour, or one category of the closed error taxonomy with its retry
52
+ classification and non-disclosure obligations. Every precondition is a condition a real host
53
+ reproduces, never a test double, so an adapter written in any language replays the corpus in its own
54
+ test suite without executing Studio code. The reference host's own claim against the profile is
55
+ `test/host-vectors.test.ts`. The profile records the obligations it does not yet assert; consult
56
+ `docs/contracts/conformance-profiles.md` before treating a green replay as complete coverage.
57
+
58
+ `@kumwe/studio-testkit/vectors/host-sequence/<filename>` publishes the additive assertion set for
59
+ `studio.profile/host-baseline-v2`. The bounded sequence shape expresses pending and settled operations,
60
+ fixed-window policies, explicit clock advances and renderer completions, and final state. Nine vectors
61
+ cover in-flight/completed replay, changed argument/context refusal, canonical numeric intent,
62
+ resource-scope separation, wrong-operation refusal, failed-attempt retry after a window reset, matching
63
+ preview cancellation with late-result discard, and cross-context cancellation isolation. The
64
+ TypeScript replay is `test/host-sequence-vectors.test.ts`; other runtimes consume the same JSON and
65
+ schema directly. The exact assertion list and deliberately recorded limits live in
66
+ `docs/contracts/conformance-profiles.md`.
67
+
68
+ `@kumwe/studio-testkit/vectors/canonical/<filename>` publishes the canonical serialization corpus:
69
+ each vector carries a bounded value and either the exact canonical string with the SRI-style digest of
70
+ its UTF-8 bytes, or the stable reason the canonical form refuses it. Its expectations were produced by
71
+ an independent canonicalizer rather than recorded from the reference implementation, so replaying it
72
+ is a cross-implementation check.
73
+
74
+ `@kumwe/studio-testkit/vectors/preview/<filename>` publishes the executable assertion set for
75
+ `studio.profile/preview-identity-v1`. Each complete Blueprint fixes the lowercase SHA-256 digest of
76
+ its canonical UTF-8 bytes, the artifact/revision/digest render tuple with a unique attempt ID, and the
77
+ exact marker preorder plus one-to-one marker map. The reference replay is
78
+ `test/preview-vectors.test.ts`; another runtime hashes and traverses the same JSON without executing
79
+ Studio code.
80
+
81
+ `@kumwe/studio-testkit/vectors/schema-profile/<filename>` publishes the executable assertion set for
82
+ `studio.profile/schema-property`. Accepted candidates carry instance verdicts and the first stable
83
+ keyword/pointer diagnostic; rejected candidates carry the closed admission code and schema pointer.
84
+ `runSchemaProfileVector(vector)` replays one vector through the TypeScript reference without consulting
85
+ its expected verdicts or diagnostics. Other runtimes consume the same JSON directly and do not execute
86
+ testkit code. Boundary vectors identify their published limit, exact value, and side of the ceiling;
87
+ the corpus contains exactly one at-limit and one exact-plus-one case for every advertised limit. Its
88
+ acyclic-reference fan-out case must complete without expanding the reference DAG exponentially. The
89
+ TypeScript reference exposes the full ordered set of distinct failures: repeated branches do not
90
+ duplicate an otherwise identical keyword, instance pointer, and message diagnostic.
91
+ Competing-failure vectors also pin one admission order across root invariants, local-reference
92
+ resolution, recursion, and structural keyword checks.
93
+
94
+ `@kumwe/studio-testkit/corpus-manifest.json` carries the sha256 digest of every file in the published
95
+ corpus, grouped by the directory it ships in. A host that vendors the corpus verifies its copy against
96
+ this manifest, so a stale or altered fixture is detected before it silently changes what a conformance
97
+ claim means. The schema manifest in `@kumwe/studio-protocol` covers the schemas; this covers everything
98
+ replayed against them.
99
+
36
100
  Gate A requires valid and invalid fixture corpora plus runner-neutral assertions for block, theme,
37
101
  plugin, host-port, command, preview, media, compatibility, migration, lifecycle, security,
38
- accessibility, localization, and TypeScript/Dart equivalence. Those remain target deliverables; this
39
- foundation alpha must not be cited as their evidence.
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.