@pie-players/pie-assessment-toolkit 0.3.74 → 1.0.0-beta.0

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 (257) hide show
  1. package/README.md +658 -714
  2. package/custom-elements.json +1315 -0
  3. package/dist/attempt/TestSession.d.ts +1 -21
  4. package/dist/attempt/TestSession.js +16 -102
  5. package/dist/components/ItemScope.custom-element.d.ts +1 -0
  6. package/dist/components/ItemScope.custom-element.js +1 -0
  7. package/dist/components/ItemToolBar.custom-element.js +1 -1
  8. package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
  9. package/dist/components/SectionToolBar.custom-element.js +1 -1
  10. package/dist/components/chunks/ItemToolBar-3zrc4p3d.js +4 -0
  11. package/dist/components/chunks/ItemToolBar-66hcwmfw.js +2 -0
  12. package/dist/components/chunks/ItemToolBar-9gqhfxtn.js +40 -0
  13. package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
  14. package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-kkj69ptr.js} +1 -1
  15. package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
  16. package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
  17. package/dist/components/item-scope-element.d.ts +2 -0
  18. package/dist/components/item-scope-element.js +2 -0
  19. package/dist/context/assessment-toolkit-context.d.ts +33 -6
  20. package/dist/index.d.ts +25 -50
  21. package/dist/index.js +15 -45
  22. package/dist/policy/core/PolicySource.d.ts +2 -2
  23. package/dist/policy/core/ToolPolicyEngine.d.ts +118 -34
  24. package/dist/policy/core/ToolPolicyEngine.js +203 -56
  25. package/dist/policy/core/compose-decision.d.ts +28 -7
  26. package/dist/policy/core/compose-decision.js +95 -74
  27. package/dist/policy/core/decision-types.d.ts +98 -55
  28. package/dist/policy/core/feature-decision.d.ts +28 -19
  29. package/dist/policy/core/feature-decision.js +15 -11
  30. package/dist/policy/core/pnp-policy-inputs.d.ts +29 -35
  31. package/dist/policy/core/pnp-policy-inputs.js +40 -88
  32. package/dist/policy/core/provenance.d.ts +10 -5
  33. package/dist/policy/core/provenance.js +1 -1
  34. package/dist/policy/core/tool-parameters.d.ts +11 -0
  35. package/dist/policy/core/tool-parameters.js +15 -0
  36. package/dist/policy/engine.d.ts +7 -23
  37. package/dist/policy/engine.js +5 -20
  38. package/dist/policy/sources/PnpPolicySource.d.ts +43 -68
  39. package/dist/policy/sources/PnpPolicySource.js +133 -132
  40. package/dist/runtime/SectionControllerBinding.d.ts +283 -0
  41. package/dist/runtime/SectionControllerBinding.js +456 -0
  42. package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
  43. package/dist/runtime/SectionRuntimeEngine.js +30 -372
  44. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
  45. package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
  46. package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
  47. package/dist/runtime/adapter/dom-event-bridge.js +17 -44
  48. package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -3
  49. package/dist/runtime/adapter/subscriber-fanout.js +2 -6
  50. package/dist/runtime/catalog-context.d.ts +19 -0
  51. package/dist/runtime/catalog-context.js +28 -0
  52. package/dist/runtime/composition-emit-scheduler.d.ts +12 -18
  53. package/dist/runtime/composition-emit-scheduler.js +10 -16
  54. package/dist/runtime/content-language.d.ts +32 -0
  55. package/dist/runtime/content-language.js +46 -0
  56. package/dist/runtime/content-region.d.ts +13 -0
  57. package/dist/runtime/content-region.js +29 -0
  58. package/dist/runtime/content-registration.d.ts +13 -0
  59. package/dist/runtime/content-registration.js +25 -0
  60. package/dist/runtime/core/SectionEngineCore.d.ts +2 -4
  61. package/dist/runtime/core/SectionEngineCore.js +2 -6
  62. package/dist/runtime/core/cohort.d.ts +1 -6
  63. package/dist/runtime/core/cohort.js +1 -10
  64. package/dist/runtime/core/engine-input.d.ts +18 -30
  65. package/dist/runtime/core/engine-input.js +11 -12
  66. package/dist/runtime/core/engine-output.d.ts +17 -40
  67. package/dist/runtime/core/engine-output.js +9 -21
  68. package/dist/runtime/core/engine-readiness.d.ts +5 -37
  69. package/dist/runtime/core/engine-readiness.js +8 -41
  70. package/dist/runtime/core/engine-resolver.d.ts +46 -74
  71. package/dist/runtime/core/engine-resolver.js +18 -43
  72. package/dist/runtime/core/engine-state.d.ts +28 -36
  73. package/dist/runtime/core/engine-state.js +18 -21
  74. package/dist/runtime/core/engine-transition.d.ts +14 -19
  75. package/dist/runtime/core/engine-transition.js +74 -53
  76. package/dist/runtime/engine.d.ts +16 -19
  77. package/dist/runtime/engine.js +12 -19
  78. package/dist/runtime/page-warnings.d.ts +13 -0
  79. package/dist/runtime/page-warnings.js +22 -0
  80. package/dist/runtime/policy-input-forwarding.d.ts +25 -0
  81. package/dist/runtime/policy-input-forwarding.js +25 -0
  82. package/dist/runtime/registration-events.d.ts +22 -14
  83. package/dist/runtime/runtime-event-claim.d.ts +8 -0
  84. package/dist/runtime/runtime-event-claim.js +15 -0
  85. package/dist/runtime/runtime-id.d.ts +1 -1
  86. package/dist/runtime/runtime-id.js +1 -1
  87. package/dist/runtime/shell-event-bridge.d.ts +45 -0
  88. package/dist/runtime/shell-event-bridge.js +127 -0
  89. package/dist/runtime/shell-registration.d.ts +73 -0
  90. package/dist/runtime/shell-registration.js +95 -0
  91. package/dist/runtime/shell-scope.d.ts +68 -0
  92. package/dist/runtime/shell-scope.js +194 -0
  93. package/dist/runtime/tool-host-contract.d.ts +8 -14
  94. package/dist/runtime/tool-host-contract.js +12 -12
  95. package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
  96. package/dist/runtime/unclaimed-registration-watch.js +23 -0
  97. package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
  98. package/dist/services/AccessibilityCatalogResolver.js +29 -42
  99. package/dist/services/ElementToolStateStore.d.ts +42 -67
  100. package/dist/services/ElementToolStateStore.js +65 -71
  101. package/dist/services/HighlightCoordinator.d.ts +28 -40
  102. package/dist/services/HighlightCoordinator.js +459 -381
  103. package/dist/services/RangeSerializer.d.ts +11 -33
  104. package/dist/services/RangeSerializer.js +88 -59
  105. package/dist/services/SSMLExtractor.d.ts +8 -31
  106. package/dist/services/SSMLExtractor.js +18 -40
  107. package/dist/services/TTSService.d.ts +159 -119
  108. package/dist/services/TTSService.js +937 -822
  109. package/dist/services/ToolCoordinator.d.ts +42 -102
  110. package/dist/services/ToolCoordinator.js +178 -256
  111. package/dist/services/ToolRegistry.d.ts +152 -133
  112. package/dist/services/ToolRegistry.js +192 -178
  113. package/dist/services/ToolkitCoordinator.d.ts +233 -237
  114. package/dist/services/ToolkitCoordinator.js +615 -557
  115. package/dist/services/audio-handoff.d.ts +6 -7
  116. package/dist/services/audio-handoff.js +20 -14
  117. package/dist/services/catalog-owner.d.ts +0 -1
  118. package/dist/services/framework-error-bus.d.ts +3 -6
  119. package/dist/services/framework-error-bus.js +3 -6
  120. package/dist/services/framework-error.d.ts +51 -13
  121. package/dist/services/framework-error.js +19 -20
  122. package/dist/services/interfaces.d.ts +189 -184
  123. package/dist/services/section-controller-types.d.ts +7 -7
  124. package/dist/services/section-session-assignment.d.ts +21 -0
  125. package/dist/services/section-session-assignment.js +80 -0
  126. package/dist/services/spoken-audio-cards.d.ts +2 -6
  127. package/dist/services/spoken-audio-cards.js +2 -6
  128. package/dist/services/tool-config-defaults.d.ts +3 -3
  129. package/dist/services/tool-config-defaults.js +3 -3
  130. package/dist/services/tool-config-validation.d.ts +9 -12
  131. package/dist/services/tool-config-validation.js +47 -87
  132. package/dist/services/tool-context.d.ts +7 -31
  133. package/dist/services/tool-context.js +99 -65
  134. package/dist/services/tool-failure.d.ts +30 -0
  135. package/dist/services/tool-failure.js +11 -0
  136. package/dist/services/tool-icons.d.ts +5 -5
  137. package/dist/services/tool-icons.js +6 -5
  138. package/dist/services/tool-instance-id.d.ts +8 -7
  139. package/dist/services/tool-instance-id.js +12 -24
  140. package/dist/services/tool-providers/TTSToolProvider.d.ts +20 -58
  141. package/dist/services/tool-providers/TTSToolProvider.js +32 -85
  142. package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -11
  143. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +29 -60
  144. package/dist/services/tool-providers/ToolProviderRegistry.js +128 -144
  145. package/dist/services/tool-request.d.ts +31 -12
  146. package/dist/services/tool-request.js +31 -16
  147. package/dist/services/toolbar-decided-tools.d.ts +16 -0
  148. package/dist/services/toolbar-decided-tools.js +29 -0
  149. package/dist/services/toolbar-items.js +2 -5
  150. package/dist/services/tools-config-normalizer.d.ts +33 -29
  151. package/dist/services/tools-config-normalizer.js +26 -28
  152. package/dist/services/tts/browser-provider.d.ts +39 -6
  153. package/dist/services/tts/browser-provider.js +280 -160
  154. package/dist/services/tts/catalog-span-alignment.js +14 -7
  155. package/dist/services/tts/flat-tree.d.ts +64 -0
  156. package/dist/services/tts/flat-tree.js +269 -0
  157. package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
  158. package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
  159. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
  160. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
  161. package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
  162. package/dist/services/tts/generated-speech/index.d.ts +1 -1
  163. package/dist/services/tts/generated-speech/index.js +1 -1
  164. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
  165. package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
  166. package/dist/services/tts/generated-speech/types.d.ts +1 -1
  167. package/dist/services/tts/generated-speech/types.js +1 -1
  168. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +22 -16
  169. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
  170. package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
  171. package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
  172. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
  173. package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
  174. package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
  175. package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
  176. package/dist/services/tts/math-aware-text-processing.js +42 -47
  177. package/dist/services/tts/math-control-names.d.ts +21 -0
  178. package/dist/services/tts/math-control-names.js +142 -0
  179. package/dist/services/tts/math-speech.d.ts +12 -1
  180. package/dist/services/tts/math-speech.js +54 -18
  181. package/dist/services/tts/mathml-sanitization.d.ts +7 -0
  182. package/dist/services/tts/mathml-sanitization.js +9 -1
  183. package/dist/services/tts/provider-options.d.ts +52 -0
  184. package/dist/services/tts/provider-options.js +1 -0
  185. package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
  186. package/dist/services/tts/ssml/spoken-text.js +29 -0
  187. package/dist/services/tts/start-failure.d.ts +4 -0
  188. package/dist/services/tts/start-failure.js +19 -0
  189. package/dist/services/tts/text-processing.d.ts +9 -0
  190. package/dist/services/tts/text-processing.js +46 -33
  191. package/dist/services/tts/text-segmentation.d.ts +12 -0
  192. package/dist/services/tts/text-segmentation.js +60 -10
  193. package/dist/services/tts-runtime-config.d.ts +54 -26
  194. package/dist/services/tts-runtime-config.js +27 -112
  195. package/dist/tools/content-capability-resolution.d.ts +9 -11
  196. package/dist/tools/content-capability-resolution.js +8 -45
  197. package/dist/tools/registration.d.ts +59 -0
  198. package/dist/tools/registration.js +55 -0
  199. package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
  200. package/dist/tools/registrations/toolbar-registration-helpers.js +8 -2
  201. package/dist/tools/tool-surface-host.d.ts +6 -10
  202. package/dist/tools/tool-surface-host.js +45 -50
  203. package/dist/tools/tool-tag-map.d.ts +5 -15
  204. package/dist/tools/tool-tag-map.js +6 -20
  205. package/dist/utils/structural-equality.d.ts +11 -0
  206. package/dist/utils/structural-equality.js +47 -0
  207. package/package.json +15 -29
  208. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
  209. package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
  210. package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +0 -40
  211. package/dist/components/chunks/ItemToolBar-h4xap0t0.js +0 -4
  212. package/dist/components/chunks/ItemToolBar-wr2myaah.js +0 -2
  213. package/dist/components/chunks/sre-engine-wf9s43gg.js +0 -1
  214. package/dist/context/runtime-context-consumer.d.ts +0 -13
  215. package/dist/context/runtime-context-consumer.js +0 -18
  216. package/dist/item-loader.d.ts +0 -44
  217. package/dist/item-loader.js +0 -61
  218. package/dist/policy/core/engine-context.d.ts +0 -29
  219. package/dist/policy/core/engine-context.js +0 -27
  220. package/dist/policy/core/policy-source-tag.d.ts +0 -31
  221. package/dist/policy/core/policy-source-tag.js +0 -28
  222. package/dist/policy/internal.d.ts +0 -25
  223. package/dist/policy/internal.js +0 -25
  224. package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
  225. package/dist/runtime/adapter/coordinator-bridge.js +0 -126
  226. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
  227. package/dist/runtime/adapter/framework-error-bridge.js +0 -46
  228. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
  229. package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
  230. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
  231. package/dist/runtime/core/engine-stage-derivation.js +0 -29
  232. package/dist/runtime/engine-context.d.ts +0 -39
  233. package/dist/runtime/engine-context.js +0 -31
  234. package/dist/runtime/internal.d.ts +0 -43
  235. package/dist/runtime/internal.js +0 -45
  236. package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -74
  237. package/dist/runtime/section-runtime-engine-host-context.js +0 -57
  238. package/dist/runtime/stage-emit-gate.d.ts +0 -92
  239. package/dist/runtime/stage-emit-gate.js +0 -82
  240. package/dist/services/ContextVariableStore.d.ts +0 -113
  241. package/dist/services/ContextVariableStore.js +0 -206
  242. package/dist/services/I18nService.d.ts +0 -47
  243. package/dist/services/I18nService.js +0 -84
  244. package/dist/services/ThemeProvider.d.ts +0 -95
  245. package/dist/services/ThemeProvider.js +0 -334
  246. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
  247. package/dist/services/defaultPersonalNeedsProfile.js +0 -26
  248. package/dist/services/pnp-standard-features.d.ts +0 -238
  249. package/dist/services/pnp-standard-features.js +0 -338
  250. package/dist/services/tts-control-events.d.ts +0 -13
  251. package/dist/services/tts-control-events.js +0 -7
  252. package/dist/tools/client.d.ts +0 -10
  253. package/dist/tools/client.js +0 -10
  254. package/dist/tools/internal.d.ts +0 -44
  255. package/dist/tools/internal.js +0 -39
  256. package/dist/utils/logger.d.ts +0 -6
  257. package/dist/utils/logger.js +0 -10
