@pie-players/pie-assessment-toolkit 0.3.74 → 0.3.75

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 (228) hide show
  1. package/README.md +349 -313
  2. package/dist/attempt/TestSession.d.ts +1 -20
  3. package/dist/attempt/TestSession.js +8 -99
  4. package/dist/components/ItemScope.custom-element.d.ts +1 -0
  5. package/dist/components/ItemScope.custom-element.js +1 -0
  6. package/dist/components/ItemToolBar.custom-element.js +1 -1
  7. package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
  8. package/dist/components/SectionToolBar.custom-element.js +1 -1
  9. package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
  10. package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-97hx60z4.js} +1 -1
  11. package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
  12. package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
  13. package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
  14. package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
  15. package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
  16. package/dist/components/item-scope-element.d.ts +2 -0
  17. package/dist/components/item-scope-element.js +2 -0
  18. package/dist/context/assessment-toolkit-context.d.ts +27 -6
  19. package/dist/index.d.ts +22 -47
  20. package/dist/index.js +12 -36
  21. package/dist/policy/core/PolicySource.d.ts +1 -1
  22. package/dist/policy/core/ToolPolicyEngine.d.ts +77 -32
  23. package/dist/policy/core/ToolPolicyEngine.js +136 -46
  24. package/dist/policy/core/compose-decision.d.ts +28 -7
  25. package/dist/policy/core/compose-decision.js +75 -54
  26. package/dist/policy/core/decision-types.d.ts +65 -34
  27. package/dist/policy/core/feature-decision.d.ts +16 -9
  28. package/dist/policy/core/feature-decision.js +14 -8
  29. package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
  30. package/dist/policy/core/pnp-policy-inputs.js +28 -56
  31. package/dist/policy/core/provenance.d.ts +9 -4
  32. package/dist/policy/core/provenance.js +1 -1
  33. package/dist/policy/engine.d.ts +7 -23
  34. package/dist/policy/engine.js +5 -20
  35. package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
  36. package/dist/policy/sources/PnpPolicySource.js +117 -118
  37. package/dist/runtime/SectionControllerBinding.d.ts +279 -0
  38. package/dist/runtime/SectionControllerBinding.js +450 -0
  39. package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
  40. package/dist/runtime/SectionRuntimeEngine.js +30 -372
  41. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
  42. package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
  43. package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
  44. package/dist/runtime/adapter/dom-event-bridge.js +17 -44
  45. package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
  46. package/dist/runtime/adapter/subscriber-fanout.js +1 -2
  47. package/dist/runtime/catalog-context.d.ts +19 -0
  48. package/dist/runtime/catalog-context.js +28 -0
  49. package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
  50. package/dist/runtime/composition-emit-scheduler.js +9 -15
  51. package/dist/runtime/content-language.d.ts +32 -0
  52. package/dist/runtime/content-language.js +46 -0
  53. package/dist/runtime/content-region.d.ts +17 -0
  54. package/dist/runtime/content-region.js +29 -0
  55. package/dist/runtime/content-registration.d.ts +13 -0
  56. package/dist/runtime/content-registration.js +25 -0
  57. package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
  58. package/dist/runtime/core/SectionEngineCore.js +2 -2
  59. package/dist/runtime/core/cohort.d.ts +1 -1
  60. package/dist/runtime/core/cohort.js +1 -1
  61. package/dist/runtime/core/engine-input.d.ts +18 -30
  62. package/dist/runtime/core/engine-input.js +11 -12
  63. package/dist/runtime/core/engine-output.d.ts +16 -40
  64. package/dist/runtime/core/engine-output.js +9 -21
  65. package/dist/runtime/core/engine-readiness.d.ts +5 -37
  66. package/dist/runtime/core/engine-readiness.js +8 -41
  67. package/dist/runtime/core/engine-resolver.d.ts +46 -74
  68. package/dist/runtime/core/engine-resolver.js +18 -43
  69. package/dist/runtime/core/engine-state.d.ts +28 -36
  70. package/dist/runtime/core/engine-state.js +18 -21
  71. package/dist/runtime/core/engine-transition.d.ts +14 -19
  72. package/dist/runtime/core/engine-transition.js +71 -51
  73. package/dist/runtime/engine.d.ts +16 -19
  74. package/dist/runtime/engine.js +12 -19
  75. package/dist/runtime/page-warnings.d.ts +13 -0
  76. package/dist/runtime/page-warnings.js +22 -0
  77. package/dist/runtime/policy-input-forwarding.d.ts +25 -0
  78. package/dist/runtime/policy-input-forwarding.js +25 -0
  79. package/dist/runtime/registration-events.d.ts +11 -0
  80. package/dist/runtime/runtime-event-claim.d.ts +8 -0
  81. package/dist/runtime/runtime-event-claim.js +15 -0
  82. package/dist/runtime/shell-event-bridge.d.ts +45 -0
  83. package/dist/runtime/shell-event-bridge.js +127 -0
  84. package/dist/runtime/shell-registration.d.ts +73 -0
  85. package/dist/runtime/shell-registration.js +95 -0
  86. package/dist/runtime/shell-scope.d.ts +68 -0
  87. package/dist/runtime/shell-scope.js +188 -0
  88. package/dist/runtime/tool-host-contract.d.ts +8 -10
  89. package/dist/runtime/tool-host-contract.js +11 -11
  90. package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
  91. package/dist/runtime/unclaimed-registration-watch.js +23 -0
  92. package/dist/services/ElementToolStateStore.d.ts +14 -10
  93. package/dist/services/ElementToolStateStore.js +37 -13
  94. package/dist/services/HighlightCoordinator.d.ts +21 -21
  95. package/dist/services/HighlightCoordinator.js +431 -325
  96. package/dist/services/RangeSerializer.d.ts +10 -1
  97. package/dist/services/RangeSerializer.js +87 -14
  98. package/dist/services/TTSService.d.ts +117 -70
  99. package/dist/services/TTSService.js +668 -578
  100. package/dist/services/ToolCoordinator.d.ts +43 -60
  101. package/dist/services/ToolCoordinator.js +164 -206
  102. package/dist/services/ToolRegistry.d.ts +74 -57
  103. package/dist/services/ToolRegistry.js +104 -114
  104. package/dist/services/ToolkitCoordinator.d.ts +183 -189
  105. package/dist/services/ToolkitCoordinator.js +477 -431
  106. package/dist/services/audio-handoff.d.ts +6 -7
  107. package/dist/services/audio-handoff.js +20 -14
  108. package/dist/services/catalog-owner.d.ts +0 -1
  109. package/dist/services/framework-error-bus.d.ts +3 -6
  110. package/dist/services/framework-error-bus.js +3 -6
  111. package/dist/services/framework-error.d.ts +22 -7
  112. package/dist/services/framework-error.js +9 -7
  113. package/dist/services/interfaces.d.ts +158 -129
  114. package/dist/services/section-session-assignment.d.ts +21 -0
  115. package/dist/services/section-session-assignment.js +82 -0
  116. package/dist/services/spoken-audio-cards.d.ts +0 -2
  117. package/dist/services/spoken-audio-cards.js +0 -2
  118. package/dist/services/tool-config-defaults.d.ts +3 -3
  119. package/dist/services/tool-config-defaults.js +3 -3
  120. package/dist/services/tool-config-validation.d.ts +4 -5
  121. package/dist/services/tool-config-validation.js +36 -61
  122. package/dist/services/tool-context.d.ts +0 -8
  123. package/dist/services/tool-context.js +0 -12
  124. package/dist/services/tool-icons.d.ts +4 -3
  125. package/dist/services/tool-icons.js +4 -3
  126. package/dist/services/tool-instance-id.d.ts +0 -1
  127. package/dist/services/tool-instance-id.js +0 -6
  128. package/dist/services/tool-providers/TTSToolProvider.d.ts +18 -19
  129. package/dist/services/tool-providers/TTSToolProvider.js +37 -34
  130. package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
  131. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +30 -26
  132. package/dist/services/tool-providers/ToolProviderRegistry.js +119 -93
  133. package/dist/services/tool-request.d.ts +27 -12
  134. package/dist/services/tool-request.js +24 -14
  135. package/dist/services/toolbar-decided-tools.d.ts +15 -0
  136. package/dist/services/toolbar-decided-tools.js +28 -0
  137. package/dist/services/tools-config-normalizer.d.ts +17 -22
  138. package/dist/services/tools-config-normalizer.js +2 -10
  139. package/dist/services/tts/browser-provider.d.ts +38 -2
  140. package/dist/services/tts/browser-provider.js +276 -140
  141. package/dist/services/tts/flat-tree.d.ts +71 -0
  142. package/dist/services/tts/flat-tree.js +269 -0
  143. package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
  144. package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
  145. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
  146. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
  147. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
  148. package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
  149. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +12 -4
  150. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
  151. package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
  152. package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
  153. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
  154. package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
  155. package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
  156. package/dist/services/tts/math-aware-text-processing.js +32 -18
  157. package/dist/services/tts/math-control-names.d.ts +21 -0
  158. package/dist/services/tts/math-control-names.js +142 -0
  159. package/dist/services/tts/math-speech.d.ts +11 -0
  160. package/dist/services/tts/math-speech.js +51 -18
  161. package/dist/services/tts/provider-options.d.ts +41 -0
  162. package/dist/services/tts/provider-options.js +1 -0
  163. package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
  164. package/dist/services/tts/ssml/spoken-text.js +29 -0
  165. package/dist/services/tts/start-failure.d.ts +11 -0
  166. package/dist/services/tts/start-failure.js +19 -0
  167. package/dist/services/tts/text-processing.d.ts +9 -0
  168. package/dist/services/tts/text-processing.js +46 -33
  169. package/dist/services/tts/text-segmentation.d.ts +7 -0
  170. package/dist/services/tts/text-segmentation.js +47 -0
  171. package/dist/services/tts-runtime-config.d.ts +25 -17
  172. package/dist/services/tts-runtime-config.js +16 -95
  173. package/dist/tools/content-capability-resolution.d.ts +7 -9
  174. package/dist/tools/content-capability-resolution.js +8 -45
  175. package/dist/tools/registration.d.ts +58 -0
  176. package/dist/tools/registration.js +54 -0
  177. package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
  178. package/dist/tools/tool-surface-host.d.ts +6 -10
  179. package/dist/tools/tool-surface-host.js +44 -42
  180. package/dist/tools/tool-tag-map.d.ts +5 -15
  181. package/dist/tools/tool-tag-map.js +6 -20
  182. package/dist/utils/structural-equality.d.ts +11 -0
  183. package/dist/utils/structural-equality.js +47 -0
  184. package/package.json +13 -29
  185. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
  186. package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
  187. package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +0 -40
  188. package/dist/components/chunks/ItemToolBar-h4xap0t0.js +0 -4
  189. package/dist/components/chunks/ItemToolBar-wr2myaah.js +0 -2
  190. package/dist/components/chunks/sre-engine-wf9s43gg.js +0 -1
  191. package/dist/context/runtime-context-consumer.d.ts +0 -13
  192. package/dist/context/runtime-context-consumer.js +0 -18
  193. package/dist/item-loader.d.ts +0 -44
  194. package/dist/item-loader.js +0 -61
  195. package/dist/policy/core/engine-context.d.ts +0 -29
  196. package/dist/policy/core/engine-context.js +0 -27
  197. package/dist/policy/core/policy-source-tag.d.ts +0 -31
  198. package/dist/policy/core/policy-source-tag.js +0 -28
  199. package/dist/policy/internal.d.ts +0 -25
  200. package/dist/policy/internal.js +0 -25
  201. package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
  202. package/dist/runtime/adapter/coordinator-bridge.js +0 -126
  203. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
  204. package/dist/runtime/adapter/framework-error-bridge.js +0 -46
  205. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
  206. package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
  207. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
  208. package/dist/runtime/core/engine-stage-derivation.js +0 -29
  209. package/dist/runtime/engine-context.d.ts +0 -39
  210. package/dist/runtime/engine-context.js +0 -31
  211. package/dist/runtime/internal.d.ts +0 -43
  212. package/dist/runtime/internal.js +0 -45
  213. package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -74
  214. package/dist/runtime/section-runtime-engine-host-context.js +0 -57
  215. package/dist/runtime/stage-emit-gate.d.ts +0 -92
  216. package/dist/runtime/stage-emit-gate.js +0 -82
  217. package/dist/services/I18nService.d.ts +0 -47
  218. package/dist/services/I18nService.js +0 -84
  219. package/dist/services/ThemeProvider.d.ts +0 -95
  220. package/dist/services/ThemeProvider.js +0 -334
  221. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
  222. package/dist/services/defaultPersonalNeedsProfile.js +0 -26
  223. package/dist/services/pnp-standard-features.d.ts +0 -238
  224. package/dist/services/pnp-standard-features.js +0 -338
  225. package/dist/tools/client.d.ts +0 -10
  226. package/dist/tools/client.js +0 -10
  227. package/dist/tools/internal.d.ts +0 -44
  228. package/dist/tools/internal.js +0 -39