@@ -1,112 +1,52 @@
1
1
  /**
2
- * Section runtime engine — public facade (M7 — Variant C, layered).
2
+ * Section runtime engine — the section player's stage chain.
3
3
  *
4
- * The facade is the narrow, stable entry point hosts use to mount,
5
- * drive, and dispose a section runtime. It composes three layers
6
- * introduced in earlier M7 PRs:
4
+ * The section player's layout kernel owns one per layout element and drives it
5
+ * with `dispatchInput`: the cohort it shows (`initialize`, `cohort-change`,
6
+ * `update-runtime`), the controller resolving (`section-controller-resolved`),
7
+ * and the readiness signals it derives (`update-readiness-signals`). The pure
8
+ * FSM core turns those into `pie-stage-change` and `pie-loading-complete`,
9
+ * which the adapter dispatches on the layout element, bubbling and composed;
10
+ * `subscribe` receives the same outputs in batches.
7
11
  *
8
- * - the **registry** (`RuntimeRegistry`) — registered item/passage
9
- * shells in document order, used for canonical-id lookup;
10
- * - the **adapter** (`SectionEngineAdapter`) — single I/O seam over
11
- * the pure FSM core, fanning outputs to the DOM, framework-error
12
- * bus, instrumentation hook, and host subscribers;
13
- * - the **resolver** (`resolveSectionEngineRuntimeState`) — the
14
- * toolkit-side resolution helper that produces the effective
15
- * runtime + tools snapshot a host feeds to the FSM core.
12
+ * The engine is the only stage emitter. It holds no controller and no
13
+ * registry: the toolkit's `SectionControllerBinding` owns those. The kernel
14
+ * learns that the controller resolved from the toolkit's `section-ready`, whose
15
+ * detail carries the controller and its cohort.
16
16
  *
17
- * The facade exposes an engine-side surface for stage/lifecycle inputs and a
18
- * controller-facing surface for item registration, session updates, and host
19
- * controller commands:
20
- *
21
- * 1. The **engine-side** surface (`attachHost`, `dispatchInput`,
22
- * `subscribe`, `getState`, `getEffectiveRuntime`,
23
- * `setInstrumentationHook`). This is what the kernel and the
24
- * `pie-assessment-toolkit` CE will switch onto in M7 PR 5 and
25
- * PR 6. Construction is lazy: `attachHost(...)` builds the
26
- * adapter on first call, with the supplied host element,
27
- * framework-error bus, and (optional) coordinator. After
28
- * construction, host re-attachments (e.g. cohort change with a
29
- * new layout shell) update the adapter's host element via
30
- * `setHost(...)`.
31
- *
32
- * 2. The **controller-side** surface (`initialize`,
33
- * `register`, `unregister`, `handleContent*`, `updateItemSession`,
34
- * `navigateToItem`, `persist`, `hydrate`, `dispose`). The
35
- * `PieAssessmentToolkit.svelte` CE drives section-controller and
36
- * item-shell events through this surface.
37
- *
38
- * The two surfaces share `RuntimeRegistry` and the resolved
39
- * `SectionControllerHandle`.
17
+ * `attachHost(...)` builds the adapter on first call; a later call moves it to
18
+ * a new host element.
40
19
  */
41
- import { SectionEngineAdapter, } from "./adapter/SectionEngineAdapter.js";
42
- import { resolveSectionEngineRuntimeState, } from "./core/engine-resolver.js";
20
+ import { SectionEngineAdapter } from "./adapter/SectionEngineAdapter.js";
43
21
  import { createInitialEngineState, } from "./core/engine-state.js";
44
- import { createPieLogger, isGlobalDebugEnabled, } from "@pie-players/pie-players-shared";
45
- import { RuntimeRegistry } from "./RuntimeRegistry.js";
46
22
  import { createRuntimeId } from "./runtime-id.js";
47
- const logger = createPieLogger("section-runtime-engine", () => isGlobalDebugEnabled());
48
23
  export class SectionRuntimeEngine {
49
- registry = new RuntimeRegistry();
50
24
  runtimeId = createRuntimeId("section-engine");
51
- // Engine-side state (PR 3+).
52
25
  adapter = null;
53
- // Controller-side state.
54
- controller = null;
55
- coordinator = null;
56
- sectionId = "";
57
- attemptId;
58
- unsubscribeController = null;
59
- activeInitToken = 0;
60
- /**
61
- * Tracks which `(canonicalItemId, contentKind)` pairs have already
62
- * fired `handleContentLoaded` on this engine. Mirrored alongside
63
- * `RuntimeRegistry`'s registered set so a cohort handoff can
64
- * replay the persistent shells' loaded state into the new
65
- * controller — see `replayRegisteredShellsIntoController` and the
66
- * PIE-512 Phase B regression test.
67
- *
68
- * Cleared in lockstep with `handleContentUnregistered` and on
69
- * `dispose`. Not exposed publicly: the registry alone is the
70
- * external surface; the loaded set exists only to seed cohort B's
71
- * controller with the live state cohort A's shells produced.
72
- */
73
- loadedRenderableKeys = new Set();
74
- // ============================================================
75
- // Engine-side surface (PR 3+; driven by the kernel from PR 5,
76
- // by the toolkit CE from PR 6, and by the facade smoke test today).
77
- // ============================================================
78
26
  /**
79
- * Attach the host element + framework-error bus + sourceCe so the
80
- * adapter can dispatch DOM events and bus errors. Required before
81
- * `dispatchInput` / `subscribe` produce observable effects.
27
+ * Attach the host element and `sourceCe` the adapter dispatches DOM events
28
+ * with. Required before `dispatchInput` / `subscribe` produce observable
29
+ * effects.
82
30
  *
83
- * Constructs the adapter on the first call. Subsequent calls keep
84
- * the adapter and update its host element / instrumentation hook
85
- * (used by layout-shell rollovers and instrumentation reconfig).
31
+ * Constructs the adapter on the first call. Subsequent calls keep the
32
+ * adapter and update its host element.
86
33
  */
87
34
  attachHost(args) {
88
35
  if (this.adapter) {
89
36
  this.adapter.setHost(args.host);
90
- if (args.instrumentationHook !== undefined) {
91
- this.adapter.setInstrumentationHook(args.instrumentationHook);
92
- }
93
37
  return;
94
38
  }
95
39
  this.adapter = new SectionEngineAdapter({
96
40
  host: args.host,
97
41
  runtimeId: this.runtimeId,
98
42
  sourceCe: args.sourceCe,
99
- frameworkErrorBus: args.frameworkErrorBus,
100
- coordinator: args.coordinator,
101
- instrumentationHook: args.instrumentationHook,
102
43
  now: args.now,
103
44
  });
104
45
  }
105
46
  /**
106
47
  * Forward a host-constructed input to the FSM core via the adapter.
107
48
  * Returns the outputs the transition produced (subscribers and the
108
- * DOM/framework-error/instrumentation bridges have already
109
- * received them).
49
+ * DOM bridge have already received them).
110
50
  *
111
51
  * No-op (returns `[]`) before `attachHost(...)` so callers that
112
52
  * dispatch optimistically during teardown do not throw.
@@ -132,304 +72,22 @@ export class SectionRuntimeEngine {
132
72
  return this.adapter?.getState() ?? createInitialEngineState();
133
73
  }
134
74
  /**
135
- * Resolve the effective runtime + tools snapshot for the given
136
- * two-tier inputs. This is a pure function over the resolver — it
137
- * does not depend on adapter state — so callers can use it both
138
- * pre- and post-`attachHost`. The kernel uses it to seed
139
- * `dispatchInput({ kind: "initialize", effectiveRuntime, ... })`.
140
- */
141
- getEffectiveRuntime(args, deps) {
142
- return resolveSectionEngineRuntimeState(args, deps).effectiveRuntime;
143
- }
144
- /**
145
- * Update the adapter's instrumentation hook. No-op pre-attach.
146
- * Hosts that always want a hook should pass it via `attachHost`.
147
- */
148
- setInstrumentationHook(hook) {
149
- this.adapter?.setInstrumentationHook(hook);
150
- }
151
- /**
152
- * Stable per-engine runtime id used to scope DOM-event details and
153
- * registry telemetry. Exposed so tests and instrumentation can pin
154
- * the value the bridges emit.
75
+ * Stable per-engine runtime id, the `runtimeId` of every event detail the
76
+ * engine dispatches.
155
77
  */
156
78
  getRuntimeId() {
157
79
  return this.runtimeId;
158
80
  }
159
- // ============================================================
160
- // Controller-side surface.
161
- // ============================================================
162
- async initialize(args) {
163
- this.activeInitToken += 1;
164
- const token = this.activeInitToken;
165
- this.coordinator = args.coordinator;
166
- this.sectionId = args.sectionId;
167
- this.attemptId = args.attemptId;
168
- const resolved = (await args.coordinator.getOrCreateSectionController({
169
- sectionId: args.sectionId,
170
- attemptId: args.attemptId,
171
- input: {
172
- section: args.section,
173
- sectionId: args.sectionId,
174
- assessmentId: args.assessmentId,
175
- view: args.view,
176
- },
177
- updateExisting: true,
178
- createDefaultController: args.createDefaultController,
179
- }));
180
- if (token !== this.activeInitToken)
181
- return;
182
- this.unsubscribeController?.();
183
- this.controller = resolved;
184
- // PIE-512 Phase C: always re-feed the registry's currently
185
- // registered shells (and their loaded state) into the resolved
186
- // controller. We do NOT gate on `resolved !== previousController`
187
- // any more.
188
- //
189
- // Why the gate had to go:
190
- // - Cohort flip resolving to a fresh controller — replay seeds
191
- // the new controller, which is the original Phase B fix.
192
- // - Same-cohort `updateInput` resolving to the existing
193
- // controller — the coordinator's
194
- // `resolveExistingSectionController` calls
195
- // `existingController.updateInput(input)` (engine always
196
- // passes `updateExisting: true`), and pre-Phase-C
197
- // `SectionController.initialize` wiped lifecycle tracking
198
- // unconditionally. A subscriber attaching between the wipe
199
- // and the next live event saw an empty
200
- // `loadedRenderables` snapshot.
201
- //
202
- // Phase C makes this re-feed safe by combining (a) the
203
- // section-identity gate around `resetLifecycleTracking()` in
204
- // `SectionController.initialize` (so same-cohort `updateInput`
205
- // preserves tracking) with (b) idempotent
206
- // `handleContentRegistered` / `handleContentLoaded` on the
207
- // controller (so re-feeding the same registry entries is a
208
- // no-op if the controller already knows about them, but
209
- // re-seeds the controller in the post-`updateInput`-wipe case
210
- // that pre-Phase-C used to encounter).
211
- this.replayRegisteredShellsIntoController(resolved);
212
- args.onCompositionChanged?.(resolved.getCompositionModel?.());
213
- this.unsubscribeController =
214
- resolved.subscribe?.((event) => {
215
- // Isolated deliberately: the controller's emit loop catches per
216
- // listener, so a diagnostic handler that throws would take the
217
- // composition republish down with it and every cue and Try would stop
218
- // reaching the cards — a failure with no symptom except a warning.
219
- try {
220
- args.onControllerEvent?.(event);
221
- }
222
- catch (error) {
223
- logger.warn("onControllerEvent handler threw", error);
224
- }
225
- args.onCompositionChanged?.(resolved.getCompositionModel?.());
226
- }) || null;
227
- }
228
- /**
229
- * Re-feed the engine's `RuntimeRegistry` and loaded-set into the
230
- * resolved controller. Call site: `initialize(...)` — runs on
231
- * EVERY initialize, both cohort-flip-resolves-fresh-controller
232
- * and same-cohort-resolves-existing-controller cases. Phase C
233
- * dropped the `resolved !== previousController` gate; see the
234
- * comment at the call site for why.
235
- *
236
- * Two-pass order — register every shell in document order, then
237
- * issue `handleContentLoaded` for each shell whose load already
238
- * fired on this engine. The two-pass shape prevents
239
- * `evaluateSectionLoadingState` from flapping
240
- * `section-loading-complete` `false→true→false→…` while replay is
241
- * mid-walk: any subscriber wired before the engine's own
242
- * `controller.subscribe` (no such caller today, but cheap defense
243
- * for future wiring) sees one clean `false→true` transition.
244
- *
245
- * Idempotent on the controller side — Phase C makes
246
- * `SectionController.handleContentRegistered` and
247
- * `handleContentLoaded` early-return on duplicates so re-feeding
248
- * the same shells into a controller that already tracks them is
249
- * a true no-op (no spurious re-emits, no re-evaluation of
250
- * `section-loading-complete`). At the call site no listener is
251
- * attached during the replay window, so `emitChange` side effects
252
- * fire into a void on this pass anyway, but the controller-side
253
- * idempotence is what makes the replay safe to run on every
254
- * initialize regardless of whether the controller is fresh.
255
- */
256
- replayRegisteredShellsIntoController(controller) {
257
- if (!controller.handleContentRegistered)
258
- return;
259
- const shells = this.registry.getOrderedShells();
260
- if (shells.length === 0)
261
- return;
262
- for (const shell of shells) {
263
- const canonicalItemId = shell.canonicalItemId || shell.itemId;
264
- controller.handleContentRegistered({
265
- itemId: shell.itemId,
266
- canonicalItemId,
267
- contentKind: shell.contentKind || shell.kind,
268
- });
269
- }
270
- const now = Date.now();
271
- for (const shell of shells) {
272
- const canonicalItemId = shell.canonicalItemId || shell.itemId;
273
- const key = this.getLoadedKey(canonicalItemId, shell.contentKind);
274
- if (this.loadedRenderableKeys.has(key)) {
275
- controller.handleContentLoaded?.({
276
- itemId: shell.itemId,
277
- canonicalItemId,
278
- contentKind: shell.contentKind || shell.kind,
279
- timestamp: now,
280
- });
281
- }
282
- }
283
- }
284
- /**
285
- * Stable key for the engine's `loadedRenderableKeys` set. Mirrors
286
- * the `(canonicalItemId, contentKind)` shape `SectionController`
287
- * uses internally (see `getRenderableKey`); we only need
288
- * consistent add/check semantics on this side, not byte-identical
289
- * normalization with the controller.
290
- */
291
- getLoadedKey(canonicalItemId, contentKind) {
292
- return `${contentKind ?? ""}:${canonicalItemId}`;
293
- }
294
- register(detail) {
295
- return this.registry.register(detail);
296
- }
297
- unregister(element) {
298
- return this.registry.unregister(element);
299
- }
300
- getCompositionModel() {
301
- return this.controller?.getCompositionModel?.() ?? null;
302
- }
303
- getCanonicalItemId(itemId) {
304
- const map = this.registry.getCanonicalIdMap();
305
- return (map[itemId] || this.controller?.getCanonicalItemId?.(itemId) || itemId);
306
- }
307
- handleContentRegistered(detail) {
308
- this.controller?.handleContentRegistered?.({
309
- itemId: detail.itemId,
310
- canonicalItemId: detail.canonicalItemId || detail.itemId,
311
- contentKind: detail.contentKind || detail.kind,
312
- });
313
- }
314
- handleContentUnregistered(detail) {
315
- const canonicalItemId = detail.canonicalItemId || detail.itemId;
316
- // Key the load-set delete with the same `contentKind`-only
317
- // shape that `handleContentLoaded` and
318
- // `replayRegisteredShellsIntoController` use, so add/check/
319
- // delete keys round-trip identically. The `|| detail.kind`
320
- // fallback is preserved for the controller-forwarded payload
321
- // because the controller normalizes via `toSectionContentKind`
322
- // and the `kind` field remains meaningful there.
323
- this.loadedRenderableKeys.delete(this.getLoadedKey(canonicalItemId, detail.contentKind));
324
- this.controller?.handleContentUnregistered?.({
325
- itemId: detail.itemId,
326
- canonicalItemId,
327
- contentKind: detail.contentKind || detail.kind,
328
- });
329
- }
330
- handleContentLoaded(args) {
331
- const canonicalItemId = args.canonicalItemId || args.itemId;
332
- this.loadedRenderableKeys.add(this.getLoadedKey(canonicalItemId, args.contentKind));
333
- this.controller?.handleContentLoaded?.(args);
334
- }
335
- handleItemPlayerError(args) {
336
- this.controller?.handleItemPlayerError?.(args);
337
- }
338
- reportSectionError(args) {
339
- this.controller?.reportSectionError?.(args);
340
- }
341
- updateItemSession(itemId, session) {
342
- const canonicalId = this.getCanonicalItemId(itemId);
343
- return this.controller?.updateItemSession?.(canonicalId, session) ?? null;
344
- }
345
- navigateToItem(index) {
346
- return this.controller?.navigateToItem?.(index) ?? null;
347
- }
348
81
  /**
349
- * Route a learner's formative action to the controller.
350
- *
351
- * Canonicalized here for the same reason `updateItemSession` is: the runtime
352
- * id a card dispatches with is not necessarily the identifier the controller
353
- * keys state by.
82
+ * Emit `disposed` for the active cohort and detach. Idempotent; inputs
83
+ * after it are ignored.
354
84
  */
355
- handleFormativeAction(action) {
356
- if (!action?.itemId)
357
- return;
358
- const canonicalId = this.getCanonicalItemId(action.itemId);
359
- if (action.action === "retry") {
360
- this.controller?.retryFormativeItem?.({ itemId: canonicalId });
85
+ dispose() {
86
+ const adapter = this.adapter;
87
+ if (!adapter)
361
88
  return;
362
- }
363
- this.controller?.recordFormativeTry?.({
364
- itemId: canonicalId,
365
- outcomes: action.outcomes,
366
- });
367
- }
368
- /**
369
- * Bind or release the section's Media Time Source.
370
- *
371
- * A pass-through, like `handleFormativeAction`: the engine routes, the
372
- * controller decides. `renderableId` travels with the attach because whether the
373
- * registering renderable is the one `stimulusRef` names is the controller's call
374
- * — it validated `stimulusRef` in the first place.
375
- */
376
- handleMediaTimeSource(action) {
377
- if (action?.action === "detach") {
378
- this.controller?.detachMediaTimeSource?.({
379
- origin: action.origin ?? "host",
380
- });
381
- return;
382
- }
383
- if (!action?.source)
384
- return;
385
- this.controller?.attachMediaTimeSource?.(action.source, {
386
- origin: action.origin ?? "host",
387
- renderableId: action.renderableId,
388
- });
389
- }
390
- /**
391
- * Silence media audio because something else is about to speak.
392
- *
393
- * A pass-through like `handleMediaTimeSource`, and for the same reason: which
394
- * source is authoritative and whether it reports `canPause` are the controller's
395
- * to know. Returns whether media audio is now silent, or `true` where there is
396
- * no timed-media controller to ask — nothing is playing.
397
- */
398
- requestMediaPauseForCompetingAudio() {
399
- return this.controller?.pauseMediaForCompetingAudio?.() ?? true;
400
- }
401
- async persist() {
402
- await this.controller?.persist?.();
403
- }
404
- async hydrate() {
405
- await this.controller?.hydrate?.();
406
- }
407
- getRegistry() {
408
- return this.registry;
409
- }
410
- async dispose() {
411
- this.activeInitToken += 1;
412
- this.unsubscribeController?.();
413
- this.unsubscribeController = null;
414
- if (this.coordinator && this.sectionId) {
415
- await this.coordinator.disposeSectionController({
416
- sectionId: this.sectionId,
417
- attemptId: this.attemptId,
418
- });
419
- }
420
- this.registry.clear();
421
- this.loadedRenderableKeys.clear();
422
- this.controller = null;
423
- this.coordinator = null;
424
- // Tear down the engine-side adapter (if attached) last so any
425
- // `dispose` FSM input flows through the bridges before they
426
- // detach. Adapter disposal is idempotent and safe even when
427
- // nothing is attached.
428
- if (this.adapter) {
429
- const adapter = this.adapter;
430
- this.adapter = null;
431
- await adapter.dispose();
432
- }
89
+ this.adapter = null;
90
+ adapter.dispose();
433
91
  }
434
92
  }
435
93
  const noopDispose = () => { };
@@ -1,55 +1,30 @@
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
- import type { FrameworkErrorReporter } from "../../services/framework-error-bus.js";
47
24
  import { SectionEngineCore } from "../core/SectionEngineCore.js";
48
25
  import type { SectionEngineInput } from "../core/engine-input.js";
49
26
  import type { SectionEngineOutput } from "../core/engine-output.js";
50
27
  import type { SectionEngineState } from "../core/engine-state.js";
51
- import { type CoordinatorPort, type ResolveSectionControllerArgs } from "./coordinator-bridge.js";
52
- import { type InstrumentationHook } from "./instrumentation-bridge.js";
53
28
  import { type EngineOutputListener } from "./subscriber-fanout.js";
54
29
  export interface SectionEngineAdapterOptions {
55
30
  /** Element on which DOM events are dispatched. */
@@ -60,22 +35,6 @@ export interface SectionEngineAdapterOptions {
60
35
  * Tag name of the host CE without the `--version-<encoded>` suffix.
61
36
  */
62
37
  sourceCe: string;
63
- /**
64
- * Framework-error bus (write side). Shared with the toolkit CE so
65
- * subscribers via `coordinator.subscribeFrameworkErrors` see the
66
- * same fan-out.
67
- */
68
- frameworkErrorBus: FrameworkErrorReporter;
69
- /**
70
- * Optional toolkit coordinator. When supplied, the adapter wires
71
- * its framework-error subscription, controller resolution, and
72
- * disposal through the coordinator-bridge. Standalone callers (no
73
- * coordinator) can omit this and feed `framework-error` and
74
- * `section-controller-resolved` inputs directly.
75
- */
76
- coordinator?: CoordinatorPort;
77
- /** Optional one-shot observability hook. */
78
- instrumentationHook?: InstrumentationHook;
79
38
  /** Clock injection for the DOM bridge. Defaults to `Date.now()`. */
80
39
  now?: () => string;
81
40
  /**
@@ -88,10 +47,7 @@ export interface SectionEngineAdapterOptions {
88
47
  export declare class SectionEngineAdapter {
89
48
  private readonly core;
90
49
  private readonly domEventBridge;
91
- private readonly frameworkErrorBridge;
92
- private readonly instrumentationBridge;
93
50
  private readonly subscriberFanout;
94
- private readonly coordinatorBridge;
95
51
  private readonly unsubscribeCore;
96
52
  private disposed;
97
53
  constructor(options: SectionEngineAdapterOptions);
@@ -116,28 +72,11 @@ export declare class SectionEngineAdapter {
116
72
  */
117
73
  setHost(host: EventTarget): void;
118
74
  /**
119
- * Update the instrumentation hook at runtime.
120
- */
121
- setInstrumentationHook(hook: InstrumentationHook | undefined): void;
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.
129
- */
130
- resolveSectionController(args: ResolveSectionControllerArgs): Promise<void>;
131
- /**
132
- * Tear the adapter down. Safe to call more than once. Disposes the
133
- * coordinator bridge (which in turn disposes the section
134
- * controller for the current cohort), detaches the core
135
- * subscription, and clears subscribers.
136
- *
137
- * Does **not** dispose the framework-error bus — its lifetime is
138
- * owned by the toolkit CE / host.
75
+ * Tear the adapter down. Safe to call more than once. Emits `disposed`
76
+ * for the active cohort, then detaches the core subscription and
77
+ * clears subscribers.
139
78
  */
140
- dispose(): Promise<void>;
79
+ dispose(): void;
141
80
  private routeOutputs;
142
81
  private routeOne;
143
82
  }