@@ -1,61 +1,33 @@
1
1
  /**
2
- * Section runtime engine adapter (M7 — Variant C, layered).
2
+ * Section runtime engine adapter.
3
3
  *
4
4
  * The adapter is the single I/O seam between the pure FSM core
5
- * (`SectionEngineCore`) and the rest of the world (DOM, coordinator,
6
- * framework-error bus, host subscribers, instrumentation). It does
7
- * exactly two jobs:
5
+ * (`SectionEngineCore`) and the rest of the world (the DOM and host
6
+ * subscribers). It does exactly two jobs:
8
7
  *
9
- * 1. Translate **host inputs** (from kernels, the toolkit CE, or
10
- * direct facade callers) into `SectionEngineInput`s and forward
11
- * them to the core via `core.dispatch(input)`.
8
+ * 1. Forward host-constructed `SectionEngineInput`s to the core via
9
+ * `core.dispatch(input)`.
12
10
  *
13
- * 2. Subscribe to the core's output stream and **route each output**
14
- * through the bridges in a deterministic order so the public DOM
15
- * surface, framework-error bus, instrumentation hook, and host
16
- * subscribers all see exactly the same fan-out with
17
- * byte-identical detail shapes.
11
+ * 2. Subscribe to the core's output stream and route each batch, in
12
+ * order, to the DOM-event bridge (`pie-stage-change`,
13
+ * `pie-loading-complete`) and then to the subscriber fan-out (one
14
+ * batch per `core.dispatch`).
18
15
  *
19
- * Output routing is a single exhaustive `switch` (`assertNever` on
20
- * the default branch) so adding a new `SectionEngineOutput` kind in
21
- * `engine-output.ts` is a compile error here until the adapter knows
22
- * what to do with it.
16
+ * Output routing is a single exhaustive `switch`, so a new
17
+ * `SectionEngineOutput` kind is a compile error here until the adapter
18
+ * routes it.
23
19
  *
24
- * **Routing order per output:**
25
- * - canonical DOM event (`pie-stage-change`, `pie-loading-complete`,
26
- * `framework-error`)
27
- * - framework-error bus (single fan-out for in-process subscribers)
28
- * - instrumentation hook
29
- * - public subscriber fan-out (batched, runs once per
30
- * `core.dispatch`)
31
- *
32
- * The `readiness-change` / `interaction-ready` / `ready`
33
- * DOM events and their event bridge were removed in the
34
- * broad architecture review compat sweep; the corresponding output
35
- * kinds are gone from `engine-output.ts`.
36
- *
37
- * **Layering constraint.** The adapter is plain TS. It must not
38
- * import `svelte` — the M7 implementation plan and
39
- * `scripts/check-engine-core-purity.mjs` enforce the core's purity;
40
- * the adapter follows the same constraint by convention so it stays
41
- * usable from non-Svelte hosts (Node tests, Storybook, or future
42
- * non-Svelte consumers). `bun run check:custom-elements:dist`
43
- * already blocks `.svelte` imports in published `dist`; adding a
44
- * Svelte dependency here would also leak through that gate.
20
+ * **Layering constraint.** The adapter is plain TS and must not import
21
+ * `svelte`; `scripts/check-engine-core-purity.mjs` enforces it, so the
22
+ * adapter stays usable from non-Svelte hosts and Node tests.
45
23
  */
46
24
  import { SectionEngineCore } from "../core/SectionEngineCore.js";
47
- import { createCoordinatorBridge, } from "./coordinator-bridge.js";
48
25
  import { createDomEventBridge, } from "./dom-event-bridge.js";
49
- import { createFrameworkErrorBridge, } from "./framework-error-bridge.js";
50
- import { createInstrumentationBridge, } from "./instrumentation-bridge.js";
51
26
  import { createSubscriberFanout, } from "./subscriber-fanout.js";
52
27
  export class SectionEngineAdapter {
53
28
  core;
54
29
  domEventBridge;
55
- frameworkErrorBridge;
56
- instrumentationBridge;
57
30
  subscriberFanout;
58
- coordinatorBridge;
59
31
  unsubscribeCore;
60
32
  disposed = false;
61
33
  constructor(options) {
@@ -66,19 +38,7 @@ export class SectionEngineAdapter {
66
38
  sourceCe: options.sourceCe,
67
39
  now: options.now,
68
40
  });
69
- this.frameworkErrorBridge = createFrameworkErrorBridge({
70
- bus: options.frameworkErrorBus,
71
- });
72
- this.instrumentationBridge = createInstrumentationBridge({
73
- hook: options.instrumentationHook,
74
- });
75
41
  this.subscriberFanout = createSubscriberFanout();
76
- this.coordinatorBridge = options.coordinator
77
- ? createCoordinatorBridge({
78
- coordinator: options.coordinator,
79
- dispatchCoreInput: (input) => this.dispatchInput(input),
80
- })
81
- : null;
82
42
  this.unsubscribeCore = this.core.subscribe((outputs) => {
83
43
  this.routeOutputs(outputs);
84
44
  });
@@ -114,35 +74,11 @@ export class SectionEngineAdapter {
114
74
  this.domEventBridge.setHost(host);
115
75
  }
116
76
  /**
117
- * Update the instrumentation hook at runtime.
118
- */
119
- setInstrumentationHook(hook) {
120
- this.instrumentationBridge.setHook(hook);
121
- }
122
- /**
123
- * Resolve a section controller through the configured coordinator.
124
- *
125
- * Throws if the adapter was constructed without a coordinator.
126
- * Standalone callers should manually feed
127
- * `{ kind: "section-controller-resolved" }` after their own
128
- * controller resolution path completes.
77
+ * Tear the adapter down. Safe to call more than once. Emits `disposed`
78
+ * for the active cohort, then detaches the core subscription and
79
+ * clears subscribers.
129
80
  */
130
- resolveSectionController(args) {
131
- if (!this.coordinatorBridge) {
132
- throw new Error("[SectionEngineAdapter] resolveSectionController called without a coordinator.");
133
- }
134
- return this.coordinatorBridge.resolveSectionController(args);
135
- }
136
- /**
137
- * Tear the adapter down. Safe to call more than once. Disposes the
138
- * coordinator bridge (which in turn disposes the section
139
- * controller for the current cohort), detaches the core
140
- * subscription, and clears subscribers.
141
- *
142
- * Does **not** dispose the framework-error bus — its lifetime is
143
- * owned by the toolkit CE / host.
144
- */
145
- async dispose() {
81
+ dispose() {
146
82
  if (this.disposed)
147
83
  return;
148
84
  this.disposed = true;
@@ -151,9 +87,6 @@ export class SectionEngineAdapter {
151
87
  this.core.dispatch({ kind: "dispose" });
152
88
  this.unsubscribeCore();
153
89
  this.subscriberFanout.dispose();
154
- if (this.coordinatorBridge) {
155
- await this.coordinatorBridge.dispose();
156
- }
157
90
  }
158
91
  routeOutputs(outputs) {
159
92
  for (const output of outputs) {
@@ -167,16 +100,10 @@ export class SectionEngineAdapter {
167
100
  case "loading-complete":
168
101
  this.domEventBridge.dispatch(output);
169
102
  break;
170
- case "framework-error":
171
- this.domEventBridge.dispatch(output);
172
- this.frameworkErrorBridge.dispatch(output);
173
- break;
174
103
  default: {
175
104
  const exhaustive = output;
176
105
  void exhaustive;
177
- return;
178
106
  }
179
107
  }
180
- this.instrumentationBridge.dispatch(output);
181
108
  }
182
109
  }
@@ -1,36 +1,21 @@
1
1
  /**
2
- * DOM event bridge for the section runtime engine adapter (M7 — Variant
3
- * C, layered).
2
+ * DOM event bridge for the section runtime engine adapter.
4
3
  *
5
- * Translates canonical engine outputs (`stage-change`,
6
- * `loading-complete`, `framework-error`) into DOM `CustomEvent`
7
- * dispatches on the host element. Mirrors the kernel's existing
8
- * `dispatch("pie-stage-change", …)` / `dispatch("pie-loading-complete", …)`
9
- * / `dispatch("framework-error", …)` emit chain bit-for-bit so the M6
10
- * canonical event surface stays stable while the kernel migrates onto
11
- * the engine in PR 5.
4
+ * Translates engine outputs (`stage-change`, `loading-complete`) into
5
+ * `pie-stage-change` and `pie-loading-complete` on the host element. Both are
6
+ * dispatched with `CROSS_BOUNDARY_EVENT_INIT` (bubbling, composed), the init
7
+ * every other runtime event uses, so a listener above the layout element hears
8
+ * them as it hears `toolkit-ready` or `framework-error`.
12
9
  *
13
- * **Detail-shape contract.** The engine core emits structurally minimal
14
- * outputs (`{ stage, status, cohort }`, `{ cohort, itemCount,
15
- * loadedCount }`). The bridge enriches them with `runtimeId`,
16
- * `sourceCe`, and `timestamp` so the dispatched DOM event detail
17
- * matches the canonical
18
- * `packages/players-shared/src/pie/stages.ts#StageChangeDetail` and
19
- * `LoadingCompleteDetail` shapes verbatim. `runtimeId` and `sourceCe`
20
- * are supplied at adapter construction time (one per engine instance);
21
- * `timestamp` is captured per-emit via the injected `now()` clock so
22
- * tests can pin a deterministic value.
10
+ * **Detail-shape contract.** The core emits structurally minimal outputs
11
+ * (`{ stage, status, cohort }`, `{ cohort, itemCount }`). The bridge enriches
12
+ * them with `runtimeId`, `sourceCe` and `timestamp` so the dispatched detail
13
+ * matches `StageChangeDetail` and `LoadingCompleteDetail` in
14
+ * `packages/players-shared/src/pie/stages.ts`. `runtimeId` and `sourceCe` are
15
+ * fixed per engine; `timestamp` comes from the injected `now()` clock.
23
16
  *
24
- * **Why not import the stage tracker.** The tracker's monotonic /
25
- * skipped-fill enforcement now lives in the engine core's transition
26
- * function. The bridge is purely an output-to-DOM translator — it does
27
- * not gate emissions, does not re-order, does not de-duplicate. That
28
- * keeps the responsibility clean and matches the "outputs are already
29
- * ordered correctly by the core" contract from
30
- * `engine-transition.ts`.
31
- *
32
- * The bridge **must not** import `svelte`; per the M7 layering
33
- * constraint the adapter is plain TS.
17
+ * The bridge only translates: ordering and once-per-cohort gating belong to
18
+ * the transition function. It must not import `svelte`.
34
19
  */
35
20
  import type { SectionEngineOutput } from "../core/engine-output.js";
36
21
  export interface DomEventBridgeOptions {
@@ -41,7 +26,7 @@ export interface DomEventBridgeOptions {
41
26
  /**
42
27
  * Tag name of the host CE without the `--version-<encoded>` suffix.
43
28
  * Each layout CE that mounts the kernel passes its own canonical tag
44
- * name; the toolkit CE passes its own.
29
+ * name.
45
30
  */
46
31
  sourceCe: string;
47
32
  /**
@@ -1,37 +1,23 @@
1
1
  /**
2
- * DOM event bridge for the section runtime engine adapter (M7 — Variant
3
- * C, layered).
2
+ * DOM event bridge for the section runtime engine adapter.
4
3
  *
5
- * Translates canonical engine outputs (`stage-change`,
6
- * `loading-complete`, `framework-error`) into DOM `CustomEvent`
7
- * dispatches on the host element. Mirrors the kernel's existing
8
- * `dispatch("pie-stage-change", …)` / `dispatch("pie-loading-complete", …)`
9
- * / `dispatch("framework-error", …)` emit chain bit-for-bit so the M6
10
- * canonical event surface stays stable while the kernel migrates onto
11
- * the engine in PR 5.
4
+ * Translates engine outputs (`stage-change`, `loading-complete`) into
5
+ * `pie-stage-change` and `pie-loading-complete` on the host element. Both are
6
+ * dispatched with `CROSS_BOUNDARY_EVENT_INIT` (bubbling, composed), the init
7
+ * every other runtime event uses, so a listener above the layout element hears
8
+ * them as it hears `toolkit-ready` or `framework-error`.
12
9
  *
13
- * **Detail-shape contract.** The engine core emits structurally minimal
14
- * outputs (`{ stage, status, cohort }`, `{ cohort, itemCount,
15
- * loadedCount }`). The bridge enriches them with `runtimeId`,
16
- * `sourceCe`, and `timestamp` so the dispatched DOM event detail
17
- * matches the canonical
18
- * `packages/players-shared/src/pie/stages.ts#StageChangeDetail` and
19
- * `LoadingCompleteDetail` shapes verbatim. `runtimeId` and `sourceCe`
20
- * are supplied at adapter construction time (one per engine instance);
21
- * `timestamp` is captured per-emit via the injected `now()` clock so
22
- * tests can pin a deterministic value.
10
+ * **Detail-shape contract.** The core emits structurally minimal outputs
11
+ * (`{ stage, status, cohort }`, `{ cohort, itemCount }`). The bridge enriches
12
+ * them with `runtimeId`, `sourceCe` and `timestamp` so the dispatched detail
13
+ * matches `StageChangeDetail` and `LoadingCompleteDetail` in
14
+ * `packages/players-shared/src/pie/stages.ts`. `runtimeId` and `sourceCe` are
15
+ * fixed per engine; `timestamp` comes from the injected `now()` clock.
23
16
  *
24
- * **Why not import the stage tracker.** The tracker's monotonic /
25
- * skipped-fill enforcement now lives in the engine core's transition
26
- * function. The bridge is purely an output-to-DOM translator — it does
27
- * not gate emissions, does not re-order, does not de-duplicate. That
28
- * keeps the responsibility clean and matches the "outputs are already
29
- * ordered correctly by the core" contract from
30
- * `engine-transition.ts`.
31
- *
32
- * The bridge **must not** import `svelte`; per the M7 layering
33
- * constraint the adapter is plain TS.
17
+ * The bridge only translates: ordering and once-per-cohort gating belong to
18
+ * the transition function. It must not import `svelte`.
34
19
  */
20
+ import { dispatchCrossBoundaryEvent } from "../tool-host-contract.js";
35
21
  export function createDomEventBridge(options) {
36
22
  const { runtimeId, sourceCe } = options;
37
23
  let host = options.host;
@@ -46,7 +32,7 @@ export function createDomEventBridge(options) {
46
32
  timestamp: now(),
47
33
  sourceCe,
48
34
  };
49
- host.dispatchEvent(new CustomEvent("pie-stage-change", { detail }));
35
+ dispatchCrossBoundaryEvent(host, "pie-stage-change", detail);
50
36
  }
51
37
  function dispatchLoadingComplete(output) {
52
38
  const detail = {
@@ -54,20 +40,10 @@ export function createDomEventBridge(options) {
54
40
  sectionId: output.cohort.sectionId,
55
41
  attemptId: output.cohort.attemptId ? output.cohort.attemptId : undefined,
56
42
  itemCount: output.itemCount,
57
- loadedCount: output.loadedCount,
58
43
  timestamp: now(),
59
44
  sourceCe,
60
45
  };
61
- host.dispatchEvent(new CustomEvent("pie-loading-complete", {
62
- detail,
63
- }));
64
- }
65
- function dispatchFrameworkError(output) {
66
- // Mirror the kernel's existing surface — the `framework-error`
67
- // DOM event detail is the framework-error model. The
68
- // `framework-error-bridge` separately reports the same model
69
- // into the bus so subscribers see one fan-out per error.
70
- host.dispatchEvent(new CustomEvent("framework-error", { detail: output.error }));
46
+ dispatchCrossBoundaryEvent(host, "pie-loading-complete", detail);
71
47
  }
72
48
  function dispatch(output) {
73
49
  switch (output.kind) {
@@ -77,9 +53,6 @@ export function createDomEventBridge(options) {
77
53
  case "loading-complete":
78
54
  dispatchLoadingComplete(output);
79
55
  return;
80
- case "framework-error":
81
- dispatchFrameworkError(output);
82
- return;
83
56
  default: {
84
57
  const exhaustive = output;
85
58
  void exhaustive;
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Subscriber fan-out for the section runtime engine adapter (M7 — Variant
3
- * C, layered).
2
+ * Subscriber fan-out for the section runtime engine adapter.
4
3
  *
5
4
  * The adapter exposes a single `subscribe(listener)` channel for hosts
6
5
  * that want a synchronous stream of `SectionEngineOutput[]` batches —
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Subscriber fan-out for the section runtime engine adapter (M7 — Variant
3
- * C, layered).
2
+ * Subscriber fan-out for the section runtime engine adapter.
4
3
  *
5
4
  * The adapter exposes a single `subscribe(listener)` channel for hosts
6
5
  * that want a synchronous stream of `SectionEngineOutput[]` batches —
@@ -0,0 +1,19 @@
1
+ import { type AssessmentToolkitShellContext } from "../context/assessment-toolkit-context.js";
2
+ import type { CatalogLookupContext } from "../services/AccessibilityCatalogResolver.js";
3
+ /** Where a shell's owner registered its catalogs, from the toolkit runtime context. */
4
+ export interface CatalogRuntimeScope {
5
+ assessmentId?: string;
6
+ sectionId?: string;
7
+ }
8
+ /**
9
+ * The catalog lookup context for content in `shell`: the cards its owner
10
+ * registered, then the assessment's.
11
+ */
12
+ export declare const catalogContextForShell: (shell: AssessmentToolkitShellContext, runtime?: CatalogRuntimeScope | null) => CatalogLookupContext;
13
+ /**
14
+ * The catalog lookup context for the shell scope holding `node`, asked of that
15
+ * shell's context provider at the time of the call, or undefined outside every
16
+ * shell scope. For a tool that serves several shells and so has no shell
17
+ * context of its own, such as the section-wide annotation toolbar.
18
+ */
19
+ export declare const catalogContextHolding: (node: Node, runtime?: CatalogRuntimeScope | null) => CatalogLookupContext | undefined;
@@ -0,0 +1,28 @@
1
+ import { requestContext } from "@pie-players/pie-context";
2
+ import { assessmentToolkitShellContext, } from "../context/assessment-toolkit-context.js";
3
+ import { catalogOwnerContextFor } from "../services/catalog-owner.js";
4
+ import { composedParentElement } from "../services/tts/flat-tree.js";
5
+ /**
6
+ * The catalog lookup context for content in `shell`: the cards its owner
7
+ * registered, then the assessment's.
8
+ */
9
+ export const catalogContextForShell = (shell, runtime) => catalogOwnerContextFor({
10
+ kind: shell.kind,
11
+ assessmentId: runtime?.assessmentId,
12
+ sectionId: runtime?.sectionId,
13
+ itemId: shell.itemId,
14
+ canonicalItemId: shell.canonicalItemId || shell.itemId,
15
+ });
16
+ /**
17
+ * The catalog lookup context for the shell scope holding `node`, asked of that
18
+ * shell's context provider at the time of the call, or undefined outside every
19
+ * shell scope. For a tool that serves several shells and so has no shell
20
+ * context of its own, such as the section-wide annotation toolbar.
21
+ */
22
+ export const catalogContextHolding = (node, runtime) => {
23
+ const element = node.nodeType === 1 ? node : composedParentElement(node);
24
+ const shell = element
25
+ ? requestContext(element, assessmentToolkitShellContext)
26
+ : undefined;
27
+ return shell ? catalogContextForShell(shell, runtime) : undefined;
28
+ };
@@ -1,23 +1,18 @@
1
1
  /**
2
- * Composition emit scheduler (PIE-885).
2
+ * Composition emit scheduler.
3
3
  *
4
4
  * `PieAssessmentToolkit.svelte` publishes the section composition to the
5
5
  * players through exactly one path — the `composition-changed` event — and
6
6
  * coalesces bursts of updates behind a one-shot latch so several changes
7
7
  * within one frame produce a single emit.
8
8
  *
9
- * That latch used to be cleared only by a `requestAnimationFrame` callback,
10
- * and the frame branch was chosen whenever `window.requestAnimationFrame`
11
- * merely *existed* rather than when it was known to fire. In a document that
12
- * never paints the callback never ran, the latch never cleared, and no
13
- * `composition-changed` was ever dispatched: the section controller held a
14
- * correct view model while the player kept its initial empty composition, so
15
- * every `pie-section-player` route rendered no content at all. The permanent
16
- * failure was in contexts with no compositor — headless browsers, hidden or
17
- * offscreen tabs, agent and CI automation harnesses. A background tab only
18
- * rendered late, because its pending frame becomes due on refocus.
19
- *
20
- * So the frame is raced against a deadline timer instead of trusted. Whichever
9
+ * The latch is released by a `requestAnimationFrame` callback raced against a
10
+ * deadline timer, because the existence of `window.requestAnimationFrame` does
11
+ * not mean it fires: in a document with no compositor (headless browsers,
12
+ * hidden or offscreen tabs, CI and agent harnesses) the callback never runs, so
13
+ * a frame-only latch would never clear and the player would keep its initial
14
+ * empty composition while the section controller held a correct view model. A
15
+ * background tab's pending frame only becomes due on refocus. Whichever
21
16
  * arrives first releases the latch and flushes, and a non-painting document
22
17
  * degrades to a slower render rather than a permanent blank. Svelte's own
23
18
  * `tick()` races the same two primitives for the same reason.
@@ -34,8 +29,7 @@
34
29
  *
35
30
  * NOT a public surface: internal to the toolkit and not exported from
36
31
  * `runtime/engine.ts`. It exists as its own module so the race can be pinned in
37
- * a unit test without mounting the toolkit CE — same rationale as
38
- * `runtime/stage-emit-gate.ts`.
32
+ * a unit test without mounting the toolkit CE.
39
33
  */
40
34
  /**
41
35
  * How long to wait for a frame before the timer takes over.
@@ -1,23 +1,18 @@
1
1
  /**
2
- * Composition emit scheduler (PIE-885).
2
+ * Composition emit scheduler.
3
3
  *
4
4
  * `PieAssessmentToolkit.svelte` publishes the section composition to the
5
5
  * players through exactly one path — the `composition-changed` event — and
6
6
  * coalesces bursts of updates behind a one-shot latch so several changes
7
7
  * within one frame produce a single emit.
8
8
  *
9
- * That latch used to be cleared only by a `requestAnimationFrame` callback,
10
- * and the frame branch was chosen whenever `window.requestAnimationFrame`
11
- * merely *existed* rather than when it was known to fire. In a document that
12
- * never paints the callback never ran, the latch never cleared, and no
13
- * `composition-changed` was ever dispatched: the section controller held a
14
- * correct view model while the player kept its initial empty composition, so
15
- * every `pie-section-player` route rendered no content at all. The permanent
16
- * failure was in contexts with no compositor — headless browsers, hidden or
17
- * offscreen tabs, agent and CI automation harnesses. A background tab only
18
- * rendered late, because its pending frame becomes due on refocus.
19
- *
20
- * So the frame is raced against a deadline timer instead of trusted. Whichever
9
+ * The latch is released by a `requestAnimationFrame` callback raced against a
10
+ * deadline timer, because the existence of `window.requestAnimationFrame` does
11
+ * not mean it fires: in a document with no compositor (headless browsers,
12
+ * hidden or offscreen tabs, CI and agent harnesses) the callback never runs, so
13
+ * a frame-only latch would never clear and the player would keep its initial
14
+ * empty composition while the section controller held a correct view model. A
15
+ * background tab's pending frame only becomes due on refocus. Whichever
21
16
  * arrives first releases the latch and flushes, and a non-painting document
22
17
  * degrades to a slower render rather than a permanent blank. Svelte's own
23
18
  * `tick()` races the same two primitives for the same reason.
@@ -34,8 +29,7 @@
34
29
  *
35
30
  * NOT a public surface: internal to the toolkit and not exported from
36
31
  * `runtime/engine.ts`. It exists as its own module so the race can be pinned in
37
- * a unit test without mounting the toolkit CE — same rationale as
38
- * `runtime/stage-emit-gate.ts`.
32
+ * a unit test without mounting the toolkit CE.
39
33
  */
40
34
  /**
41
35
  * How long to wait for a frame before the timer takes over.
@@ -0,0 +1,32 @@
1
+ /** The content language when neither the markup nor the host names one. */
2
+ export declare const DEFAULT_CONTENT_LANGUAGE = "en-US";
3
+ /**
4
+ * The nearest non-empty `lang` attribute at or above `node`, climbing through
5
+ * shadow hosts, and ending after `boundary` when one is given.
6
+ */
7
+ export declare const findLangAttribute: (node: Node | null | undefined, boundary?: Element | null) => string | undefined;
8
+ export interface ContentLanguageOptions {
9
+ /**
10
+ * Where the `lang` climb ends, inclusive. Defaults to the nearest shell scope
11
+ * host above the target; with neither, markup names no language.
12
+ */
13
+ boundary?: Element | null;
14
+ /** The host's `content-language` input. */
15
+ contentLanguage?: string | null;
16
+ }
17
+ /**
18
+ * The language the content at `target` is named as being in: the nearest `lang`
19
+ * between it and its shell scope host, else the host's `content-language` input.
20
+ * Undefined when neither names one.
21
+ *
22
+ * The climb stops at the shell because the page's own `lang` above it is the
23
+ * interface language, which the toolkit's `locale` carries; content language is
24
+ * the content's. Resolved at speak time, since a reading target's markup can
25
+ * change between reads.
26
+ */
27
+ export declare const findContentLanguage: (target: Node | null | undefined, options?: ContentLanguageOptions) => string | undefined;
28
+ /**
29
+ * {@link findContentLanguage}, else `en-US`: the language text processing and
30
+ * catalog lookup read.
31
+ */
32
+ export declare const resolveContentLanguage: (target: Node | null | undefined, options?: ContentLanguageOptions) => string;
@@ -0,0 +1,46 @@
1
+ import { composedParentElement } from "../services/tts/flat-tree.js";
2
+ import { findShellScopeHost } from "./content-region.js";
3
+ /** The content language when neither the markup nor the host names one. */
4
+ export const DEFAULT_CONTENT_LANGUAGE = "en-US";
5
+ /**
6
+ * The nearest non-empty `lang` attribute at or above `node`, climbing through
7
+ * shadow hosts, and ending after `boundary` when one is given.
8
+ */
9
+ export const findLangAttribute = (node, boundary) => {
10
+ let current = !node
11
+ ? null
12
+ : node.nodeType === 1
13
+ ? node
14
+ : composedParentElement(node);
15
+ while (current) {
16
+ const lang = current.getAttribute("lang")?.trim();
17
+ if (lang)
18
+ return lang;
19
+ if (boundary && current === boundary)
20
+ return undefined;
21
+ current = composedParentElement(current);
22
+ }
23
+ return undefined;
24
+ };
25
+ /**
26
+ * The language the content at `target` is named as being in: the nearest `lang`
27
+ * between it and its shell scope host, else the host's `content-language` input.
28
+ * Undefined when neither names one.
29
+ *
30
+ * The climb stops at the shell because the page's own `lang` above it is the
31
+ * interface language, which the toolkit's `locale` carries; content language is
32
+ * the content's. Resolved at speak time, since a reading target's markup can
33
+ * change between reads.
34
+ */
35
+ export const findContentLanguage = (target, options = {}) => {
36
+ const boundary = options.boundary !== undefined
37
+ ? options.boundary
38
+ : findShellScopeHost(target);
39
+ const fromMarkup = boundary ? findLangAttribute(target, boundary) : undefined;
40
+ return fromMarkup || options.contentLanguage?.trim() || undefined;
41
+ };
42
+ /**
43
+ * {@link findContentLanguage}, else `en-US`: the language text processing and
44
+ * catalog lookup read.
45
+ */
46
+ export const resolveContentLanguage = (target, options = {}) => findContentLanguage(target, options) ?? DEFAULT_CONTENT_LANGUAGE;
@@ -0,0 +1,17 @@
1
+ /** Marks the part of a shell scope that holds the content tools read and annotate. */
2
+ export declare const CONTENT_REGION_SELECTOR = "[data-region='content']";
3
+ /** Marks the host of a shell scope (`<pie-item-scope>`, `<pie-passage-shell>`). */
4
+ export declare const SHELL_SCOPE_HOST_SELECTOR = "[data-pie-shell-root]";
5
+ /**
6
+ * The content region of `scope` that tools read and annotate.
7
+ *
8
+ * With `target`, the region holding it: the nearest `data-region="content"`
9
+ * element from `target` up to `scope`, climbing through shadow hosts. Otherwise,
10
+ * or when `target` lies in none, `scope` itself when it is a content region,
11
+ * else its first content region, else `scope`, so a scope that marks no region
12
+ * is read whole. Resolved at each use, because a card renders its regions after
13
+ * its tools connect.
14
+ */
15
+ export declare const resolveContentRegion: (scope: Element, target?: Node | null) => Element;
16
+ /** The nearest shell scope host at or above `node`, climbing through shadow hosts. */
17
+ export declare const findShellScopeHost: (node: Node | null | undefined) => Element | null;
@@ -0,0 +1,29 @@
1
+ import { composedClosest, flatQuerySelector, } from "../services/tts/flat-tree.js";
2
+ /** Marks the part of a shell scope that holds the content tools read and annotate. */
3
+ export const CONTENT_REGION_SELECTOR = "[data-region='content']";
4
+ /** Marks the host of a shell scope (`<pie-item-scope>`, `<pie-passage-shell>`). */
5
+ export const SHELL_SCOPE_HOST_SELECTOR = "[data-pie-shell-root]";
6
+ /**
7
+ * The content region of `scope` that tools read and annotate.
8
+ *
9
+ * With `target`, the region holding it: the nearest `data-region="content"`
10
+ * element from `target` up to `scope`, climbing through shadow hosts. Otherwise,
11
+ * or when `target` lies in none, `scope` itself when it is a content region,
12
+ * else its first content region, else `scope`, so a scope that marks no region
13
+ * is read whole. Resolved at each use, because a card renders its regions after
14
+ * its tools connect.
15
+ */
16
+ export const resolveContentRegion = (scope, target) => {
17
+ if (target) {
18
+ const holding = composedClosest(target, CONTENT_REGION_SELECTOR, scope);
19
+ if (holding)
20
+ return holding;
21
+ }
22
+ if (scope.matches?.(CONTENT_REGION_SELECTOR))
23
+ return scope;
24
+ return (scope.querySelector?.(CONTENT_REGION_SELECTOR) ??
25
+ flatQuerySelector(scope, CONTENT_REGION_SELECTOR) ??
26
+ scope);
27
+ };
28
+ /** The nearest shell scope host at or above `node`, climbing through shadow hosts. */
29
+ export const findShellScopeHost = (node) => node ? composedClosest(node, SHELL_SCOPE_HOST_SELECTOR) : null;
@@ -0,0 +1,13 @@
1
+ import type { ToolkitCoordinatorApi } from "../services/interfaces.js";
2
+ import type { RuntimeRegistrationDetail } from "./registration-events.js";
3
+ /**
4
+ * What a content registration files with the coordinator: the content's
5
+ * accessibility catalogs, and an item's policy settings under its canonical
6
+ * id, the id its item-level toolbar scopes decisions by. Returns the cleanups
7
+ * that withdraw them, for the toolkit to run when the content unregisters or
8
+ * the coordinator changes.
9
+ */
10
+ export declare function registerContentWithCoordinator(coordinator: Pick<ToolkitCoordinatorApi, "catalogResolver" | "registerItemSettings">, detail: RuntimeRegistrationDetail, owner: {
11
+ assessmentId: string;
12
+ sectionId: string;
13
+ }): Array<() => void>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * What a content registration files with the coordinator: the content's
3
+ * accessibility catalogs, and an item's policy settings under its canonical
4
+ * id, the id its item-level toolbar scopes decisions by. Returns the cleanups
5
+ * that withdraw them, for the toolkit to run when the content unregisters or
6
+ * the coordinator changes.
7
+ */
8
+ export function registerContentWithCoordinator(coordinator, detail, owner) {
9
+ const cleanups = [
10
+ coordinator.catalogResolver.registerOwner({
11
+ owner: {
12
+ kind: detail.kind,
13
+ itemId: detail.itemId,
14
+ canonicalItemId: detail.canonicalItemId,
15
+ assessmentId: owner.assessmentId,
16
+ sectionId: owner.sectionId,
17
+ },
18
+ entity: detail.item,
19
+ }),
20
+ ];
21
+ if (detail.kind === "item" && detail.settings) {
22
+ cleanups.push(coordinator.registerItemSettings(detail.canonicalItemId || detail.itemId, detail.settings));
23
+ }
24
+ return cleanups;
25
+ }