@pie-players/pie-assessment-toolkit 0.3.47 → 0.3.49

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 (86) hide show
  1. package/dist/attempt/AssessmentSession.js +2 -1
  2. package/dist/attempt/AssessmentSession.js.map +1 -1
  3. package/dist/attempt/adapters/activity-to-test-attempt-session.js +12 -8
  4. package/dist/attempt/adapters/activity-to-test-attempt-session.js.map +1 -1
  5. package/dist/components/ItemToolBar.custom-element.js +56 -17
  6. package/dist/components/PieAssessmentToolkit.custom-element.js +84 -29
  7. package/dist/components/SectionToolBar.custom-element.js +55 -17
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/policy/core/pnp-policy-inputs.js +1 -2
  11. package/dist/policy/core/pnp-policy-inputs.js.map +1 -1
  12. package/dist/policy/core/provenance.js.map +1 -1
  13. package/dist/runtime/SectionRuntimeEngine.js +1 -1
  14. package/dist/runtime/SectionRuntimeEngine.js.map +1 -1
  15. package/dist/runtime/core/cohort.js.map +1 -1
  16. package/dist/runtime/core/engine-input.js.map +1 -1
  17. package/dist/runtime/core/engine-readiness.js.map +1 -1
  18. package/dist/runtime/core/engine-resolver.js.map +1 -1
  19. package/dist/runtime/core/engine-transition.js +1 -3
  20. package/dist/runtime/core/engine-transition.js.map +1 -1
  21. package/dist/runtime/registration-events.js.map +1 -1
  22. package/dist/runtime/session-event-emitter-policy.js.map +1 -1
  23. package/dist/services/HighlightCoordinator.js +2 -1
  24. package/dist/services/HighlightCoordinator.js.map +1 -1
  25. package/dist/services/I18nService.d.ts +1 -1
  26. package/dist/services/I18nService.js.map +1 -1
  27. package/dist/services/SSMLExtractor.js.map +1 -1
  28. package/dist/services/TTSService.js +5 -2
  29. package/dist/services/TTSService.js.map +1 -1
  30. package/dist/services/ThemeProvider.js.map +1 -1
  31. package/dist/services/ToolRegistry.d.ts +1 -1
  32. package/dist/services/ToolRegistry.js.map +1 -1
  33. package/dist/services/ToolkitCoordinator.js +21 -11
  34. package/dist/services/ToolkitCoordinator.js.map +1 -1
  35. package/dist/services/createDefaultToolRegistry.js +4 -2
  36. package/dist/services/createDefaultToolRegistry.js.map +1 -1
  37. package/dist/services/framework-error-bus.js.map +1 -1
  38. package/dist/services/framework-error.js.map +1 -1
  39. package/dist/services/interfaces.js.map +1 -1
  40. package/dist/services/section-controller-types.js.map +1 -1
  41. package/dist/services/tool-config-defaults.js +7 -1
  42. package/dist/services/tool-config-defaults.js.map +1 -1
  43. package/dist/services/tool-config-validation.js +3 -1
  44. package/dist/services/tool-config-validation.js.map +1 -1
  45. package/dist/services/tool-instance-id.js.map +1 -1
  46. package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -1
  47. package/dist/services/tool-providers/TTSToolProvider.js.map +1 -1
  48. package/dist/services/toolbar-items.js.map +1 -1
  49. package/dist/services/tools-config-normalizer.js +1 -2
  50. package/dist/services/tools-config-normalizer.js.map +1 -1
  51. package/dist/services/tts/browser-provider.js +60 -18
  52. package/dist/services/tts/browser-provider.js.map +1 -1
  53. package/dist/services/tts/catalog-span-alignment.js +8 -3
  54. package/dist/services/tts/catalog-span-alignment.js.map +1 -1
  55. package/dist/services/tts/generated-speech/assemble-plan.js.map +1 -1
  56. package/dist/services/tts/generated-speech/index.d.ts +1 -1
  57. package/dist/services/tts/generated-speech/index.js +1 -1
  58. package/dist/services/tts/generated-speech/index.js.map +1 -1
  59. package/dist/services/tts/generated-speech/math-speech-cache.js +3 -1
  60. package/dist/services/tts/generated-speech/math-speech-cache.js.map +1 -1
  61. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js.map +1 -1
  62. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js.map +1 -1
  63. package/dist/services/tts/math-alignment/mathml-tokenizer.js.map +1 -1
  64. package/dist/services/tts/math-alignment/sequence-aligner.js.map +1 -1
  65. package/dist/services/tts/math-alignment/speech-tokenizer.js.map +1 -1
  66. package/dist/services/tts/math-aware-text-processing.js +6 -3
  67. package/dist/services/tts/math-aware-text-processing.js.map +1 -1
  68. package/dist/services/tts/math-speech.js +3 -1
  69. package/dist/services/tts/math-speech.js.map +1 -1
  70. package/dist/services/tts/visual-line-ranges.js.map +1 -1
  71. package/dist/services/tts-runtime-config.js +6 -2
  72. package/dist/services/tts-runtime-config.js.map +1 -1
  73. package/dist/tools/calculators/desmos-provider.js.map +1 -1
  74. package/dist/tools/default-tool-module-loaders.js.map +1 -1
  75. package/dist/tools/registrations/accessibility-tools.js.map +1 -1
  76. package/dist/tools/registrations/calculator.js +1 -1
  77. package/dist/tools/registrations/calculator.js.map +1 -1
  78. package/dist/tools/registrations/interaction-tools.js.map +1 -1
  79. package/dist/tools/registrations/measurement-tools.js.map +1 -1
  80. package/dist/tools/registrations/subject-specific-tools.js +1 -1
  81. package/dist/tools/registrations/subject-specific-tools.js.map +1 -1
  82. package/dist/tools/registrations/tts.js +4 -2
  83. package/dist/tools/registrations/tts.js.map +1 -1
  84. package/dist/tools/types.js.map +1 -1
  85. package/dist/tools/variant-resolver.js.map +1 -1
  86. package/package.json +7 -7
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PIE Assessment Toolkit\n *\n * Independent, composable services for coordinating tools, accommodations,\n * and item players in assessment applications.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Core Infrastructure\n// ============================================================================\n\nexport type {\n\tAssessmentToolkitHostRuntimeContext,\n\tAssessmentToolkitRegionScopeContext,\n\tAssessmentToolkitRuntimeContext,\n\tAssessmentToolkitShellContext,\n\tItemPlayerConfig,\n\tItemPlayerType,\n\tShellContextKind,\n} from \"./context/assessment-toolkit-context.js\";\nexport {\n\tassessmentToolkitHostRuntimeContext,\n\tassessmentToolkitRegionScopeContext,\n\tassessmentToolkitRuntimeContext,\n\tassessmentToolkitShellContext,\n} from \"./context/assessment-toolkit-context.js\";\nexport {\n\tconnectAssessmentToolkitHostRuntimeContext,\n\tconnectAssessmentToolkitRegionScopeContext,\n\tconnectAssessmentToolkitRuntimeContext,\n\tconnectAssessmentToolkitShellContext,\n} from \"./context/runtime-context-consumer.js\";\nexport {\n\tPIE_INTERNAL_CONTENT_LOADED_EVENT,\n\tPIE_INTERNAL_ITEM_SESSION_CHANGED_EVENT,\n\tPIE_INTERNAL_ITEM_PLAYER_ERROR_EVENT,\n\tPIE_ITEM_SESSION_CHANGED_EVENT,\n\tPIE_REGISTER_EVENT,\n\tPIE_UNREGISTER_EVENT,\n\ttype InternalContentLoadedDetail,\n\ttype InternalItemSessionChangedDetail,\n\ttype InternalItemPlayerErrorDetail,\n\ttype ItemSessionChangedDetail,\n\ttype RuntimeRegistrationDetail,\n\ttype RuntimeRegistrationKind,\n} from \"./runtime/registration-events.js\";\nexport {\n\tconnectToolRegionScopeContext,\n\tconnectToolRuntimeContext,\n\tconnectToolShellContext,\n\tcreateCrossBoundaryEvent,\n\tdispatchCrossBoundaryEvent,\n\tisContextValueDefined,\n} from \"./runtime/tool-host-contract.js\";\n\n// ============================================================================\n// Service Interfaces\n// ============================================================================\n\nexport type {\n\tAccessibilityCatalogResolverApi,\n\tElementToolStateStoreApi,\n\tHighlightCoordinatorApi,\n\tI18nServiceApi,\n\tThemeProviderApi,\n\tToolCoordinatorApi,\n\tToolkitCoordinatorApi,\n\tTtsServiceApi,\n\tToolState,\n} from \"./services/interfaces.js\";\n\n// ============================================================================\n// Toolkit Services\n// ============================================================================\n\n// Accessibility Catalog Resolver (QTI 3.0 Accessibility Catalogs)\nexport type {\n\tCatalogLookupContext,\n\tCatalogLookupOptions,\n\tCatalogOwnerContext,\n\tCatalogOwnerKind,\n\tCatalogStatistics,\n\tCatalogType,\n\tResolvedCatalog,\n} from \"./services/AccessibilityCatalogResolver.js\";\nexport { AccessibilityCatalogResolver } from \"./services/AccessibilityCatalogResolver.js\";\n// Context Variable Store (QTI 3.0 Context Declarations)\nexport { ContextVariableStore } from \"./services/ContextVariableStore.js\";\n// Element Tool State Store (Element-level ephemeral tool state)\nexport { ElementToolStateStore } from \"./services/ElementToolStateStore.js\";\n// Highlight Coordinator\nexport type { Annotation } from \"./services/HighlightCoordinator.js\";\nexport {\n\tHighlightColor,\n\tHighlightCoordinator,\n\tHighlightType,\n} from \"./services/HighlightCoordinator.js\";\n// Range Serializer (for annotation persistence)\nexport type { SerializedRange } from \"./services/RangeSerializer.js\";\nexport { RangeSerializer } from \"./services/RangeSerializer.js\";\n// I18n Service\nexport type {\n\tI18nConfig,\n\tPluralTranslation,\n\tTranslationBundle,\n} from \"./services/I18nService.js\";\nexport { I18nService } from \"./services/I18nService.js\";\n// Tool Registry (Registry-based tool system)\nexport type {\n\tResolvedToolContext,\n\tToolbarContext,\n\tToolContextResolver,\n\tToolContextResolverContext,\n\tToolContextResolverMap,\n\tToolContextResolverResult,\n\tToolModuleLoader,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolRegistration,\n} from \"./services/ToolRegistry.js\";\nexport { ToolRegistry } from \"./services/ToolRegistry.js\";\nexport type {\n\tAssessmentToolContext,\n\tBaseToolContext,\n\tElementToolContext,\n\tItemToolContext,\n\tPassageToolContext,\n\tRubricToolContext,\n\tSectionToolContext,\n\tToolContext,\n\tToolLevel,\n} from \"./services/tool-context.js\";\nexport {\n\textractTextContent,\n\thasChoiceInteraction,\n\thasMathContent,\n\thasReadableText,\n\tisAssessmentContext,\n\tisElementContext,\n\tisItemContext,\n\tisPassageContext,\n\tisRubricContext,\n\tisSectionContext,\n} from \"./services/tool-context.js\";\nexport {\n\tDEFAULT_TOOL_PLACEMENT,\n\tDEFAULT_TOOL_ORDER,\n\tcreatePackagedToolRegistry,\n\tPACKAGED_TOOL_PLACEMENT,\n\tregisterPackagedTools,\n} from \"./services/createDefaultToolRegistry.js\";\nexport type { CreateToolsConfigArgs } from \"./services/create-tools-config.js\";\nexport { createToolsConfig } from \"./services/create-tools-config.js\";\nexport {\n\tDEFAULT_PERSONAL_NEEDS_PROFILE,\n\tcreateDefaultPersonalNeedsProfile,\n} from \"./services/defaultPersonalNeedsProfile.js\";\nexport type {\n\tToolComponentFactory,\n\tToolComponentFactoryMap,\n\tToolComponentOverrides,\n\tToolTagMap,\n} from \"./tools/tool-tag-map.js\";\nexport {\n\tcreateToolElement,\n\tDEFAULT_TOOL_TAG_MAP,\n\tresolveToolTag,\n\ttoToolIdFromTag,\n} from \"./tools/tool-tag-map.js\";\n// QTI 3.0 Standard Access Features\nexport {\n\tALL_STANDARD_ACCESS_FEATURES,\n\tEXAMPLE_PNP_CONFIGURATIONS,\n\tgetFeatureCategory,\n\tgetFeaturesInCategory,\n\tisStandardAccessFeature,\n\tQTI_STANDARD_ACCESS_FEATURES,\n} from \"./services/pnp-standard-features.js\";\n// SSML Extractor (Auto-generates catalogs from embedded SSML)\nexport type { ExtractionResult } from \"./services/SSMLExtractor.js\";\nexport { SSMLExtractor } from \"./services/SSMLExtractor.js\";\n// Theme Provider\nexport type { FontSize, ThemeConfig } from \"./services/ThemeProvider.js\";\nexport { ThemeProvider } from \"./services/ThemeProvider.js\";\n// Tool Coordinator\nexport { ToolCoordinator, ZIndexLayer } from \"./services/ToolCoordinator.js\";\n// Toolkit Coordinator (Centralized service management)\nexport type {\n\tAnswerEliminatorToolConfig,\n\tProviderLifecycleContext,\n\tSectionControllerContext,\n\tSectionControllerEvent,\n\tSectionControllerEventType,\n\tSectionItemEvent,\n\tSectionItemEventType,\n\tSectionControllerFactoryDefaults,\n\tSectionControllerHandle,\n\tSectionControllerKey,\n\tSectionScopedEvent,\n\tSectionScopedEventType,\n\tSectionSessionPersistenceConfig,\n\tSectionItemEventSubscriptionArgs,\n\tSectionScopedEventSubscriptionArgs,\n\tSectionEventSubscriptionArgs,\n\tSectionSessionPersistenceStrategy,\n\tSectionControllerLoadedRenderable,\n\tSectionControllerRuntimeState,\n\tSectionControllerSessionState,\n\tSectionPersistenceFactoryDefaults,\n\tToolConfig,\n\tToolkitCoordinatorConfig,\n\tToolkitCoordinatorHooks,\n\tToolkitErrorContext,\n\tToolkitInitStatus,\n\tToolkitServiceBundle,\n\tToolkitToolsConfig,\n\tTTSToolConfig,\n} from \"./services/ToolkitCoordinator.js\";\nexport { ToolkitCoordinator } from \"./services/ToolkitCoordinator.js\";\nexport type {\n\tCanonicalToolsConfig,\n\tToolPlacementConfig,\n\tToolPlacementLevel,\n\tToolPolicyConfig,\n\tToolProvidersConfig,\n} from \"./services/tools-config-normalizer.js\";\nexport type {\n\tFrameworkErrorKind,\n\tFrameworkErrorModel,\n\tFrameworkErrorSeverity,\n} from \"./services/framework-error.js\";\nexport {\n\tformatFrameworkErrorForConsole,\n\tframeworkErrorFromToolConfigDiagnostics,\n\tframeworkErrorFromUnknown,\n\ttoFrameworkErrorModel,\n} from \"./services/framework-error.js\";\nexport type {\n\tFrameworkErrorListener,\n} from \"./services/framework-error-bus.js\";\nexport type {\n\tToolConfigDiagnostic,\n\tToolConfigDiagnosticSeverity,\n\tToolConfigStrictness,\n\tToolConfigValidationOptions,\n\tToolConfigValidationResult,\n} from \"./services/tool-config-validation.js\";\nexport type {\n\tToolbarButtonItem,\n\tToolbarItem,\n\tToolbarItemBase,\n\tToolbarLinkItem,\n} from \"./services/toolbar-items.js\";\nexport {\n\tisExternalIconUrl,\n\tisInlineSvgIcon,\n\tisToolbarLinkItem,\n\tisValidToolbarItemShape,\n} from \"./services/toolbar-items.js\";\nexport {\n\tnormalizeToolsConfig,\n\tnormalizeToolAlias,\n\tnormalizeToolList,\n\tparseToolList,\n} from \"./services/tools-config-normalizer.js\";\nexport {\n\tframeworkErrorFromToolConfigValidation,\n\tnormalizeAndValidateToolsConfig,\n} from \"./services/tool-config-validation.js\";\nexport type {\n\tParsedToolInstanceId,\n\tToolScopeLevel,\n} from \"./services/tool-instance-id.js\";\nexport {\n\tcreateScopedToolId,\n\tparseScopedToolId,\n\ttoOverlayToolId,\n} from \"./services/tool-instance-id.js\";\n// Text-to-Speech Service\nexport type { TTSConfig } from \"./services/TTSService.js\";\nexport { PlaybackState, TTSService } from \"./services/TTSService.js\";\nexport {\n\tPIE_TTS_CONTROL_HANDOFF_EVENT,\n\ttype TTSControlHandoffDetail,\n} from \"./services/tts-control-events.js\";\nexport { BrowserTTSProvider } from \"./services/tts/browser-provider.js\";\nexport type { SREMathSpeechOptions } from \"./services/tts/math-speech.js\";\nexport type {\n\tTTSHostToolbarLayout,\n\tTTSLayoutMode,\n\tTTSRuntimeSettings,\n} from \"./services/tts-runtime-config.js\";\nexport {\n\tDEFAULT_TTS_SPEED_OPTIONS,\n\tformatTTSSpeedOptionsAsText,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedOptions,\n\tparseTTSSpeedOptionsFromText,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSRuntimeSettings,\n} from \"./services/tts-runtime-config.js\";\n// TTS Provider System\nexport type {\n\tITTSProvider,\n\tITTSProviderImplementation,\n\tTTSSpeechSegment,\n\tTTSFeature,\n\tTTSProviderCapabilities,\n} from \"@pie-players/pie-tts\";\n\n// ============================================================================\n// Item loading (client-resolvable default; optional backend hook)\n// ============================================================================\n\nexport type {\n\tCreateLoadItemOptions,\n\tLoadItem,\n\tLoadItemOptions,\n} from \"./item-loader.js\";\nexport {\n\tcreateFetchItemLoader,\n\tcreateLoadItem,\n\tItemLoadError,\n} from \"./item-loader.js\";\n\n// ============================================================================\n// Attempt Session\n// ============================================================================\n\nexport type {\n\tStorageLike,\n\tTestAttemptItemSession,\n\tTestAttemptSession,\n\tTestAttemptSessionNavigationState,\n\tTestAttemptSessionRealization,\n} from \"./attempt/TestSession.js\";\nexport {\n\tcreateMemoryStorage,\n\tcreateTestAttemptSessionIdentifier,\n\tcreateNewTestAttemptSession,\n\tgetBrowserLocalStorage,\n\tgetOrCreateAnonymousDeviceId,\n\tgetTestAttemptSessionStorageKey,\n\tloadTestAttemptSession,\n\tsaveTestAttemptSession,\n\tsetCurrentPosition,\n\tupsertItemSessionFromPieSessionChange,\n\tupsertVisitedItem,\n} from \"./attempt/TestSession.js\";\nexport type {\n\tAssessmentSession,\n\tAssessmentSectionSessionState,\n\tAssessmentSessionNavigationState,\n\tAssessmentSessionRealization,\n} from \"./attempt/AssessmentSession.js\";\nexport {\n\tcreateNewAssessmentSession,\n\tgetAssessmentSessionStorageKey,\n\tloadAssessmentSession,\n\tsaveAssessmentSession,\n\tsetCurrentSectionPosition,\n\tupsertSectionSession,\n} from \"./attempt/AssessmentSession.js\";\nexport type {\n\tActivitySessionPatchPayload,\n\tMapActivityToTestAttemptSessionArgs,\n\tPieBackendActivityDefinition,\n\tPieBackendActivityItemRef,\n\tPieBackendActivitySession,\n} from \"./attempt/adapters/activity-to-test-attempt-session.js\";\nexport {\n\tbuildActivitySessionItemUpdate,\n\tbuildActivitySessionPatchFromTestAttemptSession,\n\tmapActivityToTestAttemptSession,\n\ttoItemSessionsRecord,\n} from \"./attempt/adapters/activity-to-test-attempt-session.js\";\n\n// Section Player - Use @pie-players/pie-section-player web component\n\n// ============================================================================\n// Shared Components\n// ============================================================================\n\n// ItemToolBar custom element registration helper is exported via package.json exports field\n// Import using: import '@pie-players/pie-assessment-toolkit/components/item-toolbar-element';\n// PieAssessmentToolkit custom element registration helper is exported via package.json exports field\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PIE Assessment Toolkit\n *\n * Independent, composable services for coordinating tools, accommodations,\n * and item players in assessment applications.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Core Infrastructure\n// ============================================================================\n\nexport type {\n\tAssessmentToolkitHostRuntimeContext,\n\tAssessmentToolkitRegionScopeContext,\n\tAssessmentToolkitRuntimeContext,\n\tAssessmentToolkitShellContext,\n\tItemPlayerConfig,\n\tItemPlayerType,\n\tShellContextKind,\n} from \"./context/assessment-toolkit-context.js\";\nexport {\n\tassessmentToolkitHostRuntimeContext,\n\tassessmentToolkitRegionScopeContext,\n\tassessmentToolkitRuntimeContext,\n\tassessmentToolkitShellContext,\n} from \"./context/assessment-toolkit-context.js\";\nexport {\n\tconnectAssessmentToolkitHostRuntimeContext,\n\tconnectAssessmentToolkitRegionScopeContext,\n\tconnectAssessmentToolkitRuntimeContext,\n\tconnectAssessmentToolkitShellContext,\n} from \"./context/runtime-context-consumer.js\";\nexport {\n\tPIE_INTERNAL_CONTENT_LOADED_EVENT,\n\tPIE_INTERNAL_ITEM_SESSION_CHANGED_EVENT,\n\tPIE_INTERNAL_ITEM_PLAYER_ERROR_EVENT,\n\tPIE_ITEM_SESSION_CHANGED_EVENT,\n\tPIE_REGISTER_EVENT,\n\tPIE_UNREGISTER_EVENT,\n\ttype InternalContentLoadedDetail,\n\ttype InternalItemSessionChangedDetail,\n\ttype InternalItemPlayerErrorDetail,\n\ttype ItemSessionChangedDetail,\n\ttype RuntimeRegistrationDetail,\n\ttype RuntimeRegistrationKind,\n} from \"./runtime/registration-events.js\";\nexport {\n\tconnectToolRegionScopeContext,\n\tconnectToolRuntimeContext,\n\tconnectToolShellContext,\n\tcreateCrossBoundaryEvent,\n\tdispatchCrossBoundaryEvent,\n\tisContextValueDefined,\n} from \"./runtime/tool-host-contract.js\";\n\n// ============================================================================\n// Service Interfaces\n// ============================================================================\n\nexport type {\n\tAccessibilityCatalogResolverApi,\n\tElementToolStateStoreApi,\n\tHighlightCoordinatorApi,\n\tI18nServiceApi,\n\tThemeProviderApi,\n\tToolCoordinatorApi,\n\tToolkitCoordinatorApi,\n\tTtsServiceApi,\n\tToolState,\n} from \"./services/interfaces.js\";\n\n// ============================================================================\n// Toolkit Services\n// ============================================================================\n\n// Accessibility Catalog Resolver (QTI 3.0 Accessibility Catalogs)\nexport type {\n\tCatalogLookupContext,\n\tCatalogLookupOptions,\n\tCatalogOwnerContext,\n\tCatalogOwnerKind,\n\tCatalogStatistics,\n\tCatalogType,\n\tResolvedCatalog,\n} from \"./services/AccessibilityCatalogResolver.js\";\nexport { AccessibilityCatalogResolver } from \"./services/AccessibilityCatalogResolver.js\";\n// Context Variable Store (QTI 3.0 Context Declarations)\nexport { ContextVariableStore } from \"./services/ContextVariableStore.js\";\n// Element Tool State Store (Element-level ephemeral tool state)\nexport { ElementToolStateStore } from \"./services/ElementToolStateStore.js\";\n// Highlight Coordinator\nexport type { Annotation } from \"./services/HighlightCoordinator.js\";\nexport {\n\tHighlightColor,\n\tHighlightCoordinator,\n\tHighlightType,\n} from \"./services/HighlightCoordinator.js\";\n// Range Serializer (for annotation persistence)\nexport type { SerializedRange } from \"./services/RangeSerializer.js\";\nexport { RangeSerializer } from \"./services/RangeSerializer.js\";\n// I18n Service\nexport type {\n\tI18nConfig,\n\tPluralTranslation,\n\tTranslationBundle,\n} from \"./services/I18nService.js\";\nexport { I18nService } from \"./services/I18nService.js\";\n// Tool Registry (Registry-based tool system)\nexport type {\n\tResolvedToolContext,\n\tToolbarContext,\n\tToolContextResolver,\n\tToolContextResolverContext,\n\tToolContextResolverMap,\n\tToolContextResolverResult,\n\tToolModuleLoader,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolRegistration,\n} from \"./services/ToolRegistry.js\";\nexport { ToolRegistry } from \"./services/ToolRegistry.js\";\nexport type {\n\tAssessmentToolContext,\n\tBaseToolContext,\n\tElementToolContext,\n\tItemToolContext,\n\tPassageToolContext,\n\tRubricToolContext,\n\tSectionToolContext,\n\tToolContext,\n\tToolLevel,\n} from \"./services/tool-context.js\";\nexport {\n\textractTextContent,\n\thasChoiceInteraction,\n\thasMathContent,\n\thasReadableText,\n\tisAssessmentContext,\n\tisElementContext,\n\tisItemContext,\n\tisPassageContext,\n\tisRubricContext,\n\tisSectionContext,\n} from \"./services/tool-context.js\";\nexport {\n\tDEFAULT_TOOL_PLACEMENT,\n\tDEFAULT_TOOL_ORDER,\n\tcreatePackagedToolRegistry,\n\tPACKAGED_TOOL_PLACEMENT,\n\tregisterPackagedTools,\n} from \"./services/createDefaultToolRegistry.js\";\nexport type { CreateToolsConfigArgs } from \"./services/create-tools-config.js\";\nexport { createToolsConfig } from \"./services/create-tools-config.js\";\nexport {\n\tDEFAULT_PERSONAL_NEEDS_PROFILE,\n\tcreateDefaultPersonalNeedsProfile,\n} from \"./services/defaultPersonalNeedsProfile.js\";\nexport type {\n\tToolComponentFactory,\n\tToolComponentFactoryMap,\n\tToolComponentOverrides,\n\tToolTagMap,\n} from \"./tools/tool-tag-map.js\";\nexport {\n\tcreateToolElement,\n\tDEFAULT_TOOL_TAG_MAP,\n\tresolveToolTag,\n\ttoToolIdFromTag,\n} from \"./tools/tool-tag-map.js\";\n// QTI 3.0 Standard Access Features\nexport {\n\tALL_STANDARD_ACCESS_FEATURES,\n\tEXAMPLE_PNP_CONFIGURATIONS,\n\tgetFeatureCategory,\n\tgetFeaturesInCategory,\n\tisStandardAccessFeature,\n\tQTI_STANDARD_ACCESS_FEATURES,\n} from \"./services/pnp-standard-features.js\";\n// SSML Extractor (Auto-generates catalogs from embedded SSML)\nexport type { ExtractionResult } from \"./services/SSMLExtractor.js\";\nexport { SSMLExtractor } from \"./services/SSMLExtractor.js\";\n// Theme Provider\nexport type { FontSize, ThemeConfig } from \"./services/ThemeProvider.js\";\nexport { ThemeProvider } from \"./services/ThemeProvider.js\";\n// Tool Coordinator\nexport { ToolCoordinator, ZIndexLayer } from \"./services/ToolCoordinator.js\";\n// Toolkit Coordinator (Centralized service management)\nexport type {\n\tAnswerEliminatorToolConfig,\n\tProviderLifecycleContext,\n\tSectionControllerContext,\n\tSectionControllerEvent,\n\tSectionControllerEventType,\n\tSectionItemEvent,\n\tSectionItemEventType,\n\tSectionControllerFactoryDefaults,\n\tSectionControllerHandle,\n\tSectionControllerKey,\n\tSectionScopedEvent,\n\tSectionScopedEventType,\n\tSectionSessionPersistenceConfig,\n\tSectionItemEventSubscriptionArgs,\n\tSectionScopedEventSubscriptionArgs,\n\tSectionEventSubscriptionArgs,\n\tSectionSessionPersistenceStrategy,\n\tSectionControllerLoadedRenderable,\n\tSectionControllerRuntimeState,\n\tSectionControllerSessionState,\n\tSectionPersistenceFactoryDefaults,\n\tToolConfig,\n\tToolkitCoordinatorConfig,\n\tToolkitCoordinatorHooks,\n\tToolkitErrorContext,\n\tToolkitInitStatus,\n\tToolkitServiceBundle,\n\tToolkitToolsConfig,\n\tTTSToolConfig,\n} from \"./services/ToolkitCoordinator.js\";\nexport { ToolkitCoordinator } from \"./services/ToolkitCoordinator.js\";\nexport type {\n\tCanonicalToolsConfig,\n\tToolPlacementConfig,\n\tToolPlacementLevel,\n\tToolPolicyConfig,\n\tToolProvidersConfig,\n} from \"./services/tools-config-normalizer.js\";\nexport type {\n\tFrameworkErrorKind,\n\tFrameworkErrorModel,\n\tFrameworkErrorSeverity,\n} from \"./services/framework-error.js\";\nexport {\n\tformatFrameworkErrorForConsole,\n\tframeworkErrorFromToolConfigDiagnostics,\n\tframeworkErrorFromUnknown,\n\ttoFrameworkErrorModel,\n} from \"./services/framework-error.js\";\nexport type { FrameworkErrorListener } from \"./services/framework-error-bus.js\";\nexport type {\n\tToolConfigDiagnostic,\n\tToolConfigDiagnosticSeverity,\n\tToolConfigStrictness,\n\tToolConfigValidationOptions,\n\tToolConfigValidationResult,\n} from \"./services/tool-config-validation.js\";\nexport type {\n\tToolbarButtonItem,\n\tToolbarItem,\n\tToolbarItemBase,\n\tToolbarLinkItem,\n} from \"./services/toolbar-items.js\";\nexport {\n\tisExternalIconUrl,\n\tisInlineSvgIcon,\n\tisToolbarLinkItem,\n\tisValidToolbarItemShape,\n} from \"./services/toolbar-items.js\";\nexport {\n\tnormalizeToolsConfig,\n\tnormalizeToolAlias,\n\tnormalizeToolList,\n\tparseToolList,\n} from \"./services/tools-config-normalizer.js\";\nexport {\n\tframeworkErrorFromToolConfigValidation,\n\tnormalizeAndValidateToolsConfig,\n} from \"./services/tool-config-validation.js\";\nexport type {\n\tParsedToolInstanceId,\n\tToolScopeLevel,\n} from \"./services/tool-instance-id.js\";\nexport {\n\tcreateScopedToolId,\n\tparseScopedToolId,\n\ttoOverlayToolId,\n} from \"./services/tool-instance-id.js\";\n// Text-to-Speech Service\nexport type { TTSConfig } from \"./services/TTSService.js\";\nexport { PlaybackState, TTSService } from \"./services/TTSService.js\";\nexport {\n\tPIE_TTS_CONTROL_HANDOFF_EVENT,\n\ttype TTSControlHandoffDetail,\n} from \"./services/tts-control-events.js\";\nexport { BrowserTTSProvider } from \"./services/tts/browser-provider.js\";\nexport type { SREMathSpeechOptions } from \"./services/tts/math-speech.js\";\nexport type {\n\tTTSHostToolbarLayout,\n\tTTSLayoutMode,\n\tTTSRuntimeSettings,\n} from \"./services/tts-runtime-config.js\";\nexport {\n\tDEFAULT_TTS_SPEED_OPTIONS,\n\tformatTTSSpeedOptionsAsText,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedOptions,\n\tparseTTSSpeedOptionsFromText,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSRuntimeSettings,\n} from \"./services/tts-runtime-config.js\";\n// TTS Provider System\nexport type {\n\tITTSProvider,\n\tITTSProviderImplementation,\n\tTTSSpeechSegment,\n\tTTSFeature,\n\tTTSProviderCapabilities,\n} from \"@pie-players/pie-tts\";\n\n// ============================================================================\n// Item loading (client-resolvable default; optional backend hook)\n// ============================================================================\n\nexport type {\n\tCreateLoadItemOptions,\n\tLoadItem,\n\tLoadItemOptions,\n} from \"./item-loader.js\";\nexport {\n\tcreateFetchItemLoader,\n\tcreateLoadItem,\n\tItemLoadError,\n} from \"./item-loader.js\";\n\n// ============================================================================\n// Attempt Session\n// ============================================================================\n\nexport type {\n\tStorageLike,\n\tTestAttemptItemSession,\n\tTestAttemptSession,\n\tTestAttemptSessionNavigationState,\n\tTestAttemptSessionRealization,\n} from \"./attempt/TestSession.js\";\nexport {\n\tcreateMemoryStorage,\n\tcreateTestAttemptSessionIdentifier,\n\tcreateNewTestAttemptSession,\n\tgetBrowserLocalStorage,\n\tgetOrCreateAnonymousDeviceId,\n\tgetTestAttemptSessionStorageKey,\n\tloadTestAttemptSession,\n\tsaveTestAttemptSession,\n\tsetCurrentPosition,\n\tupsertItemSessionFromPieSessionChange,\n\tupsertVisitedItem,\n} from \"./attempt/TestSession.js\";\nexport type {\n\tAssessmentSession,\n\tAssessmentSectionSessionState,\n\tAssessmentSessionNavigationState,\n\tAssessmentSessionRealization,\n} from \"./attempt/AssessmentSession.js\";\nexport {\n\tcreateNewAssessmentSession,\n\tgetAssessmentSessionStorageKey,\n\tloadAssessmentSession,\n\tsaveAssessmentSession,\n\tsetCurrentSectionPosition,\n\tupsertSectionSession,\n} from \"./attempt/AssessmentSession.js\";\nexport type {\n\tActivitySessionPatchPayload,\n\tMapActivityToTestAttemptSessionArgs,\n\tPieBackendActivityDefinition,\n\tPieBackendActivityItemRef,\n\tPieBackendActivitySession,\n} from \"./attempt/adapters/activity-to-test-attempt-session.js\";\nexport {\n\tbuildActivitySessionItemUpdate,\n\tbuildActivitySessionPatchFromTestAttemptSession,\n\tmapActivityToTestAttemptSession,\n\ttoItemSessionsRecord,\n} from \"./attempt/adapters/activity-to-test-attempt-session.js\";\n\n// Section Player - Use @pie-players/pie-section-player web component\n\n// ============================================================================\n// Shared Components\n// ============================================================================\n\n// ItemToolBar custom element registration helper is exported via package.json exports field\n// Import using: import '@pie-players/pie-assessment-toolkit/components/item-toolbar-element';\n// PieAssessmentToolkit custom element registration helper is exported via package.json exports field\n"]}
@@ -49,8 +49,7 @@ export function assessmentHasPnpPolicyInputs(assessment) {
49
49
  pnp.prohibitedSupports.length > 0) {
50
50
  return true;
51
51
  }
52
- if (Array.isArray(pnp.activateAtInit) &&
53
- pnp.activateAtInit.length > 0) {
52
+ if (Array.isArray(pnp.activateAtInit) && pnp.activateAtInit.length > 0) {
54
53
  return true;
55
54
  }
56
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pnp-policy-inputs.js","sourceRoot":"","sources":["../../../src/policy/core/pnp-policy-inputs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PNP/profile policy input detection (M8 PR 4 — see `.cursor/plans/m8-design.md` F2 and\n * `.cursor/plans/m8-implementation-plan.md` § PR 4).\n *\n * Pure helpers that decide whether the inputs the engine has been given\n * actually carry PNP/profile policy material. Used by:\n *\n * - {@link ToolPolicyEngine}'s constructor as the auto-default for\n * `pnpEnforcement` when the host did not pass an explicit `\"on\"` /\n * `\"off\"`.\n * - {@link ToolkitCoordinator.resolveEffectivePnpEnforcement} as the\n * auto-mode rule. PR 2 used a coarse \"any non-null assessment → on\"\n * placeholder; PR 4 narrows it to \"assessment OR currentItemRef\n * carries profile policy material.\"\n *\n * The rule is intentionally narrow. Hosts that bind a bare assessment\n * record (only `id` / `name`, no PNP and no settings) do not engage\n * PNP/profile gates. The flip happens the moment the assessment carries any of:\n *\n * - `personalNeedsProfile` (any `supports`, `prohibitedSupports`, or\n * `activateAtInit`),\n * - `settings.districtPolicy` (any `blockedTools`, `requiredTools`,\n * or `policies`),\n * - `settings.testAdministration` (any populated key — `mode`,\n * `toolOverrides`, etc.),\n * - or the bound `currentItemRef.settings` carries\n * `requiredTools` / `restrictedTools` / `toolParameters`.\n *\n * Hosts opt out of the auto-on behavior by passing\n * `pnpEnforcement: \"off\"` explicitly (engine input or\n * `ToolkitCoordinator.setPnpEnforcement(\"off\")`).\n */\n\nimport type {\n\tAssessmentEntity,\n\tAssessmentItemRef,\n} from \"@pie-players/pie-players-shared/types\";\n\n/**\n * Return `true` when the assessment carries any PNP/profile policy\n * material that the engine's `PnpPolicySource` would consume.\n *\n * The check is structural — the presence of a non-empty PNP, district\n * policy, or test administration block is enough; the content does not\n * have to validate against any specific rule.\n */\nexport function assessmentHasPnpPolicyInputs(\n\tassessment: AssessmentEntity | null | undefined,\n): boolean {\n\tif (!assessment) return false;\n\tconst pnp = assessment.personalNeedsProfile;\n\tif (pnp) {\n\t\tif (Array.isArray(pnp.supports) && pnp.supports.length > 0) return true;\n\t\tif (\n\t\t\tArray.isArray(pnp.prohibitedSupports) &&\n\t\t\tpnp.prohibitedSupports.length > 0\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tif (\n\t\t\tArray.isArray(pnp.activateAtInit) &&\n\t\t\tpnp.activateAtInit.length > 0\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\tconst settings = assessment.settings;\n\tif (settings) {\n\t\tconst district = settings.districtPolicy;\n\t\tif (district) {\n\t\t\tif (\n\t\t\t\tArray.isArray(district.blockedTools) &&\n\t\t\t\tdistrict.blockedTools.length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tArray.isArray(district.requiredTools) &&\n\t\t\t\tdistrict.requiredTools.length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tdistrict.policies &&\n\t\t\t\ttypeof district.policies === \"object\" &&\n\t\t\t\tObject.keys(district.policies).length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tconst admin = settings.testAdministration;\n\t\tif (admin && typeof admin === \"object\") {\n\t\t\tfor (const key of Object.keys(admin)) {\n\t\t\t\tconst value = (admin as Record<string, unknown>)[key];\n\t\t\t\tif (value === undefined || value === null) continue;\n\t\t\t\tif (Array.isArray(value) && value.length === 0) continue;\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === \"object\" &&\n\t\t\t\t\t!Array.isArray(value) &&\n\t\t\t\t\tObject.keys(value as Record<string, unknown>).length === 0\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Return `true` when the bound item reference carries item-level profile policy\n * material (`requiredTools`, `restrictedTools`, or `toolParameters`).\n *\n * Used in addition to {@link assessmentHasPnpPolicyInputs} so a host that\n * navigates to an item with profile-relevant settings — without a parent\n * assessment carrying its own PNP/district/test-admin block — still\n * gets PNP/profile gates engaged for that item.\n */\nexport function itemRefHasPnpPolicyInputs(\n\titemRef: AssessmentItemRef | null | undefined,\n): boolean {\n\tconst settings = itemRef?.settings;\n\tif (!settings) return false;\n\tif (\n\t\tArray.isArray(settings.requiredTools) &&\n\t\tsettings.requiredTools.length > 0\n\t) {\n\t\treturn true;\n\t}\n\tif (\n\t\tArray.isArray(settings.restrictedTools) &&\n\t\tsettings.restrictedTools.length > 0\n\t) {\n\t\treturn true;\n\t}\n\tif (\n\t\tsettings.toolParameters &&\n\t\ttypeof settings.toolParameters === \"object\" &&\n\t\tObject.keys(settings.toolParameters).length > 0\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Resolve the default `pnpEnforcement` mode given the bound inputs.\n *\n * Returns `\"on\"` when {@link assessmentHasPnpPolicyInputs} or\n * {@link itemRefHasPnpPolicyInputs} reports any profile policy material; otherwise\n * `\"off\"`. Hosts override the default by passing an explicit\n * `pnpEnforcement` value (engine input) or by calling\n * `ToolkitCoordinator.setPnpEnforcement(\"on\" | \"off\")`.\n */\nexport function resolveDefaultPnpEnforcement(args: {\n\tassessment?: AssessmentEntity | null;\n\tcurrentItemRef?: AssessmentItemRef | null;\n}): \"on\" | \"off\" {\n\tif (assessmentHasPnpPolicyInputs(args.assessment)) return \"on\";\n\tif (itemRefHasPnpPolicyInputs(args.currentItemRef)) return \"on\";\n\treturn \"off\";\n}\n"]}
1
+ {"version":3,"file":"pnp-policy-inputs.js","sourceRoot":"","sources":["../../../src/policy/core/pnp-policy-inputs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PNP/profile policy input detection (M8 PR 4 — see `.cursor/plans/m8-design.md` F2 and\n * `.cursor/plans/m8-implementation-plan.md` § PR 4).\n *\n * Pure helpers that decide whether the inputs the engine has been given\n * actually carry PNP/profile policy material. Used by:\n *\n * - {@link ToolPolicyEngine}'s constructor as the auto-default for\n * `pnpEnforcement` when the host did not pass an explicit `\"on\"` /\n * `\"off\"`.\n * - {@link ToolkitCoordinator.resolveEffectivePnpEnforcement} as the\n * auto-mode rule. PR 2 used a coarse \"any non-null assessment → on\"\n * placeholder; PR 4 narrows it to \"assessment OR currentItemRef\n * carries profile policy material.\"\n *\n * The rule is intentionally narrow. Hosts that bind a bare assessment\n * record (only `id` / `name`, no PNP and no settings) do not engage\n * PNP/profile gates. The flip happens the moment the assessment carries any of:\n *\n * - `personalNeedsProfile` (any `supports`, `prohibitedSupports`, or\n * `activateAtInit`),\n * - `settings.districtPolicy` (any `blockedTools`, `requiredTools`,\n * or `policies`),\n * - `settings.testAdministration` (any populated key — `mode`,\n * `toolOverrides`, etc.),\n * - or the bound `currentItemRef.settings` carries\n * `requiredTools` / `restrictedTools` / `toolParameters`.\n *\n * Hosts opt out of the auto-on behavior by passing\n * `pnpEnforcement: \"off\"` explicitly (engine input or\n * `ToolkitCoordinator.setPnpEnforcement(\"off\")`).\n */\n\nimport type {\n\tAssessmentEntity,\n\tAssessmentItemRef,\n} from \"@pie-players/pie-players-shared/types\";\n\n/**\n * Return `true` when the assessment carries any PNP/profile policy\n * material that the engine's `PnpPolicySource` would consume.\n *\n * The check is structural — the presence of a non-empty PNP, district\n * policy, or test administration block is enough; the content does not\n * have to validate against any specific rule.\n */\nexport function assessmentHasPnpPolicyInputs(\n\tassessment: AssessmentEntity | null | undefined,\n): boolean {\n\tif (!assessment) return false;\n\tconst pnp = assessment.personalNeedsProfile;\n\tif (pnp) {\n\t\tif (Array.isArray(pnp.supports) && pnp.supports.length > 0) return true;\n\t\tif (\n\t\t\tArray.isArray(pnp.prohibitedSupports) &&\n\t\t\tpnp.prohibitedSupports.length > 0\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tif (Array.isArray(pnp.activateAtInit) && pnp.activateAtInit.length > 0) {\n\t\t\treturn true;\n\t\t}\n\t}\n\tconst settings = assessment.settings;\n\tif (settings) {\n\t\tconst district = settings.districtPolicy;\n\t\tif (district) {\n\t\t\tif (\n\t\t\t\tArray.isArray(district.blockedTools) &&\n\t\t\t\tdistrict.blockedTools.length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tArray.isArray(district.requiredTools) &&\n\t\t\t\tdistrict.requiredTools.length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tdistrict.policies &&\n\t\t\t\ttypeof district.policies === \"object\" &&\n\t\t\t\tObject.keys(district.policies).length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tconst admin = settings.testAdministration;\n\t\tif (admin && typeof admin === \"object\") {\n\t\t\tfor (const key of Object.keys(admin)) {\n\t\t\t\tconst value = (admin as Record<string, unknown>)[key];\n\t\t\t\tif (value === undefined || value === null) continue;\n\t\t\t\tif (Array.isArray(value) && value.length === 0) continue;\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === \"object\" &&\n\t\t\t\t\t!Array.isArray(value) &&\n\t\t\t\t\tObject.keys(value as Record<string, unknown>).length === 0\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Return `true` when the bound item reference carries item-level profile policy\n * material (`requiredTools`, `restrictedTools`, or `toolParameters`).\n *\n * Used in addition to {@link assessmentHasPnpPolicyInputs} so a host that\n * navigates to an item with profile-relevant settings — without a parent\n * assessment carrying its own PNP/district/test-admin block — still\n * gets PNP/profile gates engaged for that item.\n */\nexport function itemRefHasPnpPolicyInputs(\n\titemRef: AssessmentItemRef | null | undefined,\n): boolean {\n\tconst settings = itemRef?.settings;\n\tif (!settings) return false;\n\tif (\n\t\tArray.isArray(settings.requiredTools) &&\n\t\tsettings.requiredTools.length > 0\n\t) {\n\t\treturn true;\n\t}\n\tif (\n\t\tArray.isArray(settings.restrictedTools) &&\n\t\tsettings.restrictedTools.length > 0\n\t) {\n\t\treturn true;\n\t}\n\tif (\n\t\tsettings.toolParameters &&\n\t\ttypeof settings.toolParameters === \"object\" &&\n\t\tObject.keys(settings.toolParameters).length > 0\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Resolve the default `pnpEnforcement` mode given the bound inputs.\n *\n * Returns `\"on\"` when {@link assessmentHasPnpPolicyInputs} or\n * {@link itemRefHasPnpPolicyInputs} reports any profile policy material; otherwise\n * `\"off\"`. Hosts override the default by passing an explicit\n * `pnpEnforcement` value (engine input) or by calling\n * `ToolkitCoordinator.setPnpEnforcement(\"on\" | \"off\")`.\n */\nexport function resolveDefaultPnpEnforcement(args: {\n\tassessment?: AssessmentEntity | null;\n\tcurrentItemRef?: AssessmentItemRef | null;\n}): \"on\" | \"off\" {\n\tif (assessmentHasPnpPolicyInputs(args.assessment)) return \"on\";\n\tif (itemRefHasPnpPolicyInputs(args.currentItemRef)) return \"on\";\n\treturn \"off\";\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"provenance.js","sourceRoot":"","sources":["../../../src/policy/core/provenance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool Policy Provenance (M8 — see `.cursor/plans/m8-design.md` § 4).\n *\n * Tracks decisions from every Pass-1 contributor: host placement, host policy,\n * provider veto, PNP/profile gates, and custom policy sources.\n */\n\n/**\n * Rule vocabulary for tool policy decisions.\n */\nexport type ToolPolicyDecisionRule =\n\t| \"district-block\"\n\t| \"test-admin-override\"\n\t| \"item-restriction\"\n\t| \"item-requirement\"\n\t| \"district-requirement\"\n\t| \"pnp-support\"\n\t| \"pnp-prohibited\"\n\t| \"placement-membership\"\n\t| \"provider-disabled\"\n\t| \"host-allowlist\"\n\t| \"host-blocked\"\n\t| \"required-tool-blocked\"\n\t| \"custom-source\"\n\t| \"system-default\";\n\nexport type ToolPolicySourceType =\n\t| \"organization\"\n\t| \"assessment\"\n\t| \"section\"\n\t| \"item\"\n\t| \"student\"\n\t| \"system\"\n\t| \"host\"\n\t| \"custom\";\n\nexport interface ToolPolicyResolutionDecision {\n\t/** Monotonic step index across the entire decision log. */\n\tstep: number;\n\n\t/**\n\t * Precedence level. PNP/profile rules use `1`–`6`; non-profile rules use `0`\n\t * for host-side gates or `7+` for custom sources that run after PNP/profile policy.\n\t */\n\tprecedence: number;\n\n\trule: ToolPolicyDecisionRule;\n\n\t/** Tool ID being resolved (post-PNP-support-mapping where applicable). */\n\tfeatureId: string;\n\n\taction: \"block\" | \"enable\" | \"skip\" | \"advisory\";\n\n\tsource: {\n\t\ttype: ToolPolicySourceType;\n\t\tid?: string;\n\t\tname?: string;\n\t};\n\n\treason: string;\n\n\tvalue?: unknown;\n\n\ttimestamp: Date;\n}\n\nexport interface ToolPolicyFeatureTrail {\n\tfeatureId: string;\n\tfinalState: \"enabled\" | \"blocked\" | \"not-configured\" | \"advisory-only\";\n\twinningDecision?: ToolPolicyResolutionDecision;\n\tallDecisions: ToolPolicyResolutionDecision[];\n\texplanation: string;\n}\n\nexport interface ToolPolicyProvenance {\n\tcontextId: string;\n\tresolvedAt: Date;\n\tsources: {\n\t\torganization?: { id: string; name: string; pnpDefaults?: unknown };\n\t\tassessment?: { id: string; name: string; settings?: unknown };\n\t\tsection?: { id: string; title?: string; settings?: unknown };\n\t\titem?: { id: string; name?: string; settings?: unknown };\n\t\tstudent?: { id: string; pnpProfile?: unknown };\n\t\thost?: { id: string; config?: unknown };\n\t};\n\tfeatures: Map<string, ToolPolicyFeatureTrail>;\n\tdecisionLog: ToolPolicyResolutionDecision[];\n\tsummary: {\n\t\ttotalFeatures: number;\n\t\tenabled: number;\n\t\tblocked: number;\n\t\tnotConfigured: number;\n\t\tbySource: Record<string, number>;\n\t\tbyRule: Record<string, number>;\n\t};\n}\n\ninterface AddDecisionParams {\n\tprecedence: number;\n\trule: ToolPolicyDecisionRule;\n\tfeatureId: string;\n\taction: ToolPolicyResolutionDecision[\"action\"];\n\tsourceType: ToolPolicySourceType;\n\tsourceId?: string;\n\tsourceName?: string;\n\treason: string;\n\tvalue?: unknown;\n}\n\n/**\n * Builder for `ToolPolicyProvenance`.\n */\nexport class ToolPolicyProvenanceBuilder {\n\tprivate provenance: ToolPolicyProvenance;\n\tprivate stepCounter = 0;\n\n\tconstructor(contextId: string) {\n\t\tthis.provenance = {\n\t\t\tcontextId,\n\t\t\tresolvedAt: new Date(),\n\t\t\tsources: {},\n\t\t\tfeatures: new Map(),\n\t\t\tdecisionLog: [],\n\t\t\tsummary: {\n\t\t\t\ttotalFeatures: 0,\n\t\t\t\tenabled: 0,\n\t\t\t\tblocked: 0,\n\t\t\t\tnotConfigured: 0,\n\t\t\t\tbySource: {},\n\t\t\t\tbyRule: {},\n\t\t\t},\n\t\t};\n\t}\n\n\taddSource(\n\t\ttype: keyof ToolPolicyProvenance[\"sources\"],\n\t\tdata: { id: string; name?: string; config?: unknown },\n\t): this {\n\t\tconst base = { id: data.id, name: data.name ?? data.id };\n\t\tswitch (type) {\n\t\t\tcase \"organization\":\n\t\t\t\tthis.provenance.sources.organization = {\n\t\t\t\t\t...base,\n\t\t\t\t\tpnpDefaults: data.config,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"assessment\":\n\t\t\t\tthis.provenance.sources.assessment = {\n\t\t\t\t\t...base,\n\t\t\t\t\tsettings: data.config,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"section\":\n\t\t\t\tthis.provenance.sources.section = { ...base, settings: data.config };\n\t\t\t\tbreak;\n\t\t\tcase \"item\":\n\t\t\t\tthis.provenance.sources.item = { ...base, settings: data.config };\n\t\t\t\tbreak;\n\t\t\tcase \"student\":\n\t\t\t\tthis.provenance.sources.student = {\n\t\t\t\t\tid: data.id,\n\t\t\t\t\tpnpProfile: data.config,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"host\":\n\t\t\t\tthis.provenance.sources.host = { id: data.id, config: data.config };\n\t\t\t\tbreak;\n\t\t}\n\t\treturn this;\n\t}\n\n\taddDecision(params: AddDecisionParams): this {\n\t\tconst decision: ToolPolicyResolutionDecision = {\n\t\t\tstep: ++this.stepCounter,\n\t\t\tprecedence: params.precedence,\n\t\t\trule: params.rule,\n\t\t\tfeatureId: params.featureId,\n\t\t\taction: params.action,\n\t\t\tsource: {\n\t\t\t\ttype: params.sourceType,\n\t\t\t\tid: params.sourceId,\n\t\t\t\tname: params.sourceName,\n\t\t\t},\n\t\t\treason: params.reason,\n\t\t\tvalue: params.value,\n\t\t\ttimestamp: new Date(),\n\t\t};\n\n\t\tthis.provenance.decisionLog.push(decision);\n\n\t\tlet trail = this.provenance.features.get(params.featureId);\n\t\tif (!trail) {\n\t\t\ttrail = {\n\t\t\t\tfeatureId: params.featureId,\n\t\t\t\tfinalState: \"not-configured\",\n\t\t\t\tallDecisions: [],\n\t\t\t\texplanation: \"\",\n\t\t\t};\n\t\t\tthis.provenance.features.set(params.featureId, trail);\n\t\t}\n\t\ttrail.allDecisions.push(decision);\n\n\t\t// \"advisory\" doesn't change finalState — it preserves the existing\n\t\t// blocked/enabled state and only flags a documented conflict.\n\t\tif (params.action === \"advisory\") {\n\t\t\tif (trail.finalState === \"not-configured\") {\n\t\t\t\ttrail.finalState = \"advisory-only\";\n\t\t\t}\n\t\t} else if (params.action !== \"skip\") {\n\t\t\tconst isWinning =\n\t\t\t\t!trail.winningDecision ||\n\t\t\t\tdecision.precedence < trail.winningDecision.precedence;\n\t\t\tif (isWinning) {\n\t\t\t\ttrail.winningDecision = decision;\n\t\t\t\ttrail.finalState = decision.action === \"enable\" ? \"enabled\" : \"blocked\";\n\t\t\t}\n\t\t}\n\n\t\tthis.provenance.summary.bySource[params.sourceType] =\n\t\t\t(this.provenance.summary.bySource[params.sourceType] || 0) + 1;\n\t\tthis.provenance.summary.byRule[params.rule] =\n\t\t\t(this.provenance.summary.byRule[params.rule] || 0) + 1;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Reconcile every feature's `finalState` against the post-pipeline\n\t * candidate set.\n\t *\n\t * The eager `finalState` updates inside `addDecision` track the\n\t * highest-precedence non-skip decision per feature, but a tool's\n\t * *actual* visibility is only known after step 6 of the\n\t * composition pipeline — earlier decisions can be reversed by\n\t * later host gates, PNP/profile gates, or custom sources. This method\n\t * walks every feature trail and rewrites `finalState` from the\n\t * final candidate set so callers can rely on\n\t * `provenance.features.get(toolId)?.finalState` as the canonical\n\t * \"is this tool visible right now?\" answer (M8 design § 4 + § 12).\n\t *\n\t * Semantics applied per feature:\n\t * - In `survivingIds` → \"enabled\"\n\t * - Not in `survivingIds`, has any non-skip decision → \"blocked\"\n\t * - Not in `survivingIds`, only advisory decisions → \"advisory-only\"\n\t * - Otherwise → \"not-configured\"\n\t *\n\t * Surviving features without any logged decisions get a synthetic\n\t * \"enabled\" trail so the provenance is dense enough for hosts that\n\t * iterate `provenance.features` to find the visible set.\n\t */\n\treconcileFinalStates(survivingIds: ReadonlySet<string>): this {\n\t\tfor (const featureId of survivingIds) {\n\t\t\tlet trail = this.provenance.features.get(featureId);\n\t\t\tif (!trail) {\n\t\t\t\ttrail = {\n\t\t\t\t\tfeatureId,\n\t\t\t\t\tfinalState: \"enabled\",\n\t\t\t\t\tallDecisions: [],\n\t\t\t\t\texplanation: \"\",\n\t\t\t\t};\n\t\t\t\tthis.provenance.features.set(featureId, trail);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttrail.finalState = \"enabled\";\n\t\t}\n\n\t\tfor (const trail of this.provenance.features.values()) {\n\t\t\tif (survivingIds.has(trail.featureId)) continue;\n\t\t\tconst hasNonSkip = trail.allDecisions.some(\n\t\t\t\t(d) => d.action !== \"skip\" && d.action !== \"advisory\",\n\t\t\t);\n\t\t\tconst hasAdvisory = trail.allDecisions.some(\n\t\t\t\t(d) => d.action === \"advisory\",\n\t\t\t);\n\t\t\tif (hasNonSkip) {\n\t\t\t\ttrail.finalState = \"blocked\";\n\t\t\t} else if (hasAdvisory) {\n\t\t\t\ttrail.finalState = \"advisory-only\";\n\t\t\t} else {\n\t\t\t\ttrail.finalState = \"not-configured\";\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tbuild(): ToolPolicyProvenance {\n\t\tfor (const trail of this.provenance.features.values()) {\n\t\t\ttrail.explanation = generateExplanation(trail);\n\t\t}\n\t\tfor (const trail of this.provenance.features.values()) {\n\t\t\tthis.provenance.summary.totalFeatures++;\n\t\t\tif (trail.finalState === \"enabled\") {\n\t\t\t\tthis.provenance.summary.enabled++;\n\t\t\t} else if (trail.finalState === \"blocked\") {\n\t\t\t\tthis.provenance.summary.blocked++;\n\t\t\t} else {\n\t\t\t\tthis.provenance.summary.notConfigured++;\n\t\t\t}\n\t\t}\n\t\treturn this.provenance;\n\t}\n}\n\nfunction generateExplanation(trail: ToolPolicyFeatureTrail): string {\n\tif (!trail.winningDecision) {\n\t\tif (trail.finalState === \"advisory-only\") {\n\t\t\tconst advisory = trail.allDecisions.find((d) => d.action === \"advisory\");\n\t\t\treturn advisory\n\t\t\t\t? `Feature \"${trail.featureId}\" was kept in its host-decided state; ${advisory.reason}`\n\t\t\t\t: `Feature \"${trail.featureId}\" carries an advisory note.`;\n\t\t}\n\t\treturn `Feature \"${trail.featureId}\" was not configured at any level.`;\n\t}\n\n\tconst decision = trail.winningDecision;\n\tconst sourceName = decision.source.name || decision.source.type;\n\tlet explanation = `Feature \"${trail.featureId}\" is ${trail.finalState}.\\n\\n`;\n\texplanation += `**Primary Reason** (${decision.rule}):\\n`;\n\texplanation += `${decision.reason}\\n`;\n\texplanation += `Source: ${sourceName} (${decision.source.type})\\n`;\n\tconst overridden = trail.allDecisions.filter(\n\t\t(d) =>\n\t\t\td.step !== decision.step &&\n\t\t\td.action !== \"skip\" &&\n\t\t\td.action !== \"advisory\" &&\n\t\t\td.precedence > decision.precedence,\n\t);\n\tif (overridden.length > 0) {\n\t\texplanation += `\\n**Overridden Rules**:\\n`;\n\t\tfor (const d of overridden) {\n\t\t\texplanation += `- ${d.rule}: ${d.reason}\\n`;\n\t\t}\n\t}\n\treturn explanation;\n}\n\n"]}
1
+ {"version":3,"file":"provenance.js","sourceRoot":"","sources":["../../../src/policy/core/provenance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool Policy Provenance (M8 — see `.cursor/plans/m8-design.md` § 4).\n *\n * Tracks decisions from every Pass-1 contributor: host placement, host policy,\n * provider veto, PNP/profile gates, and custom policy sources.\n */\n\n/**\n * Rule vocabulary for tool policy decisions.\n */\nexport type ToolPolicyDecisionRule =\n\t| \"district-block\"\n\t| \"test-admin-override\"\n\t| \"item-restriction\"\n\t| \"item-requirement\"\n\t| \"district-requirement\"\n\t| \"pnp-support\"\n\t| \"pnp-prohibited\"\n\t| \"placement-membership\"\n\t| \"provider-disabled\"\n\t| \"host-allowlist\"\n\t| \"host-blocked\"\n\t| \"required-tool-blocked\"\n\t| \"custom-source\"\n\t| \"system-default\";\n\nexport type ToolPolicySourceType =\n\t| \"organization\"\n\t| \"assessment\"\n\t| \"section\"\n\t| \"item\"\n\t| \"student\"\n\t| \"system\"\n\t| \"host\"\n\t| \"custom\";\n\nexport interface ToolPolicyResolutionDecision {\n\t/** Monotonic step index across the entire decision log. */\n\tstep: number;\n\n\t/**\n\t * Precedence level. PNP/profile rules use `1`–`6`; non-profile rules use `0`\n\t * for host-side gates or `7+` for custom sources that run after PNP/profile policy.\n\t */\n\tprecedence: number;\n\n\trule: ToolPolicyDecisionRule;\n\n\t/** Tool ID being resolved (post-PNP-support-mapping where applicable). */\n\tfeatureId: string;\n\n\taction: \"block\" | \"enable\" | \"skip\" | \"advisory\";\n\n\tsource: {\n\t\ttype: ToolPolicySourceType;\n\t\tid?: string;\n\t\tname?: string;\n\t};\n\n\treason: string;\n\n\tvalue?: unknown;\n\n\ttimestamp: Date;\n}\n\nexport interface ToolPolicyFeatureTrail {\n\tfeatureId: string;\n\tfinalState: \"enabled\" | \"blocked\" | \"not-configured\" | \"advisory-only\";\n\twinningDecision?: ToolPolicyResolutionDecision;\n\tallDecisions: ToolPolicyResolutionDecision[];\n\texplanation: string;\n}\n\nexport interface ToolPolicyProvenance {\n\tcontextId: string;\n\tresolvedAt: Date;\n\tsources: {\n\t\torganization?: { id: string; name: string; pnpDefaults?: unknown };\n\t\tassessment?: { id: string; name: string; settings?: unknown };\n\t\tsection?: { id: string; title?: string; settings?: unknown };\n\t\titem?: { id: string; name?: string; settings?: unknown };\n\t\tstudent?: { id: string; pnpProfile?: unknown };\n\t\thost?: { id: string; config?: unknown };\n\t};\n\tfeatures: Map<string, ToolPolicyFeatureTrail>;\n\tdecisionLog: ToolPolicyResolutionDecision[];\n\tsummary: {\n\t\ttotalFeatures: number;\n\t\tenabled: number;\n\t\tblocked: number;\n\t\tnotConfigured: number;\n\t\tbySource: Record<string, number>;\n\t\tbyRule: Record<string, number>;\n\t};\n}\n\ninterface AddDecisionParams {\n\tprecedence: number;\n\trule: ToolPolicyDecisionRule;\n\tfeatureId: string;\n\taction: ToolPolicyResolutionDecision[\"action\"];\n\tsourceType: ToolPolicySourceType;\n\tsourceId?: string;\n\tsourceName?: string;\n\treason: string;\n\tvalue?: unknown;\n}\n\n/**\n * Builder for `ToolPolicyProvenance`.\n */\nexport class ToolPolicyProvenanceBuilder {\n\tprivate provenance: ToolPolicyProvenance;\n\tprivate stepCounter = 0;\n\n\tconstructor(contextId: string) {\n\t\tthis.provenance = {\n\t\t\tcontextId,\n\t\t\tresolvedAt: new Date(),\n\t\t\tsources: {},\n\t\t\tfeatures: new Map(),\n\t\t\tdecisionLog: [],\n\t\t\tsummary: {\n\t\t\t\ttotalFeatures: 0,\n\t\t\t\tenabled: 0,\n\t\t\t\tblocked: 0,\n\t\t\t\tnotConfigured: 0,\n\t\t\t\tbySource: {},\n\t\t\t\tbyRule: {},\n\t\t\t},\n\t\t};\n\t}\n\n\taddSource(\n\t\ttype: keyof ToolPolicyProvenance[\"sources\"],\n\t\tdata: { id: string; name?: string; config?: unknown },\n\t): this {\n\t\tconst base = { id: data.id, name: data.name ?? data.id };\n\t\tswitch (type) {\n\t\t\tcase \"organization\":\n\t\t\t\tthis.provenance.sources.organization = {\n\t\t\t\t\t...base,\n\t\t\t\t\tpnpDefaults: data.config,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"assessment\":\n\t\t\t\tthis.provenance.sources.assessment = {\n\t\t\t\t\t...base,\n\t\t\t\t\tsettings: data.config,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"section\":\n\t\t\t\tthis.provenance.sources.section = { ...base, settings: data.config };\n\t\t\t\tbreak;\n\t\t\tcase \"item\":\n\t\t\t\tthis.provenance.sources.item = { ...base, settings: data.config };\n\t\t\t\tbreak;\n\t\t\tcase \"student\":\n\t\t\t\tthis.provenance.sources.student = {\n\t\t\t\t\tid: data.id,\n\t\t\t\t\tpnpProfile: data.config,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"host\":\n\t\t\t\tthis.provenance.sources.host = { id: data.id, config: data.config };\n\t\t\t\tbreak;\n\t\t}\n\t\treturn this;\n\t}\n\n\taddDecision(params: AddDecisionParams): this {\n\t\tconst decision: ToolPolicyResolutionDecision = {\n\t\t\tstep: ++this.stepCounter,\n\t\t\tprecedence: params.precedence,\n\t\t\trule: params.rule,\n\t\t\tfeatureId: params.featureId,\n\t\t\taction: params.action,\n\t\t\tsource: {\n\t\t\t\ttype: params.sourceType,\n\t\t\t\tid: params.sourceId,\n\t\t\t\tname: params.sourceName,\n\t\t\t},\n\t\t\treason: params.reason,\n\t\t\tvalue: params.value,\n\t\t\ttimestamp: new Date(),\n\t\t};\n\n\t\tthis.provenance.decisionLog.push(decision);\n\n\t\tlet trail = this.provenance.features.get(params.featureId);\n\t\tif (!trail) {\n\t\t\ttrail = {\n\t\t\t\tfeatureId: params.featureId,\n\t\t\t\tfinalState: \"not-configured\",\n\t\t\t\tallDecisions: [],\n\t\t\t\texplanation: \"\",\n\t\t\t};\n\t\t\tthis.provenance.features.set(params.featureId, trail);\n\t\t}\n\t\ttrail.allDecisions.push(decision);\n\n\t\t// \"advisory\" doesn't change finalState — it preserves the existing\n\t\t// blocked/enabled state and only flags a documented conflict.\n\t\tif (params.action === \"advisory\") {\n\t\t\tif (trail.finalState === \"not-configured\") {\n\t\t\t\ttrail.finalState = \"advisory-only\";\n\t\t\t}\n\t\t} else if (params.action !== \"skip\") {\n\t\t\tconst isWinning =\n\t\t\t\t!trail.winningDecision ||\n\t\t\t\tdecision.precedence < trail.winningDecision.precedence;\n\t\t\tif (isWinning) {\n\t\t\t\ttrail.winningDecision = decision;\n\t\t\t\ttrail.finalState = decision.action === \"enable\" ? \"enabled\" : \"blocked\";\n\t\t\t}\n\t\t}\n\n\t\tthis.provenance.summary.bySource[params.sourceType] =\n\t\t\t(this.provenance.summary.bySource[params.sourceType] || 0) + 1;\n\t\tthis.provenance.summary.byRule[params.rule] =\n\t\t\t(this.provenance.summary.byRule[params.rule] || 0) + 1;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Reconcile every feature's `finalState` against the post-pipeline\n\t * candidate set.\n\t *\n\t * The eager `finalState` updates inside `addDecision` track the\n\t * highest-precedence non-skip decision per feature, but a tool's\n\t * *actual* visibility is only known after step 6 of the\n\t * composition pipeline — earlier decisions can be reversed by\n\t * later host gates, PNP/profile gates, or custom sources. This method\n\t * walks every feature trail and rewrites `finalState` from the\n\t * final candidate set so callers can rely on\n\t * `provenance.features.get(toolId)?.finalState` as the canonical\n\t * \"is this tool visible right now?\" answer (M8 design § 4 + § 12).\n\t *\n\t * Semantics applied per feature:\n\t * - In `survivingIds` → \"enabled\"\n\t * - Not in `survivingIds`, has any non-skip decision → \"blocked\"\n\t * - Not in `survivingIds`, only advisory decisions → \"advisory-only\"\n\t * - Otherwise → \"not-configured\"\n\t *\n\t * Surviving features without any logged decisions get a synthetic\n\t * \"enabled\" trail so the provenance is dense enough for hosts that\n\t * iterate `provenance.features` to find the visible set.\n\t */\n\treconcileFinalStates(survivingIds: ReadonlySet<string>): this {\n\t\tfor (const featureId of survivingIds) {\n\t\t\tlet trail = this.provenance.features.get(featureId);\n\t\t\tif (!trail) {\n\t\t\t\ttrail = {\n\t\t\t\t\tfeatureId,\n\t\t\t\t\tfinalState: \"enabled\",\n\t\t\t\t\tallDecisions: [],\n\t\t\t\t\texplanation: \"\",\n\t\t\t\t};\n\t\t\t\tthis.provenance.features.set(featureId, trail);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttrail.finalState = \"enabled\";\n\t\t}\n\n\t\tfor (const trail of this.provenance.features.values()) {\n\t\t\tif (survivingIds.has(trail.featureId)) continue;\n\t\t\tconst hasNonSkip = trail.allDecisions.some(\n\t\t\t\t(d) => d.action !== \"skip\" && d.action !== \"advisory\",\n\t\t\t);\n\t\t\tconst hasAdvisory = trail.allDecisions.some(\n\t\t\t\t(d) => d.action === \"advisory\",\n\t\t\t);\n\t\t\tif (hasNonSkip) {\n\t\t\t\ttrail.finalState = \"blocked\";\n\t\t\t} else if (hasAdvisory) {\n\t\t\t\ttrail.finalState = \"advisory-only\";\n\t\t\t} else {\n\t\t\t\ttrail.finalState = \"not-configured\";\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tbuild(): ToolPolicyProvenance {\n\t\tfor (const trail of this.provenance.features.values()) {\n\t\t\ttrail.explanation = generateExplanation(trail);\n\t\t}\n\t\tfor (const trail of this.provenance.features.values()) {\n\t\t\tthis.provenance.summary.totalFeatures++;\n\t\t\tif (trail.finalState === \"enabled\") {\n\t\t\t\tthis.provenance.summary.enabled++;\n\t\t\t} else if (trail.finalState === \"blocked\") {\n\t\t\t\tthis.provenance.summary.blocked++;\n\t\t\t} else {\n\t\t\t\tthis.provenance.summary.notConfigured++;\n\t\t\t}\n\t\t}\n\t\treturn this.provenance;\n\t}\n}\n\nfunction generateExplanation(trail: ToolPolicyFeatureTrail): string {\n\tif (!trail.winningDecision) {\n\t\tif (trail.finalState === \"advisory-only\") {\n\t\t\tconst advisory = trail.allDecisions.find((d) => d.action === \"advisory\");\n\t\t\treturn advisory\n\t\t\t\t? `Feature \"${trail.featureId}\" was kept in its host-decided state; ${advisory.reason}`\n\t\t\t\t: `Feature \"${trail.featureId}\" carries an advisory note.`;\n\t\t}\n\t\treturn `Feature \"${trail.featureId}\" was not configured at any level.`;\n\t}\n\n\tconst decision = trail.winningDecision;\n\tconst sourceName = decision.source.name || decision.source.type;\n\tlet explanation = `Feature \"${trail.featureId}\" is ${trail.finalState}.\\n\\n`;\n\texplanation += `**Primary Reason** (${decision.rule}):\\n`;\n\texplanation += `${decision.reason}\\n`;\n\texplanation += `Source: ${sourceName} (${decision.source.type})\\n`;\n\tconst overridden = trail.allDecisions.filter(\n\t\t(d) =>\n\t\t\td.step !== decision.step &&\n\t\t\td.action !== \"skip\" &&\n\t\t\td.action !== \"advisory\" &&\n\t\t\td.precedence > decision.precedence,\n\t);\n\tif (overridden.length > 0) {\n\t\texplanation += `\\n**Overridden Rules**:\\n`;\n\t\tfor (const d of overridden) {\n\t\t\texplanation += `- ${d.rule}: ${d.reason}\\n`;\n\t\t}\n\t}\n\treturn explanation;\n}\n"]}
@@ -290,7 +290,7 @@ export class SectionRuntimeEngine {
290
290
  }
291
291
  getCanonicalItemId(itemId) {
292
292
  const map = this.registry.getCanonicalIdMap();
293
- return map[itemId] || this.controller?.getCanonicalItemId?.(itemId) || itemId;
293
+ return (map[itemId] || this.controller?.getCanonicalItemId?.(itemId) || itemId);
294
294
  }
295
295
  handleContentRegistered(detail) {
296
296
  this.controller?.handleContentRegistered?.({
@@ -1 +1 @@
1
- {"version":3,"file":"SectionRuntimeEngine.js","sourceRoot":"","sources":["../../src/runtime/SectionRuntimeEngine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Section runtime engine — public facade (M7 — Variant C, layered).\n *\n * The facade is the narrow, stable entry point hosts use to mount,\n * drive, and dispose a section runtime. It composes three layers\n * introduced in earlier M7 PRs:\n *\n * - the **registry** (`RuntimeRegistry`) — registered item/passage\n * shells in document order, used for canonical-id lookup;\n * - the **adapter** (`SectionEngineAdapter`) — single I/O seam over\n * the pure FSM core, fanning outputs to the DOM, framework-error\n * bus, instrumentation hook, and host subscribers;\n * - the **resolver** (`resolveSectionEngineRuntimeState`) — the\n * toolkit-side resolution helper that produces the effective\n * runtime + tools snapshot a host feeds to the FSM core.\n *\n * The facade exposes an engine-side surface for stage/lifecycle inputs and a\n * controller-facing surface for item registration, session updates, and host\n * controller commands:\n *\n * 1. The **engine-side** surface (`attachHost`, `dispatchInput`,\n * `subscribe`, `getState`, `getEffectiveRuntime`,\n * `setInstrumentationHook`). This is what the kernel and the\n * `pie-assessment-toolkit` CE will switch onto in M7 PR 5 and\n * PR 6. Construction is lazy: `attachHost(...)` builds the\n * adapter on first call, with the supplied host element,\n * framework-error bus, and (optional) coordinator. After\n * construction, host re-attachments (e.g. cohort change with a\n * new layout shell) update the adapter's host element via\n * `setHost(...)`.\n *\n * 2. The **controller-side** surface (`initialize`,\n * `register`, `unregister`, `handleContent*`, `updateItemSession`,\n * `navigateToItem`, `persist`, `hydrate`, `dispose`). The\n * `PieAssessmentToolkit.svelte` CE drives section-controller and\n * item-shell events through this surface.\n *\n * The two surfaces share `RuntimeRegistry` and the resolved\n * `SectionControllerHandle`.\n */\n\nimport type { ToolkitCoordinator } from \"../services/ToolkitCoordinator.js\";\nimport type { FrameworkErrorReporter } from \"../services/framework-error-bus.js\";\nimport type {\n\tSectionControllerEvent,\n\tSectionControllerHandle,\n} from \"../services/section-controller-types.js\";\nimport {\n\tSectionEngineAdapter,\n\ttype SectionEngineAdapterOptions,\n} from \"./adapter/SectionEngineAdapter.js\";\nimport type { InstrumentationHook } from \"./adapter/instrumentation-bridge.js\";\nimport type { EngineOutputListener } from \"./adapter/subscriber-fanout.js\";\nimport type { SectionEngineInput } from \"./core/engine-input.js\";\nimport type { SectionEngineOutput } from \"./core/engine-output.js\";\nimport {\n\tresolveSectionEngineRuntimeState,\n\ttype EffectiveRuntime,\n\ttype RuntimeInputs,\n} from \"./core/engine-resolver.js\";\nimport {\n\tcreateInitialEngineState,\n\ttype SectionEngineState,\n} from \"./core/engine-state.js\";\nimport type { RuntimeRegistrationDetail } from \"./registration-events.js\";\nimport { RuntimeRegistry } from \"./RuntimeRegistry.js\";\nimport { createRuntimeId } from \"./runtime-id.js\";\n\n/**\n * Structural view of the resolved section controller, widened with the\n * extra methods the toolkit's runtime CE calls directly. Optional so\n * stub controllers used in tests do not need every entry point.\n */\ninterface RuntimeController extends SectionControllerHandle {\n\tgetCompositionModel?: () => unknown;\n\tgetCanonicalItemId?: (itemId: string) => string;\n\thandleContentLoaded?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\tdetail?: unknown;\n\t\ttimestamp?: number;\n\t}) => void;\n\thandleContentRegistered?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t}) => void;\n\thandleContentUnregistered?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t}) => void;\n\thandleItemPlayerError?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\terror: unknown;\n\t\ttimestamp?: number;\n\t}) => void;\n\treportSectionError?: (args: {\n\t\tsource: \"item-player\" | \"section-runtime\" | \"toolkit\" | \"controller\";\n\t\terror: unknown;\n\t\titemId?: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\ttimestamp?: number;\n\t}) => void;\n\tupdateItemSession?: (\n\t\titemId: string,\n\t\tsessionDetail: unknown,\n\t) => { eventDetail?: unknown } | null;\n\tsubscribe?: (listener: (event: SectionControllerEvent) => void) => () => void;\n\tnavigateToItem?: (index: number) => unknown;\n}\n\n/**\n * Initialize args used by the toolkit CE to resolve the coordinator-backed\n * section controller.\n */\ninterface EngineInitArgs {\n\tcoordinator: ToolkitCoordinator;\n\tsection: unknown;\n\tsectionId: string;\n\tassessmentId: string;\n\tview: string;\n\tattemptId?: string;\n\tcreateDefaultController: () => Promise<RuntimeController> | RuntimeController;\n\tonCompositionChanged?: (composition: unknown) => void;\n}\n\n/**\n * Engine-side `attachHost` args. The host element, framework-error bus,\n * and `sourceCe` together let the adapter dispatch DOM events and bus\n * fan-outs consistently with the kernel emit chain.\n */\nexport interface SectionRuntimeEngineHostArgs {\n\thost: EventTarget;\n\tsourceCe: string;\n\tframeworkErrorBus: FrameworkErrorReporter;\n\tcoordinator?: SectionEngineAdapterOptions[\"coordinator\"];\n\tinstrumentationHook?: InstrumentationHook;\n\tnow?: () => string;\n}\n\nexport class SectionRuntimeEngine {\n\tprivate readonly registry = new RuntimeRegistry();\n\tprivate readonly runtimeId = createRuntimeId(\"section-engine\");\n\n\t// Engine-side state (PR 3+).\n\tprivate adapter: SectionEngineAdapter | null = null;\n\n\t// Controller-side state.\n\tprivate controller: RuntimeController | null = null;\n\tprivate coordinator: ToolkitCoordinator | null = null;\n\tprivate sectionId = \"\";\n\tprivate attemptId: string | undefined;\n\tprivate unsubscribeController: (() => void) | null = null;\n\tprivate activeInitToken = 0;\n\n\t/**\n\t * Tracks which `(canonicalItemId, contentKind)` pairs have already\n\t * fired `handleContentLoaded` on this engine. Mirrored alongside\n\t * `RuntimeRegistry`'s registered set so a cohort handoff can\n\t * replay the persistent shells' loaded state into the new\n\t * controller — see `replayRegisteredShellsIntoController` and the\n\t * PIE-512 Phase B regression test.\n\t *\n\t * Cleared in lockstep with `handleContentUnregistered` and on\n\t * `dispose`. Not exposed publicly: the registry alone is the\n\t * external surface; the loaded set exists only to seed cohort B's\n\t * controller with the live state cohort A's shells produced.\n\t */\n\tprivate readonly loadedRenderableKeys = new Set<string>();\n\n\t// ============================================================\n\t// Engine-side surface (PR 3+; driven by the kernel from PR 5,\n\t// by the toolkit CE from PR 6, and by the facade smoke test today).\n\t// ============================================================\n\n\t/**\n\t * Attach the host element + framework-error bus + sourceCe so the\n\t * adapter can dispatch DOM events and bus errors. Required before\n\t * `dispatchInput` / `subscribe` produce observable effects.\n\t *\n\t * Constructs the adapter on the first call. Subsequent calls keep\n\t * the adapter and update its host element / instrumentation hook\n\t * (used by layout-shell rollovers and instrumentation reconfig).\n\t */\n\tattachHost(args: SectionRuntimeEngineHostArgs): void {\n\t\tif (this.adapter) {\n\t\t\tthis.adapter.setHost(args.host);\n\t\t\tif (args.instrumentationHook !== undefined) {\n\t\t\t\tthis.adapter.setInstrumentationHook(args.instrumentationHook);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.adapter = new SectionEngineAdapter({\n\t\t\thost: args.host,\n\t\t\truntimeId: this.runtimeId,\n\t\t\tsourceCe: args.sourceCe,\n\t\t\tframeworkErrorBus: args.frameworkErrorBus,\n\t\t\tcoordinator: args.coordinator,\n\t\t\tinstrumentationHook: args.instrumentationHook,\n\t\t\tnow: args.now,\n\t\t});\n\t}\n\n\t/**\n\t * Forward a host-constructed input to the FSM core via the adapter.\n\t * Returns the outputs the transition produced (subscribers and the\n\t * DOM/framework-error/instrumentation bridges have already\n\t * received them).\n\t *\n\t * No-op (returns `[]`) before `attachHost(...)` so callers that\n\t * dispatch optimistically during teardown do not throw.\n\t */\n\tdispatchInput(input: SectionEngineInput): readonly SectionEngineOutput[] {\n\t\treturn this.adapter?.dispatchInput(input) ?? [];\n\t}\n\n\t/**\n\t * Subscribe to batched engine outputs (one batch per\n\t * `dispatchInput`). Returns an idempotent disposer. Pre-`attachHost`\n\t * subscriptions return a no-op disposer so callers can wire\n\t * subscriptions early without lifecycle-ordering hazards.\n\t */\n\tsubscribe(listener: EngineOutputListener): () => void {\n\t\treturn this.adapter?.subscribe(listener) ?? noopDispose;\n\t}\n\n\t/**\n\t * Read-only snapshot of the FSM state. Returns the initial idle\n\t * state before `attachHost` so callers can probe state without\n\t * special-casing the pre-attach phase.\n\t */\n\tgetState(): Readonly<SectionEngineState> {\n\t\treturn this.adapter?.getState() ?? createInitialEngineState();\n\t}\n\n\t/**\n\t * Resolve the effective runtime + tools snapshot for the given\n\t * two-tier inputs. This is a pure function over the resolver — it\n\t * does not depend on adapter state — so callers can use it both\n\t * pre- and post-`attachHost`. The kernel uses it to seed\n\t * `dispatchInput({ kind: \"initialize\", effectiveRuntime, ... })`.\n\t */\n\tgetEffectiveRuntime<P>(\n\t\targs: RuntimeInputs,\n\t\tdeps: {\n\t\t\tresolvePlayerRuntime: (resolverArgs: {\n\t\t\t\teffectiveRuntime: Record<string, unknown>;\n\t\t\t\tplayerType: string;\n\t\t\t\tenv: Record<string, unknown> | null;\n\t\t\t}) => P;\n\t\t},\n\t): EffectiveRuntime {\n\t\treturn resolveSectionEngineRuntimeState(args, deps).effectiveRuntime;\n\t}\n\n\t/**\n\t * Update the adapter's instrumentation hook. No-op pre-attach.\n\t * Hosts that always want a hook should pass it via `attachHost`.\n\t */\n\tsetInstrumentationHook(hook: InstrumentationHook | undefined): void {\n\t\tthis.adapter?.setInstrumentationHook(hook);\n\t}\n\n\t/**\n\t * Stable per-engine runtime id used to scope DOM-event details and\n\t * registry telemetry. Exposed so tests and instrumentation can pin\n\t * the value the bridges emit.\n\t */\n\tgetRuntimeId(): string {\n\t\treturn this.runtimeId;\n\t}\n\n\t// ============================================================\n\t// Controller-side surface.\n\t// ============================================================\n\n\tasync initialize(args: EngineInitArgs): Promise<void> {\n\t\tthis.activeInitToken += 1;\n\t\tconst token = this.activeInitToken;\n\t\tthis.coordinator = args.coordinator;\n\t\tthis.sectionId = args.sectionId;\n\t\tthis.attemptId = args.attemptId;\n\n\t\tconst resolved = (await args.coordinator.getOrCreateSectionController({\n\t\t\tsectionId: args.sectionId,\n\t\t\tattemptId: args.attemptId,\n\t\t\tinput: {\n\t\t\t\tsection: args.section,\n\t\t\t\tsectionId: args.sectionId,\n\t\t\t\tassessmentId: args.assessmentId,\n\t\t\t\tview: args.view,\n\t\t\t},\n\t\t\tupdateExisting: true,\n\t\t\tcreateDefaultController: args.createDefaultController,\n\t\t})) as RuntimeController;\n\n\t\tif (token !== this.activeInitToken) return;\n\t\tthis.unsubscribeController?.();\n\t\tthis.controller = resolved;\n\t\t// PIE-512 Phase C: always re-feed the registry's currently\n\t\t// registered shells (and their loaded state) into the resolved\n\t\t// controller. We do NOT gate on `resolved !== previousController`\n\t\t// any more.\n\t\t//\n\t\t// Why the gate had to go:\n\t\t// - Cohort flip resolving to a fresh controller — replay seeds\n\t\t// the new controller, which is the original Phase B fix.\n\t\t// - Same-cohort `updateInput` resolving to the existing\n\t\t// controller — the coordinator's\n\t\t// `resolveExistingSectionController` calls\n\t\t// `existingController.updateInput(input)` (engine always\n\t\t// passes `updateExisting: true`), and pre-Phase-C\n\t\t// `SectionController.initialize` wiped lifecycle tracking\n\t\t// unconditionally. A subscriber attaching between the wipe\n\t\t// and the next live event saw an empty\n\t\t// `loadedRenderables` snapshot.\n\t\t//\n\t\t// Phase C makes this re-feed safe by combining (a) the\n\t\t// section-identity gate around `resetLifecycleTracking()` in\n\t\t// `SectionController.initialize` (so same-cohort `updateInput`\n\t\t// preserves tracking) with (b) idempotent\n\t\t// `handleContentRegistered` / `handleContentLoaded` on the\n\t\t// controller (so re-feeding the same registry entries is a\n\t\t// no-op if the controller already knows about them, but\n\t\t// re-seeds the controller in the post-`updateInput`-wipe case\n\t\t// that pre-Phase-C used to encounter).\n\t\tthis.replayRegisteredShellsIntoController(resolved);\n\t\targs.onCompositionChanged?.(resolved.getCompositionModel?.());\n\t\tthis.unsubscribeController =\n\t\t\tresolved.subscribe?.(() => {\n\t\t\t\targs.onCompositionChanged?.(resolved.getCompositionModel?.());\n\t\t\t}) || null;\n\t}\n\n\t/**\n\t * Re-feed the engine's `RuntimeRegistry` and loaded-set into the\n\t * resolved controller. Call site: `initialize(...)` — runs on\n\t * EVERY initialize, both cohort-flip-resolves-fresh-controller\n\t * and same-cohort-resolves-existing-controller cases. Phase C\n\t * dropped the `resolved !== previousController` gate; see the\n\t * comment at the call site for why.\n\t *\n\t * Two-pass order — register every shell in document order, then\n\t * issue `handleContentLoaded` for each shell whose load already\n\t * fired on this engine. The two-pass shape prevents\n\t * `evaluateSectionLoadingState` from flapping\n\t * `section-loading-complete` `false→true→false→…` while replay is\n\t * mid-walk: any subscriber wired before the engine's own\n\t * `controller.subscribe` (no such caller today, but cheap defense\n\t * for future wiring) sees one clean `false→true` transition.\n\t *\n\t * Idempotent on the controller side — Phase C makes\n\t * `SectionController.handleContentRegistered` and\n\t * `handleContentLoaded` early-return on duplicates so re-feeding\n\t * the same shells into a controller that already tracks them is\n\t * a true no-op (no spurious re-emits, no re-evaluation of\n\t * `section-loading-complete`). At the call site no listener is\n\t * attached during the replay window, so `emitChange` side effects\n\t * fire into a void on this pass anyway, but the controller-side\n\t * idempotence is what makes the replay safe to run on every\n\t * initialize regardless of whether the controller is fresh.\n\t */\n\tprivate replayRegisteredShellsIntoController(\n\t\tcontroller: RuntimeController,\n\t): void {\n\t\tif (!controller.handleContentRegistered) return;\n\t\tconst shells = this.registry.getOrderedShells();\n\t\tif (shells.length === 0) return;\n\t\tfor (const shell of shells) {\n\t\t\tconst canonicalItemId = shell.canonicalItemId || shell.itemId;\n\t\t\tcontroller.handleContentRegistered({\n\t\t\t\titemId: shell.itemId,\n\t\t\t\tcanonicalItemId,\n\t\t\t\tcontentKind: shell.contentKind || shell.kind,\n\t\t\t});\n\t\t}\n\t\tconst now = Date.now();\n\t\tfor (const shell of shells) {\n\t\t\tconst canonicalItemId = shell.canonicalItemId || shell.itemId;\n\t\t\tconst key = this.getLoadedKey(canonicalItemId, shell.contentKind);\n\t\t\tif (this.loadedRenderableKeys.has(key)) {\n\t\t\t\tcontroller.handleContentLoaded?.({\n\t\t\t\t\titemId: shell.itemId,\n\t\t\t\t\tcanonicalItemId,\n\t\t\t\t\tcontentKind: shell.contentKind || shell.kind,\n\t\t\t\t\ttimestamp: now,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stable key for the engine's `loadedRenderableKeys` set. Mirrors\n\t * the `(canonicalItemId, contentKind)` shape `SectionController`\n\t * uses internally (see `getRenderableKey`); we only need\n\t * consistent add/check semantics on this side, not byte-identical\n\t * normalization with the controller.\n\t */\n\tprivate getLoadedKey(\n\t\tcanonicalItemId: string,\n\t\tcontentKind: string | undefined,\n\t): string {\n\t\treturn `${contentKind ?? \"\"}:${canonicalItemId}`;\n\t}\n\n\tregister(detail: RuntimeRegistrationDetail): boolean {\n\t\treturn this.registry.register(detail);\n\t}\n\n\tunregister(element: HTMLElement): boolean {\n\t\treturn this.registry.unregister(element);\n\t}\n\n\tgetCompositionModel(): unknown {\n\t\treturn this.controller?.getCompositionModel?.() ?? null;\n\t}\n\n\tgetCanonicalItemId(itemId: string): string {\n\t\tconst map = this.registry.getCanonicalIdMap();\n\t\treturn map[itemId] || this.controller?.getCanonicalItemId?.(itemId) || itemId;\n\t}\n\n\thandleContentRegistered(detail: RuntimeRegistrationDetail): void {\n\t\tthis.controller?.handleContentRegistered?.({\n\t\t\titemId: detail.itemId,\n\t\t\tcanonicalItemId: detail.canonicalItemId || detail.itemId,\n\t\t\tcontentKind: detail.contentKind || detail.kind,\n\t\t});\n\t}\n\n\thandleContentUnregistered(detail: RuntimeRegistrationDetail): void {\n\t\tconst canonicalItemId = detail.canonicalItemId || detail.itemId;\n\t\t// Key the load-set delete with the same `contentKind`-only\n\t\t// shape that `handleContentLoaded` and\n\t\t// `replayRegisteredShellsIntoController` use, so add/check/\n\t\t// delete keys round-trip identically. The `|| detail.kind`\n\t\t// fallback is preserved for the controller-forwarded payload\n\t\t// because the controller normalizes via `toSectionContentKind`\n\t\t// and the `kind` field remains meaningful there.\n\t\tthis.loadedRenderableKeys.delete(\n\t\t\tthis.getLoadedKey(canonicalItemId, detail.contentKind),\n\t\t);\n\t\tthis.controller?.handleContentUnregistered?.({\n\t\t\titemId: detail.itemId,\n\t\t\tcanonicalItemId,\n\t\t\tcontentKind: detail.contentKind || detail.kind,\n\t\t});\n\t}\n\n\thandleContentLoaded(args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\tdetail?: unknown;\n\t\ttimestamp?: number;\n\t}): void {\n\t\tconst canonicalItemId = args.canonicalItemId || args.itemId;\n\t\tthis.loadedRenderableKeys.add(\n\t\t\tthis.getLoadedKey(canonicalItemId, args.contentKind),\n\t\t);\n\t\tthis.controller?.handleContentLoaded?.(args);\n\t}\n\n\thandleItemPlayerError(args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\terror: unknown;\n\t\ttimestamp?: number;\n\t}): void {\n\t\tthis.controller?.handleItemPlayerError?.(args);\n\t}\n\n\treportSectionError(args: {\n\t\tsource: \"item-player\" | \"section-runtime\" | \"toolkit\" | \"controller\";\n\t\terror: unknown;\n\t\titemId?: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\ttimestamp?: number;\n\t}): void {\n\t\tthis.controller?.reportSectionError?.(args);\n\t}\n\n\tupdateItemSession(itemId: string, session: unknown): unknown {\n\t\tconst canonicalId = this.getCanonicalItemId(itemId);\n\t\treturn this.controller?.updateItemSession?.(canonicalId, session) ?? null;\n\t}\n\n\tnavigateToItem(index: number): unknown {\n\t\treturn this.controller?.navigateToItem?.(index) ?? null;\n\t}\n\n\tasync persist(): Promise<void> {\n\t\tawait this.controller?.persist?.();\n\t}\n\n\tasync hydrate(): Promise<void> {\n\t\tawait this.controller?.hydrate?.();\n\t}\n\n\tgetRegistry(): RuntimeRegistry {\n\t\treturn this.registry;\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.activeInitToken += 1;\n\t\tthis.unsubscribeController?.();\n\t\tthis.unsubscribeController = null;\n\t\tif (this.coordinator && this.sectionId) {\n\t\t\tawait this.coordinator.disposeSectionController({\n\t\t\t\tsectionId: this.sectionId,\n\t\t\t\tattemptId: this.attemptId,\n\t\t\t});\n\t\t}\n\t\tthis.registry.clear();\n\t\tthis.loadedRenderableKeys.clear();\n\t\tthis.controller = null;\n\t\tthis.coordinator = null;\n\t\t// Tear down the engine-side adapter (if attached) last so any\n\t\t// `dispose` FSM input flows through the bridges before they\n\t\t// detach. Adapter disposal is idempotent and safe even when\n\t\t// nothing is attached.\n\t\tif (this.adapter) {\n\t\t\tconst adapter = this.adapter;\n\t\t\tthis.adapter = null;\n\t\t\tawait adapter.dispose();\n\t\t}\n\t}\n}\n\nconst noopDispose = (): void => {};\n"]}
1
+ {"version":3,"file":"SectionRuntimeEngine.js","sourceRoot":"","sources":["../../src/runtime/SectionRuntimeEngine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Section runtime engine — public facade (M7 — Variant C, layered).\n *\n * The facade is the narrow, stable entry point hosts use to mount,\n * drive, and dispose a section runtime. It composes three layers\n * introduced in earlier M7 PRs:\n *\n * - the **registry** (`RuntimeRegistry`) — registered item/passage\n * shells in document order, used for canonical-id lookup;\n * - the **adapter** (`SectionEngineAdapter`) — single I/O seam over\n * the pure FSM core, fanning outputs to the DOM, framework-error\n * bus, instrumentation hook, and host subscribers;\n * - the **resolver** (`resolveSectionEngineRuntimeState`) — the\n * toolkit-side resolution helper that produces the effective\n * runtime + tools snapshot a host feeds to the FSM core.\n *\n * The facade exposes an engine-side surface for stage/lifecycle inputs and a\n * controller-facing surface for item registration, session updates, and host\n * controller commands:\n *\n * 1. The **engine-side** surface (`attachHost`, `dispatchInput`,\n * `subscribe`, `getState`, `getEffectiveRuntime`,\n * `setInstrumentationHook`). This is what the kernel and the\n * `pie-assessment-toolkit` CE will switch onto in M7 PR 5 and\n * PR 6. Construction is lazy: `attachHost(...)` builds the\n * adapter on first call, with the supplied host element,\n * framework-error bus, and (optional) coordinator. After\n * construction, host re-attachments (e.g. cohort change with a\n * new layout shell) update the adapter's host element via\n * `setHost(...)`.\n *\n * 2. The **controller-side** surface (`initialize`,\n * `register`, `unregister`, `handleContent*`, `updateItemSession`,\n * `navigateToItem`, `persist`, `hydrate`, `dispose`). The\n * `PieAssessmentToolkit.svelte` CE drives section-controller and\n * item-shell events through this surface.\n *\n * The two surfaces share `RuntimeRegistry` and the resolved\n * `SectionControllerHandle`.\n */\n\nimport type { ToolkitCoordinator } from \"../services/ToolkitCoordinator.js\";\nimport type { FrameworkErrorReporter } from \"../services/framework-error-bus.js\";\nimport type {\n\tSectionControllerEvent,\n\tSectionControllerHandle,\n} from \"../services/section-controller-types.js\";\nimport {\n\tSectionEngineAdapter,\n\ttype SectionEngineAdapterOptions,\n} from \"./adapter/SectionEngineAdapter.js\";\nimport type { InstrumentationHook } from \"./adapter/instrumentation-bridge.js\";\nimport type { EngineOutputListener } from \"./adapter/subscriber-fanout.js\";\nimport type { SectionEngineInput } from \"./core/engine-input.js\";\nimport type { SectionEngineOutput } from \"./core/engine-output.js\";\nimport {\n\tresolveSectionEngineRuntimeState,\n\ttype EffectiveRuntime,\n\ttype RuntimeInputs,\n} from \"./core/engine-resolver.js\";\nimport {\n\tcreateInitialEngineState,\n\ttype SectionEngineState,\n} from \"./core/engine-state.js\";\nimport type { RuntimeRegistrationDetail } from \"./registration-events.js\";\nimport { RuntimeRegistry } from \"./RuntimeRegistry.js\";\nimport { createRuntimeId } from \"./runtime-id.js\";\n\n/**\n * Structural view of the resolved section controller, widened with the\n * extra methods the toolkit's runtime CE calls directly. Optional so\n * stub controllers used in tests do not need every entry point.\n */\ninterface RuntimeController extends SectionControllerHandle {\n\tgetCompositionModel?: () => unknown;\n\tgetCanonicalItemId?: (itemId: string) => string;\n\thandleContentLoaded?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\tdetail?: unknown;\n\t\ttimestamp?: number;\n\t}) => void;\n\thandleContentRegistered?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t}) => void;\n\thandleContentUnregistered?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t}) => void;\n\thandleItemPlayerError?: (args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\terror: unknown;\n\t\ttimestamp?: number;\n\t}) => void;\n\treportSectionError?: (args: {\n\t\tsource: \"item-player\" | \"section-runtime\" | \"toolkit\" | \"controller\";\n\t\terror: unknown;\n\t\titemId?: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\ttimestamp?: number;\n\t}) => void;\n\tupdateItemSession?: (\n\t\titemId: string,\n\t\tsessionDetail: unknown,\n\t) => { eventDetail?: unknown } | null;\n\tsubscribe?: (listener: (event: SectionControllerEvent) => void) => () => void;\n\tnavigateToItem?: (index: number) => unknown;\n}\n\n/**\n * Initialize args used by the toolkit CE to resolve the coordinator-backed\n * section controller.\n */\ninterface EngineInitArgs {\n\tcoordinator: ToolkitCoordinator;\n\tsection: unknown;\n\tsectionId: string;\n\tassessmentId: string;\n\tview: string;\n\tattemptId?: string;\n\tcreateDefaultController: () => Promise<RuntimeController> | RuntimeController;\n\tonCompositionChanged?: (composition: unknown) => void;\n}\n\n/**\n * Engine-side `attachHost` args. The host element, framework-error bus,\n * and `sourceCe` together let the adapter dispatch DOM events and bus\n * fan-outs consistently with the kernel emit chain.\n */\nexport interface SectionRuntimeEngineHostArgs {\n\thost: EventTarget;\n\tsourceCe: string;\n\tframeworkErrorBus: FrameworkErrorReporter;\n\tcoordinator?: SectionEngineAdapterOptions[\"coordinator\"];\n\tinstrumentationHook?: InstrumentationHook;\n\tnow?: () => string;\n}\n\nexport class SectionRuntimeEngine {\n\tprivate readonly registry = new RuntimeRegistry();\n\tprivate readonly runtimeId = createRuntimeId(\"section-engine\");\n\n\t// Engine-side state (PR 3+).\n\tprivate adapter: SectionEngineAdapter | null = null;\n\n\t// Controller-side state.\n\tprivate controller: RuntimeController | null = null;\n\tprivate coordinator: ToolkitCoordinator | null = null;\n\tprivate sectionId = \"\";\n\tprivate attemptId: string | undefined;\n\tprivate unsubscribeController: (() => void) | null = null;\n\tprivate activeInitToken = 0;\n\n\t/**\n\t * Tracks which `(canonicalItemId, contentKind)` pairs have already\n\t * fired `handleContentLoaded` on this engine. Mirrored alongside\n\t * `RuntimeRegistry`'s registered set so a cohort handoff can\n\t * replay the persistent shells' loaded state into the new\n\t * controller — see `replayRegisteredShellsIntoController` and the\n\t * PIE-512 Phase B regression test.\n\t *\n\t * Cleared in lockstep with `handleContentUnregistered` and on\n\t * `dispose`. Not exposed publicly: the registry alone is the\n\t * external surface; the loaded set exists only to seed cohort B's\n\t * controller with the live state cohort A's shells produced.\n\t */\n\tprivate readonly loadedRenderableKeys = new Set<string>();\n\n\t// ============================================================\n\t// Engine-side surface (PR 3+; driven by the kernel from PR 5,\n\t// by the toolkit CE from PR 6, and by the facade smoke test today).\n\t// ============================================================\n\n\t/**\n\t * Attach the host element + framework-error bus + sourceCe so the\n\t * adapter can dispatch DOM events and bus errors. Required before\n\t * `dispatchInput` / `subscribe` produce observable effects.\n\t *\n\t * Constructs the adapter on the first call. Subsequent calls keep\n\t * the adapter and update its host element / instrumentation hook\n\t * (used by layout-shell rollovers and instrumentation reconfig).\n\t */\n\tattachHost(args: SectionRuntimeEngineHostArgs): void {\n\t\tif (this.adapter) {\n\t\t\tthis.adapter.setHost(args.host);\n\t\t\tif (args.instrumentationHook !== undefined) {\n\t\t\t\tthis.adapter.setInstrumentationHook(args.instrumentationHook);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.adapter = new SectionEngineAdapter({\n\t\t\thost: args.host,\n\t\t\truntimeId: this.runtimeId,\n\t\t\tsourceCe: args.sourceCe,\n\t\t\tframeworkErrorBus: args.frameworkErrorBus,\n\t\t\tcoordinator: args.coordinator,\n\t\t\tinstrumentationHook: args.instrumentationHook,\n\t\t\tnow: args.now,\n\t\t});\n\t}\n\n\t/**\n\t * Forward a host-constructed input to the FSM core via the adapter.\n\t * Returns the outputs the transition produced (subscribers and the\n\t * DOM/framework-error/instrumentation bridges have already\n\t * received them).\n\t *\n\t * No-op (returns `[]`) before `attachHost(...)` so callers that\n\t * dispatch optimistically during teardown do not throw.\n\t */\n\tdispatchInput(input: SectionEngineInput): readonly SectionEngineOutput[] {\n\t\treturn this.adapter?.dispatchInput(input) ?? [];\n\t}\n\n\t/**\n\t * Subscribe to batched engine outputs (one batch per\n\t * `dispatchInput`). Returns an idempotent disposer. Pre-`attachHost`\n\t * subscriptions return a no-op disposer so callers can wire\n\t * subscriptions early without lifecycle-ordering hazards.\n\t */\n\tsubscribe(listener: EngineOutputListener): () => void {\n\t\treturn this.adapter?.subscribe(listener) ?? noopDispose;\n\t}\n\n\t/**\n\t * Read-only snapshot of the FSM state. Returns the initial idle\n\t * state before `attachHost` so callers can probe state without\n\t * special-casing the pre-attach phase.\n\t */\n\tgetState(): Readonly<SectionEngineState> {\n\t\treturn this.adapter?.getState() ?? createInitialEngineState();\n\t}\n\n\t/**\n\t * Resolve the effective runtime + tools snapshot for the given\n\t * two-tier inputs. This is a pure function over the resolver — it\n\t * does not depend on adapter state — so callers can use it both\n\t * pre- and post-`attachHost`. The kernel uses it to seed\n\t * `dispatchInput({ kind: \"initialize\", effectiveRuntime, ... })`.\n\t */\n\tgetEffectiveRuntime<P>(\n\t\targs: RuntimeInputs,\n\t\tdeps: {\n\t\t\tresolvePlayerRuntime: (resolverArgs: {\n\t\t\t\teffectiveRuntime: Record<string, unknown>;\n\t\t\t\tplayerType: string;\n\t\t\t\tenv: Record<string, unknown> | null;\n\t\t\t}) => P;\n\t\t},\n\t): EffectiveRuntime {\n\t\treturn resolveSectionEngineRuntimeState(args, deps).effectiveRuntime;\n\t}\n\n\t/**\n\t * Update the adapter's instrumentation hook. No-op pre-attach.\n\t * Hosts that always want a hook should pass it via `attachHost`.\n\t */\n\tsetInstrumentationHook(hook: InstrumentationHook | undefined): void {\n\t\tthis.adapter?.setInstrumentationHook(hook);\n\t}\n\n\t/**\n\t * Stable per-engine runtime id used to scope DOM-event details and\n\t * registry telemetry. Exposed so tests and instrumentation can pin\n\t * the value the bridges emit.\n\t */\n\tgetRuntimeId(): string {\n\t\treturn this.runtimeId;\n\t}\n\n\t// ============================================================\n\t// Controller-side surface.\n\t// ============================================================\n\n\tasync initialize(args: EngineInitArgs): Promise<void> {\n\t\tthis.activeInitToken += 1;\n\t\tconst token = this.activeInitToken;\n\t\tthis.coordinator = args.coordinator;\n\t\tthis.sectionId = args.sectionId;\n\t\tthis.attemptId = args.attemptId;\n\n\t\tconst resolved = (await args.coordinator.getOrCreateSectionController({\n\t\t\tsectionId: args.sectionId,\n\t\t\tattemptId: args.attemptId,\n\t\t\tinput: {\n\t\t\t\tsection: args.section,\n\t\t\t\tsectionId: args.sectionId,\n\t\t\t\tassessmentId: args.assessmentId,\n\t\t\t\tview: args.view,\n\t\t\t},\n\t\t\tupdateExisting: true,\n\t\t\tcreateDefaultController: args.createDefaultController,\n\t\t})) as RuntimeController;\n\n\t\tif (token !== this.activeInitToken) return;\n\t\tthis.unsubscribeController?.();\n\t\tthis.controller = resolved;\n\t\t// PIE-512 Phase C: always re-feed the registry's currently\n\t\t// registered shells (and their loaded state) into the resolved\n\t\t// controller. We do NOT gate on `resolved !== previousController`\n\t\t// any more.\n\t\t//\n\t\t// Why the gate had to go:\n\t\t// - Cohort flip resolving to a fresh controller — replay seeds\n\t\t// the new controller, which is the original Phase B fix.\n\t\t// - Same-cohort `updateInput` resolving to the existing\n\t\t// controller — the coordinator's\n\t\t// `resolveExistingSectionController` calls\n\t\t// `existingController.updateInput(input)` (engine always\n\t\t// passes `updateExisting: true`), and pre-Phase-C\n\t\t// `SectionController.initialize` wiped lifecycle tracking\n\t\t// unconditionally. A subscriber attaching between the wipe\n\t\t// and the next live event saw an empty\n\t\t// `loadedRenderables` snapshot.\n\t\t//\n\t\t// Phase C makes this re-feed safe by combining (a) the\n\t\t// section-identity gate around `resetLifecycleTracking()` in\n\t\t// `SectionController.initialize` (so same-cohort `updateInput`\n\t\t// preserves tracking) with (b) idempotent\n\t\t// `handleContentRegistered` / `handleContentLoaded` on the\n\t\t// controller (so re-feeding the same registry entries is a\n\t\t// no-op if the controller already knows about them, but\n\t\t// re-seeds the controller in the post-`updateInput`-wipe case\n\t\t// that pre-Phase-C used to encounter).\n\t\tthis.replayRegisteredShellsIntoController(resolved);\n\t\targs.onCompositionChanged?.(resolved.getCompositionModel?.());\n\t\tthis.unsubscribeController =\n\t\t\tresolved.subscribe?.(() => {\n\t\t\t\targs.onCompositionChanged?.(resolved.getCompositionModel?.());\n\t\t\t}) || null;\n\t}\n\n\t/**\n\t * Re-feed the engine's `RuntimeRegistry` and loaded-set into the\n\t * resolved controller. Call site: `initialize(...)` — runs on\n\t * EVERY initialize, both cohort-flip-resolves-fresh-controller\n\t * and same-cohort-resolves-existing-controller cases. Phase C\n\t * dropped the `resolved !== previousController` gate; see the\n\t * comment at the call site for why.\n\t *\n\t * Two-pass order — register every shell in document order, then\n\t * issue `handleContentLoaded` for each shell whose load already\n\t * fired on this engine. The two-pass shape prevents\n\t * `evaluateSectionLoadingState` from flapping\n\t * `section-loading-complete` `false→true→false→…` while replay is\n\t * mid-walk: any subscriber wired before the engine's own\n\t * `controller.subscribe` (no such caller today, but cheap defense\n\t * for future wiring) sees one clean `false→true` transition.\n\t *\n\t * Idempotent on the controller side — Phase C makes\n\t * `SectionController.handleContentRegistered` and\n\t * `handleContentLoaded` early-return on duplicates so re-feeding\n\t * the same shells into a controller that already tracks them is\n\t * a true no-op (no spurious re-emits, no re-evaluation of\n\t * `section-loading-complete`). At the call site no listener is\n\t * attached during the replay window, so `emitChange` side effects\n\t * fire into a void on this pass anyway, but the controller-side\n\t * idempotence is what makes the replay safe to run on every\n\t * initialize regardless of whether the controller is fresh.\n\t */\n\tprivate replayRegisteredShellsIntoController(\n\t\tcontroller: RuntimeController,\n\t): void {\n\t\tif (!controller.handleContentRegistered) return;\n\t\tconst shells = this.registry.getOrderedShells();\n\t\tif (shells.length === 0) return;\n\t\tfor (const shell of shells) {\n\t\t\tconst canonicalItemId = shell.canonicalItemId || shell.itemId;\n\t\t\tcontroller.handleContentRegistered({\n\t\t\t\titemId: shell.itemId,\n\t\t\t\tcanonicalItemId,\n\t\t\t\tcontentKind: shell.contentKind || shell.kind,\n\t\t\t});\n\t\t}\n\t\tconst now = Date.now();\n\t\tfor (const shell of shells) {\n\t\t\tconst canonicalItemId = shell.canonicalItemId || shell.itemId;\n\t\t\tconst key = this.getLoadedKey(canonicalItemId, shell.contentKind);\n\t\t\tif (this.loadedRenderableKeys.has(key)) {\n\t\t\t\tcontroller.handleContentLoaded?.({\n\t\t\t\t\titemId: shell.itemId,\n\t\t\t\t\tcanonicalItemId,\n\t\t\t\t\tcontentKind: shell.contentKind || shell.kind,\n\t\t\t\t\ttimestamp: now,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stable key for the engine's `loadedRenderableKeys` set. Mirrors\n\t * the `(canonicalItemId, contentKind)` shape `SectionController`\n\t * uses internally (see `getRenderableKey`); we only need\n\t * consistent add/check semantics on this side, not byte-identical\n\t * normalization with the controller.\n\t */\n\tprivate getLoadedKey(\n\t\tcanonicalItemId: string,\n\t\tcontentKind: string | undefined,\n\t): string {\n\t\treturn `${contentKind ?? \"\"}:${canonicalItemId}`;\n\t}\n\n\tregister(detail: RuntimeRegistrationDetail): boolean {\n\t\treturn this.registry.register(detail);\n\t}\n\n\tunregister(element: HTMLElement): boolean {\n\t\treturn this.registry.unregister(element);\n\t}\n\n\tgetCompositionModel(): unknown {\n\t\treturn this.controller?.getCompositionModel?.() ?? null;\n\t}\n\n\tgetCanonicalItemId(itemId: string): string {\n\t\tconst map = this.registry.getCanonicalIdMap();\n\t\treturn (\n\t\t\tmap[itemId] || this.controller?.getCanonicalItemId?.(itemId) || itemId\n\t\t);\n\t}\n\n\thandleContentRegistered(detail: RuntimeRegistrationDetail): void {\n\t\tthis.controller?.handleContentRegistered?.({\n\t\t\titemId: detail.itemId,\n\t\t\tcanonicalItemId: detail.canonicalItemId || detail.itemId,\n\t\t\tcontentKind: detail.contentKind || detail.kind,\n\t\t});\n\t}\n\n\thandleContentUnregistered(detail: RuntimeRegistrationDetail): void {\n\t\tconst canonicalItemId = detail.canonicalItemId || detail.itemId;\n\t\t// Key the load-set delete with the same `contentKind`-only\n\t\t// shape that `handleContentLoaded` and\n\t\t// `replayRegisteredShellsIntoController` use, so add/check/\n\t\t// delete keys round-trip identically. The `|| detail.kind`\n\t\t// fallback is preserved for the controller-forwarded payload\n\t\t// because the controller normalizes via `toSectionContentKind`\n\t\t// and the `kind` field remains meaningful there.\n\t\tthis.loadedRenderableKeys.delete(\n\t\t\tthis.getLoadedKey(canonicalItemId, detail.contentKind),\n\t\t);\n\t\tthis.controller?.handleContentUnregistered?.({\n\t\t\titemId: detail.itemId,\n\t\t\tcanonicalItemId,\n\t\t\tcontentKind: detail.contentKind || detail.kind,\n\t\t});\n\t}\n\n\thandleContentLoaded(args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\tdetail?: unknown;\n\t\ttimestamp?: number;\n\t}): void {\n\t\tconst canonicalItemId = args.canonicalItemId || args.itemId;\n\t\tthis.loadedRenderableKeys.add(\n\t\t\tthis.getLoadedKey(canonicalItemId, args.contentKind),\n\t\t);\n\t\tthis.controller?.handleContentLoaded?.(args);\n\t}\n\n\thandleItemPlayerError(args: {\n\t\titemId: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\terror: unknown;\n\t\ttimestamp?: number;\n\t}): void {\n\t\tthis.controller?.handleItemPlayerError?.(args);\n\t}\n\n\treportSectionError(args: {\n\t\tsource: \"item-player\" | \"section-runtime\" | \"toolkit\" | \"controller\";\n\t\terror: unknown;\n\t\titemId?: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t\ttimestamp?: number;\n\t}): void {\n\t\tthis.controller?.reportSectionError?.(args);\n\t}\n\n\tupdateItemSession(itemId: string, session: unknown): unknown {\n\t\tconst canonicalId = this.getCanonicalItemId(itemId);\n\t\treturn this.controller?.updateItemSession?.(canonicalId, session) ?? null;\n\t}\n\n\tnavigateToItem(index: number): unknown {\n\t\treturn this.controller?.navigateToItem?.(index) ?? null;\n\t}\n\n\tasync persist(): Promise<void> {\n\t\tawait this.controller?.persist?.();\n\t}\n\n\tasync hydrate(): Promise<void> {\n\t\tawait this.controller?.hydrate?.();\n\t}\n\n\tgetRegistry(): RuntimeRegistry {\n\t\treturn this.registry;\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.activeInitToken += 1;\n\t\tthis.unsubscribeController?.();\n\t\tthis.unsubscribeController = null;\n\t\tif (this.coordinator && this.sectionId) {\n\t\t\tawait this.coordinator.disposeSectionController({\n\t\t\t\tsectionId: this.sectionId,\n\t\t\t\tattemptId: this.attemptId,\n\t\t\t});\n\t\t}\n\t\tthis.registry.clear();\n\t\tthis.loadedRenderableKeys.clear();\n\t\tthis.controller = null;\n\t\tthis.coordinator = null;\n\t\t// Tear down the engine-side adapter (if attached) last so any\n\t\t// `dispose` FSM input flows through the bridges before they\n\t\t// detach. Adapter disposal is idempotent and safe even when\n\t\t// nothing is attached.\n\t\tif (this.adapter) {\n\t\t\tconst adapter = this.adapter;\n\t\t\tthis.adapter = null;\n\t\t\tawait adapter.dispose();\n\t\t}\n\t}\n}\n\nconst noopDispose = (): void => {};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cohort.js","sourceRoot":"","sources":["../../../src/runtime/core/cohort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAAwB;IACjD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,OAAO,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,CAAmB,EAAE,CAAmB;IACpE,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAG1B;IACA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO;QACN,SAAS;QACT,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;KAC/B,CAAC;AACH,CAAC","sourcesContent":["/**\n * Cohort identity for the section runtime engine (M7).\n *\n * One cohort is the tuple `(sectionId, attemptId)` for the section the\n * host is currently rendering. Stage progression, readiness latches, and\n * `pie-loading-complete` emission are all gated on this tuple — when it\n * changes, the engine emits `disposed` for the outgoing cohort and\n * resets to `composed` for the new one.\n *\n * `attemptId` is optional in the public surface (per the toolkit /\n * layout-CE prop shape) but the engine carries it as the empty string\n * when absent so the cohort key is total.\n */\n\nexport interface CohortKey {\n\t/** Section identifier; required for any non-idle cohort. */\n\tsectionId: string;\n\t/** Attempt identifier; empty string if the host did not provide one. */\n\tattemptId: string;\n}\n\n/**\n * Stable string form of the cohort tuple used as a key for the\n * `loadingCompleteEmittedForCohort` latch and equality checks.\n */\nexport function cohortKey(cohort: CohortKey | null): string {\n\tif (!cohort) return \"\";\n\treturn `${cohort.sectionId}|${cohort.attemptId}`;\n}\n\n/**\n * `true` iff the two cohorts have the same `(sectionId, attemptId)` pair.\n * Treats both inputs as identifying the cohort by value, never by\n * reference.\n */\nexport function cohortsEqual(a: CohortKey | null, b: CohortKey | null): boolean {\n\tif (a === b) return true;\n\tif (!a || !b) return false;\n\treturn a.sectionId === b.sectionId && a.attemptId === b.attemptId;\n}\n\n/**\n * Normalize host-provided `(sectionId, attemptId)` into a cohort. Returns\n * `null` when the section identifier is empty — that is the engine's\n * idle state (no cohort).\n */\nexport function makeCohort(args: {\n\tsectionId: string | null | undefined;\n\tattemptId: string | null | undefined;\n}): CohortKey | null {\n\tconst sectionId = args.sectionId ?? \"\";\n\tif (!sectionId) return null;\n\treturn {\n\t\tsectionId,\n\t\tattemptId: args.attemptId ?? \"\",\n\t};\n}\n"]}
1
+ {"version":3,"file":"cohort.js","sourceRoot":"","sources":["../../../src/runtime/core/cohort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAAwB;IACjD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,OAAO,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC3B,CAAmB,EACnB,CAAmB;IAEnB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAG1B;IACA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO;QACN,SAAS;QACT,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;KAC/B,CAAC;AACH,CAAC","sourcesContent":["/**\n * Cohort identity for the section runtime engine (M7).\n *\n * One cohort is the tuple `(sectionId, attemptId)` for the section the\n * host is currently rendering. Stage progression, readiness latches, and\n * `pie-loading-complete` emission are all gated on this tuple — when it\n * changes, the engine emits `disposed` for the outgoing cohort and\n * resets to `composed` for the new one.\n *\n * `attemptId` is optional in the public surface (per the toolkit /\n * layout-CE prop shape) but the engine carries it as the empty string\n * when absent so the cohort key is total.\n */\n\nexport interface CohortKey {\n\t/** Section identifier; required for any non-idle cohort. */\n\tsectionId: string;\n\t/** Attempt identifier; empty string if the host did not provide one. */\n\tattemptId: string;\n}\n\n/**\n * Stable string form of the cohort tuple used as a key for the\n * `loadingCompleteEmittedForCohort` latch and equality checks.\n */\nexport function cohortKey(cohort: CohortKey | null): string {\n\tif (!cohort) return \"\";\n\treturn `${cohort.sectionId}|${cohort.attemptId}`;\n}\n\n/**\n * `true` iff the two cohorts have the same `(sectionId, attemptId)` pair.\n * Treats both inputs as identifying the cohort by value, never by\n * reference.\n */\nexport function cohortsEqual(\n\ta: CohortKey | null,\n\tb: CohortKey | null,\n): boolean {\n\tif (a === b) return true;\n\tif (!a || !b) return false;\n\treturn a.sectionId === b.sectionId && a.attemptId === b.attemptId;\n}\n\n/**\n * Normalize host-provided `(sectionId, attemptId)` into a cohort. Returns\n * `null` when the section identifier is empty — that is the engine's\n * idle state (no cohort).\n */\nexport function makeCohort(args: {\n\tsectionId: string | null | undefined;\n\tattemptId: string | null | undefined;\n}): CohortKey | null {\n\tconst sectionId = args.sectionId ?? \"\";\n\tif (!sectionId) return null;\n\treturn {\n\t\tsectionId,\n\t\tattemptId: args.attemptId ?? \"\",\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"engine-input.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Section runtime engine inputs (M7 — Variant C, layered core).\n *\n * Inputs are the discriminated union of events the adapter (PR 2) feeds\n * into the pure transition function (`engine-transition.ts`). The shape\n * is closed: every field is plain data so the transition can be tested\n * without any DOM, Svelte, or coordinator wiring.\n *\n * Adapter→core boundary contract:\n * - The adapter never mutates engine state directly. It always\n * constructs an input and calls `core.dispatch(input)`.\n * - Inputs are total: an unhandled `kind` is a programming error\n * (the transition uses `assertNever` exhaustiveness).\n * - Inputs carry only data, never live host references that would\n * pin lifetime. Coordinator and controller handles live in the\n * adapter; the core only sees readiness signals derived from them.\n */\n\nimport type { CohortKey } from \"./cohort.js\";\nimport type {\n\tEffectiveRuntime,\n\tRuntimeInputs,\n} from \"./engine-resolver.js\";\nimport type { EngineReadinessSignals } from \"./engine-readiness.js\";\nimport type { FrameworkErrorModel } from \"../../services/framework-error.js\";\n\n/**\n * `initialize` is the first transition out of `idle`. It carries the\n * cohort key and the resolved runtime/tools snapshot for the cohort.\n * The adapter constructs this input after running the resolver against\n * the host's two-tier inputs.\n */\nexport type EngineInputInitialize = {\n\tkind: \"initialize\";\n\tcohort: CohortKey;\n\teffectiveRuntime: EffectiveRuntime;\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n};\n\n/**\n * `update-runtime` is sent when the host two-tier inputs change but\n * the cohort does not. The transition stores the latest resolver\n * output without changing phase; readiness gates and stage progression\n * stay where they are.\n */\nexport type EngineInputUpdateRuntime = {\n\tkind: \"update-runtime\";\n\teffectiveRuntime: EffectiveRuntime;\n\teffectiveToolsConfig: unknown;\n};\n\n/**\n * `cohort-change` is sent when `(sectionId, attemptId)` changes. The\n * transition emits `disposed` for the outgoing cohort, resets state\n * to `booting-section` for the new one, and re-arms latches.\n */\nexport type EngineInputCohortChange = {\n\tkind: \"cohort-change\";\n\tcohort: CohortKey;\n\teffectiveRuntime: EffectiveRuntime;\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n};\n\n/**\n * `section-controller-resolved` is sent when the coordinator returns\n * the controller for the current cohort. Advances the phase from\n * `booting-section` → `engine-ready` (assuming `composed` is already\n * implied by `phase >= booting-section`, which the FSM treats as\n * monotonic).\n */\nexport type EngineInputSectionControllerResolved = {\n\tkind: \"section-controller-resolved\";\n};\n\n/**\n * `update-readiness-signals` carries the latest readiness snapshot\n * from the host. The transition uses it to gate the move into\n * `interactive` and to decide whether to emit `loading-complete`.\n *\n * The full signal set is sent every time so the transition does not\n * have to reason about partial overlays.\n */\nexport type EngineInputUpdateReadinessSignals = {\n\tkind: \"update-readiness-signals\";\n\tsignals: EngineReadinessSignals;\n\tloadedCount: number;\n\titemCount: number;\n\t/**\n\t * Strict-mode gate. When `\"strict\"`, `interactive` only fires\n\t * after `allLoadingComplete`; in `\"progressive\"`, `interactionReady`\n\t * is sufficient. Carried per-input so the host can reconfigure\n\t * mode mid-cohort without re-initializing.\n\t */\n\tmode: \"progressive\" | \"strict\";\n};\n\n/**\n * `framework-error` is sent for every framework-error report (M3\n * canonical channel). The transition records the latest error in\n * state and emits a `framework-error` output so the adapter can fan\n * out to subscribers and the DOM event.\n */\nexport type EngineInputFrameworkError = {\n\tkind: \"framework-error\";\n\terror: FrameworkErrorModel;\n};\n\n/**\n * `dispose` tears the engine down. Emits `disposed` for the current\n * cohort (if any) and moves to the terminal `disposed` phase. After\n * dispose the engine accepts no further inputs (the transition logs\n * a warning and is a no-op).\n */\nexport type EngineInputDispose = {\n\tkind: \"dispose\";\n};\n\nexport type SectionEngineInput =\n\t| EngineInputInitialize\n\t| EngineInputUpdateRuntime\n\t| EngineInputCohortChange\n\t| EngineInputSectionControllerResolved\n\t| EngineInputUpdateReadinessSignals\n\t| EngineInputFrameworkError\n\t| EngineInputDispose;\n\n/**\n * Convenience re-export so the adapter can import `RuntimeInputs`\n * from a single place when it constructs `initialize` inputs.\n */\nexport type { RuntimeInputs };\n"]}
1
+ {"version":3,"file":"engine-input.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Section runtime engine inputs (M7 — Variant C, layered core).\n *\n * Inputs are the discriminated union of events the adapter (PR 2) feeds\n * into the pure transition function (`engine-transition.ts`). The shape\n * is closed: every field is plain data so the transition can be tested\n * without any DOM, Svelte, or coordinator wiring.\n *\n * Adapter→core boundary contract:\n * - The adapter never mutates engine state directly. It always\n * constructs an input and calls `core.dispatch(input)`.\n * - Inputs are total: an unhandled `kind` is a programming error\n * (the transition uses `assertNever` exhaustiveness).\n * - Inputs carry only data, never live host references that would\n * pin lifetime. Coordinator and controller handles live in the\n * adapter; the core only sees readiness signals derived from them.\n */\n\nimport type { CohortKey } from \"./cohort.js\";\nimport type { EffectiveRuntime, RuntimeInputs } from \"./engine-resolver.js\";\nimport type { EngineReadinessSignals } from \"./engine-readiness.js\";\nimport type { FrameworkErrorModel } from \"../../services/framework-error.js\";\n\n/**\n * `initialize` is the first transition out of `idle`. It carries the\n * cohort key and the resolved runtime/tools snapshot for the cohort.\n * The adapter constructs this input after running the resolver against\n * the host's two-tier inputs.\n */\nexport type EngineInputInitialize = {\n\tkind: \"initialize\";\n\tcohort: CohortKey;\n\teffectiveRuntime: EffectiveRuntime;\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n};\n\n/**\n * `update-runtime` is sent when the host two-tier inputs change but\n * the cohort does not. The transition stores the latest resolver\n * output without changing phase; readiness gates and stage progression\n * stay where they are.\n */\nexport type EngineInputUpdateRuntime = {\n\tkind: \"update-runtime\";\n\teffectiveRuntime: EffectiveRuntime;\n\teffectiveToolsConfig: unknown;\n};\n\n/**\n * `cohort-change` is sent when `(sectionId, attemptId)` changes. The\n * transition emits `disposed` for the outgoing cohort, resets state\n * to `booting-section` for the new one, and re-arms latches.\n */\nexport type EngineInputCohortChange = {\n\tkind: \"cohort-change\";\n\tcohort: CohortKey;\n\teffectiveRuntime: EffectiveRuntime;\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n};\n\n/**\n * `section-controller-resolved` is sent when the coordinator returns\n * the controller for the current cohort. Advances the phase from\n * `booting-section` → `engine-ready` (assuming `composed` is already\n * implied by `phase >= booting-section`, which the FSM treats as\n * monotonic).\n */\nexport type EngineInputSectionControllerResolved = {\n\tkind: \"section-controller-resolved\";\n};\n\n/**\n * `update-readiness-signals` carries the latest readiness snapshot\n * from the host. The transition uses it to gate the move into\n * `interactive` and to decide whether to emit `loading-complete`.\n *\n * The full signal set is sent every time so the transition does not\n * have to reason about partial overlays.\n */\nexport type EngineInputUpdateReadinessSignals = {\n\tkind: \"update-readiness-signals\";\n\tsignals: EngineReadinessSignals;\n\tloadedCount: number;\n\titemCount: number;\n\t/**\n\t * Strict-mode gate. When `\"strict\"`, `interactive` only fires\n\t * after `allLoadingComplete`; in `\"progressive\"`, `interactionReady`\n\t * is sufficient. Carried per-input so the host can reconfigure\n\t * mode mid-cohort without re-initializing.\n\t */\n\tmode: \"progressive\" | \"strict\";\n};\n\n/**\n * `framework-error` is sent for every framework-error report (M3\n * canonical channel). The transition records the latest error in\n * state and emits a `framework-error` output so the adapter can fan\n * out to subscribers and the DOM event.\n */\nexport type EngineInputFrameworkError = {\n\tkind: \"framework-error\";\n\terror: FrameworkErrorModel;\n};\n\n/**\n * `dispose` tears the engine down. Emits `disposed` for the current\n * cohort (if any) and moves to the terminal `disposed` phase. After\n * dispose the engine accepts no further inputs (the transition logs\n * a warning and is a no-op).\n */\nexport type EngineInputDispose = {\n\tkind: \"dispose\";\n};\n\nexport type SectionEngineInput =\n\t| EngineInputInitialize\n\t| EngineInputUpdateRuntime\n\t| EngineInputCohortChange\n\t| EngineInputSectionControllerResolved\n\t| EngineInputUpdateReadinessSignals\n\t| EngineInputFrameworkError\n\t| EngineInputDispose;\n\n/**\n * Convenience re-export so the adapter can import `RuntimeInputs`\n * from a single place when it constructs `initialize` inputs.\n */\nexport type { RuntimeInputs };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"engine-readiness.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiCH,MAAM,UAAU,qBAAqB,CACpC,OAA+B;IAE/B,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,OAAO,CAAC,kBAAkB;QAAE,OAAO,OAAO,CAAC;IAC/C,IAAI,OAAO,CAAC,gBAAgB;QAAE,OAAO,mBAAmB,CAAC;IACzD,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,eAAe,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAIrC;IACA,8EAA8E;IAC9E,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAChF,MAAM,gBAAgB,GACrB,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACrE,MAAM,KAAK,GAAG,qBAAqB,CAAC;QACnC,GAAG,IAAI,CAAC,OAAO;QACf,kBAAkB,EAAE,UAAU;QAC9B,gBAAgB;KAChB,CAAC,CAAC;IAEH,OAAO;QACN,KAAK;QACL,gBAAgB;QAChB,kBAAkB,EAAE,UAAU;QAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;KACnB,CAAC;AACH,CAAC","sourcesContent":["/**\n * Readiness derivation for the section runtime engine (M7).\n *\n * Canonical home of `createReadinessDetail` and `resolveReadinessPhase`.\n * As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-readiness.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * Type duplication note: the public DOM-event detail aliases\n * (`SectionPlayerReadinessChangeDetail` /\n * `SectionPlayerReadinessPhase`) still live in section-player's\n * `contracts/public-events.ts` because that file is part of section-\n * player's published custom-element contract. The toolkit core defines\n * `EngineReadinessPhase` independently so it has zero section-player\n * imports. The two definitions must stay structurally identical;\n * that invariant is covered by the readiness assertions in this\n * package's tests, which mirror the section-player suite.\n */\n\n/**\n * Coarse readiness phase label, derived from the four readiness\n * signals. Surfaced via the kernel's `selectReadiness()` /\n * `getSnapshot().readiness` selectors; M6 stages own the stage-level\n * transitions on `pie-stage-change` and use this phase as a\n * convenience label only. The `readiness-change` DOM\n * event that used to surface this directly was removed in the broad\n * architecture review compat sweep alongside its\n * event bridge.\n */\nexport type EngineReadinessPhase =\n\t| \"bootstrapping\"\n\t| \"interaction-ready\"\n\t| \"loading\"\n\t| \"ready\"\n\t| \"error\";\n\nexport type EngineReadinessSignals = {\n\tsectionReady: boolean;\n\tinteractionReady: boolean;\n\tallLoadingComplete: boolean;\n\truntimeError: boolean;\n};\n\nexport type EngineReadinessDetail = {\n\tphase: EngineReadinessPhase;\n\tinteractionReady: boolean;\n\tallLoadingComplete: boolean;\n\treason?: string;\n};\n\nexport function resolveReadinessPhase(\n\tsignals: EngineReadinessSignals,\n): EngineReadinessPhase {\n\tif (signals.runtimeError) return \"error\";\n\tif (signals.allLoadingComplete) return \"ready\";\n\tif (signals.interactionReady) return \"interaction-ready\";\n\tif (signals.sectionReady) return \"loading\";\n\treturn \"bootstrapping\";\n}\n\nexport function createReadinessDetail(args: {\n\tmode: \"progressive\" | \"strict\";\n\tsignals: EngineReadinessSignals;\n\treason?: string;\n}): EngineReadinessDetail {\n\t// Final ready must always be gated by section lifecycle and complete loading.\n\tconst finalReady = args.signals.sectionReady && args.signals.allLoadingComplete;\n\tconst interactionReady =\n\t\targs.mode === \"strict\" ? finalReady : args.signals.interactionReady;\n\tconst phase = resolveReadinessPhase({\n\t\t...args.signals,\n\t\tallLoadingComplete: finalReady,\n\t\tinteractionReady,\n\t});\n\n\treturn {\n\t\tphase,\n\t\tinteractionReady,\n\t\tallLoadingComplete: finalReady,\n\t\treason: args.reason,\n\t};\n}\n"]}
1
+ {"version":3,"file":"engine-readiness.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiCH,MAAM,UAAU,qBAAqB,CACpC,OAA+B;IAE/B,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,OAAO,CAAC,kBAAkB;QAAE,OAAO,OAAO,CAAC;IAC/C,IAAI,OAAO,CAAC,gBAAgB;QAAE,OAAO,mBAAmB,CAAC;IACzD,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,eAAe,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAIrC;IACA,8EAA8E;IAC9E,MAAM,UAAU,GACf,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAC9D,MAAM,gBAAgB,GACrB,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACrE,MAAM,KAAK,GAAG,qBAAqB,CAAC;QACnC,GAAG,IAAI,CAAC,OAAO;QACf,kBAAkB,EAAE,UAAU;QAC9B,gBAAgB;KAChB,CAAC,CAAC;IAEH,OAAO;QACN,KAAK;QACL,gBAAgB;QAChB,kBAAkB,EAAE,UAAU;QAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;KACnB,CAAC;AACH,CAAC","sourcesContent":["/**\n * Readiness derivation for the section runtime engine (M7).\n *\n * Canonical home of `createReadinessDetail` and `resolveReadinessPhase`.\n * As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-readiness.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * Type duplication note: the public DOM-event detail aliases\n * (`SectionPlayerReadinessChangeDetail` /\n * `SectionPlayerReadinessPhase`) still live in section-player's\n * `contracts/public-events.ts` because that file is part of section-\n * player's published custom-element contract. The toolkit core defines\n * `EngineReadinessPhase` independently so it has zero section-player\n * imports. The two definitions must stay structurally identical;\n * that invariant is covered by the readiness assertions in this\n * package's tests, which mirror the section-player suite.\n */\n\n/**\n * Coarse readiness phase label, derived from the four readiness\n * signals. Surfaced via the kernel's `selectReadiness()` /\n * `getSnapshot().readiness` selectors; M6 stages own the stage-level\n * transitions on `pie-stage-change` and use this phase as a\n * convenience label only. The `readiness-change` DOM\n * event that used to surface this directly was removed in the broad\n * architecture review compat sweep alongside its\n * event bridge.\n */\nexport type EngineReadinessPhase =\n\t| \"bootstrapping\"\n\t| \"interaction-ready\"\n\t| \"loading\"\n\t| \"ready\"\n\t| \"error\";\n\nexport type EngineReadinessSignals = {\n\tsectionReady: boolean;\n\tinteractionReady: boolean;\n\tallLoadingComplete: boolean;\n\truntimeError: boolean;\n};\n\nexport type EngineReadinessDetail = {\n\tphase: EngineReadinessPhase;\n\tinteractionReady: boolean;\n\tallLoadingComplete: boolean;\n\treason?: string;\n};\n\nexport function resolveReadinessPhase(\n\tsignals: EngineReadinessSignals,\n): EngineReadinessPhase {\n\tif (signals.runtimeError) return \"error\";\n\tif (signals.allLoadingComplete) return \"ready\";\n\tif (signals.interactionReady) return \"interaction-ready\";\n\tif (signals.sectionReady) return \"loading\";\n\treturn \"bootstrapping\";\n}\n\nexport function createReadinessDetail(args: {\n\tmode: \"progressive\" | \"strict\";\n\tsignals: EngineReadinessSignals;\n\treason?: string;\n}): EngineReadinessDetail {\n\t// Final ready must always be gated by section lifecycle and complete loading.\n\tconst finalReady =\n\t\targs.signals.sectionReady && args.signals.allLoadingComplete;\n\tconst interactionReady =\n\t\targs.mode === \"strict\" ? finalReady : args.signals.interactionReady;\n\tconst phase = resolveReadinessPhase({\n\t\t...args.signals,\n\t\tallLoadingComplete: finalReady,\n\t\tinteractionReady,\n\t});\n\n\treturn {\n\t\tphase,\n\t\tinteractionReady,\n\t\tallLoadingComplete: finalReady,\n\t\treason: args.reason,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"engine-resolver.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Section runtime engine resolver (M7).\n *\n * Canonical home of `resolveRuntime`, `resolveToolsConfig`, and their\n * supporting helpers/types. As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-runtime.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * What is NOT absorbed in this module:\n * - `resolvePlayerRuntime` stays in section-player because it depends on\n * `DEFAULT_PLAYER_DEFINITIONS` (which side-effect-imports the\n * item-player package). The toolkit core stays free of that\n * dependency by exposing a parametrized orchestrator —\n * `resolveSectionEngineRuntimeState` — that takes a `resolvePlayerRuntime`\n * callable. The section-player wrapper\n * (`resolveSectionPlayerRuntimeState` in\n * `packages/section-player/src/components/shared/section-player-host-runtime.ts`)\n * hands its local implementation in.\n *\n * Runtime-owned configuration flows through `runtime.<key>`. Layout-only\n * inputs stay on the section-player host elements.\n */\n\nimport type { LoaderConfig } from \"@pie-players/pie-players-shared/loader-config\";\nimport type {\n\tLoadingCompleteDetail,\n\tStageChangeDetail,\n} from \"@pie-players/pie-players-shared/pie\";\nimport type { FrameworkErrorModel } from \"../../services/framework-error.js\";\nimport type { ToolConfigStrictness } from \"../../services/tool-config-validation.js\";\n\nexport const DEFAULT_ASSESSMENT_ID = \"section-demo-direct\";\nexport const DEFAULT_PLAYER_TYPE = \"iife\";\nexport const DEFAULT_LAZY_INIT = true;\nexport const DEFAULT_ISOLATION = \"inherit\";\nexport const DEFAULT_ENV = { mode: \"gather\", role: \"student\" } as Record<\n\tstring,\n\tunknown\n>;\n\nexport type PlayerOverrides = {\n\tloaderConfig?: LoaderConfig;\n\tloaderOptions?: Record<string, unknown>;\n\t[key: string]: unknown;\n};\n\nexport type FrameworkErrorHandler = (model: FrameworkErrorModel) => void;\nexport type StageChangeHandler = (detail: StageChangeDetail) => void;\nexport type LoadingCompleteHandler = (detail: LoadingCompleteDetail) => void;\n\n/**\n * Section runtime config.\n *\n * Documented exceptions (no runtime mirror, by design): identity\n * (`section-id`, `attempt-id`, `section`); layout-only shell knobs\n * (`show-toolbar`, `toolbar-position`, etc.); and layout-shell host\n * data (`policies`, `hooks`, `toolRegistry`, `*HostButtons`). Those\n * surfaces are layout-shell concerns; the runtime engine does not see\n * them. See section-player's ARCHITECTURE.md for the full policy.\n */\nexport type RuntimeConfig = {\n\tassessmentId?: string;\n\tplayerType?: string;\n\tplayer?: PlayerOverrides | null;\n\tlazyInit?: boolean;\n\ttools?: Record<string, unknown> | null;\n\ttoolContextResolvers?: Record<string, unknown> | null;\n\taccessibility?: Record<string, unknown> | null;\n\tcoordinator?: unknown;\n\tcreateSectionController?: unknown;\n\tisolation?: string;\n\tenv?: Record<string, unknown>;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\n\t// Canonical framework-error callback.\n\tonFrameworkError?: FrameworkErrorHandler;\n\n\t// Canonical stage-change callback. The DOM event\n\t// `pie-stage-change` remains the primary channel; this callback is\n\t// the convenience surface that mirrors the event one-to-one.\n\tonStageChange?: StageChangeHandler;\n\n\t// Canonical loading-complete callback. Mirrors the\n\t// `pie-loading-complete` DOM event, which the engine dispatches\n\t// once per cohort when every item has finished loading.\n\tonLoadingComplete?: LoadingCompleteHandler;\n};\n\nexport type RuntimeInputs = {\n\tassessmentId?: string;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n\truntime: RuntimeConfig | null;\n};\n\n/**\n * Pick the runtime-tier value when defined, otherwise the prop/attribute\n * value. The strict mirror rule means every tier-1 surface is resolved\n * with this single helper; per-feature special-casing is forbidden.\n */\nfunction pick<T>(\n\truntimeVal: T | undefined,\n\tattrVal: T | undefined,\n): T | undefined {\n\treturn runtimeVal !== undefined ? runtimeVal : attrVal;\n}\n\n/**\n * Resolve the canonical `onFrameworkError` handler from the two-tier\n * surface. Precedence (highest first): `runtime.onFrameworkError`,\n * then top-level `onFrameworkError`. Layout CEs and the kernel call\n * this so every entry point converges on the same handler.\n */\nexport function resolveOnFrameworkError(args: {\n\truntime: RuntimeConfig | null;\n\tonFrameworkError?: FrameworkErrorHandler;\n}): FrameworkErrorHandler | undefined {\n\tconst r = args.runtime ?? {};\n\tif (r.onFrameworkError !== undefined) return r.onFrameworkError;\n\treturn args.onFrameworkError;\n}\n\nexport function resolveToolsConfig(args: {\n\truntime: RuntimeConfig | null;\n}) {\n\tconst runtimeTools = (args.runtime?.tools || {}) as Record<string, unknown>;\n\tconst placement = (runtimeTools.placement || {}) as Record<string, unknown>;\n\tconst overlayToolsConfig = { ...runtimeTools, placement: { ...placement } };\n\t// Keep host-provided shape intact; framework-owned validation surfaces malformed config.\n\treturn overlayToolsConfig;\n}\n\nexport function resolveRuntime(args: {\n\tassessmentId: string;\n\truntime: RuntimeConfig | null;\n\teffectiveToolsConfig: unknown;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n}) {\n\tconst r = args.runtime || {};\n\tconst runtimePlayer = r.player ? { ...r.player } : null;\n\treturn {\n\t\t...r,\n\t\tassessmentId: pick(r.assessmentId, args.assessmentId),\n\t\tplayerType: r.playerType ?? DEFAULT_PLAYER_TYPE,\n\t\tplayer: runtimePlayer,\n\t\tlazyInit: r.lazyInit ?? DEFAULT_LAZY_INIT,\n\t\taccessibility: r.accessibility ?? null,\n\t\tcoordinator: r.coordinator ?? null,\n\t\tcreateSectionController: r.createSectionController,\n\t\tisolation: r.isolation ?? DEFAULT_ISOLATION,\n\t\tenv: r.env ?? DEFAULT_ENV,\n\t\ttoolConfigStrictness:\n\t\t\tpick(r.toolConfigStrictness, args.toolConfigStrictness) ?? \"error\",\n\n\t\t// Runtime callback wins; top-level callback remains a layout CE event\n\t\t// convenience for hosts that do not use DOM listeners.\n\t\tonFrameworkError: resolveOnFrameworkError({\n\t\t\truntime: args.runtime,\n\t\t\tonFrameworkError: args.onFrameworkError,\n\t\t}),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonStageChange: pick(r.onStageChange, args.onStageChange),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonLoadingComplete: pick(r.onLoadingComplete, args.onLoadingComplete),\n\n\t\ttools: args.effectiveToolsConfig,\n\t};\n}\n\n/**\n * Effective runtime returned by `resolveRuntime`. The shape is exposed\n * as `unknown` at the public boundary because consumers spread it into\n * arbitrary host props; downstream call sites narrow with the specific\n * keys they need.\n */\nexport type EffectiveRuntime = ReturnType<typeof resolveRuntime>;\n\n/**\n * Engine-side orchestrator that powers `resolveSectionPlayerRuntimeState`\n * from section-player and takes\n * `resolvePlayerRuntime` as an injected callable so the toolkit core\n * stays free of host-coupled defaults (`DEFAULT_PLAYER_DEFINITIONS`).\n */\nexport function resolveSectionEngineRuntimeState<P>(\n\targs: RuntimeInputs,\n\tdeps: {\n\t\tresolvePlayerRuntime: (resolverArgs: {\n\t\t\teffectiveRuntime: Record<string, unknown>;\n\t\t\tplayerType: string;\n\t\t\tenv: Record<string, unknown> | null;\n\t\t}) => P;\n\t},\n): {\n\teffectiveToolsConfig: unknown;\n\teffectiveRuntime: EffectiveRuntime;\n\tplayerRuntime: P;\n} {\n\tconst assessmentId = args.assessmentId ?? DEFAULT_ASSESSMENT_ID;\n\n\tconst effectiveToolsConfig = resolveToolsConfig({\n\t\truntime: args.runtime,\n\t});\n\tconst effectiveRuntime = resolveRuntime({\n\t\tassessmentId,\n\t\truntime: args.runtime,\n\t\teffectiveToolsConfig,\n\t\ttoolConfigStrictness: args.toolConfigStrictness,\n\t\tonFrameworkError: args.onFrameworkError,\n\t\tonStageChange: args.onStageChange,\n\t\tonLoadingComplete: args.onLoadingComplete,\n\t});\n\tconst playerRuntime = deps.resolvePlayerRuntime({\n\t\teffectiveRuntime: effectiveRuntime as Record<string, unknown>,\n\t\tplayerType: String(effectiveRuntime.playerType ?? DEFAULT_PLAYER_TYPE),\n\t\tenv: (effectiveRuntime.env as Record<string, unknown> | null) ?? null,\n\t});\n\treturn {\n\t\teffectiveToolsConfig,\n\t\teffectiveRuntime,\n\t\tplayerRuntime,\n\t};\n}\n"]}
1
+ {"version":3,"file":"engine-resolver.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Section runtime engine resolver (M7).\n *\n * Canonical home of `resolveRuntime`, `resolveToolsConfig`, and their\n * supporting helpers/types. As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-runtime.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * What is NOT absorbed in this module:\n * - `resolvePlayerRuntime` stays in section-player because it depends on\n * `DEFAULT_PLAYER_DEFINITIONS` (which side-effect-imports the\n * item-player package). The toolkit core stays free of that\n * dependency by exposing a parametrized orchestrator —\n * `resolveSectionEngineRuntimeState` — that takes a `resolvePlayerRuntime`\n * callable. The section-player wrapper\n * (`resolveSectionPlayerRuntimeState` in\n * `packages/section-player/src/components/shared/section-player-host-runtime.ts`)\n * hands its local implementation in.\n *\n * Runtime-owned configuration flows through `runtime.<key>`. Layout-only\n * inputs stay on the section-player host elements.\n */\n\nimport type { LoaderConfig } from \"@pie-players/pie-players-shared/loader-config\";\nimport type {\n\tLoadingCompleteDetail,\n\tStageChangeDetail,\n} from \"@pie-players/pie-players-shared/pie\";\nimport type { FrameworkErrorModel } from \"../../services/framework-error.js\";\nimport type { ToolConfigStrictness } from \"../../services/tool-config-validation.js\";\n\nexport const DEFAULT_ASSESSMENT_ID = \"section-demo-direct\";\nexport const DEFAULT_PLAYER_TYPE = \"iife\";\nexport const DEFAULT_LAZY_INIT = true;\nexport const DEFAULT_ISOLATION = \"inherit\";\nexport const DEFAULT_ENV = { mode: \"gather\", role: \"student\" } as Record<\n\tstring,\n\tunknown\n>;\n\nexport type PlayerOverrides = {\n\tloaderConfig?: LoaderConfig;\n\tloaderOptions?: Record<string, unknown>;\n\t[key: string]: unknown;\n};\n\nexport type FrameworkErrorHandler = (model: FrameworkErrorModel) => void;\nexport type StageChangeHandler = (detail: StageChangeDetail) => void;\nexport type LoadingCompleteHandler = (detail: LoadingCompleteDetail) => void;\n\n/**\n * Section runtime config.\n *\n * Documented exceptions (no runtime mirror, by design): identity\n * (`section-id`, `attempt-id`, `section`); layout-only shell knobs\n * (`show-toolbar`, `toolbar-position`, etc.); and layout-shell host\n * data (`policies`, `hooks`, `toolRegistry`, `*HostButtons`). Those\n * surfaces are layout-shell concerns; the runtime engine does not see\n * them. See section-player's ARCHITECTURE.md for the full policy.\n */\nexport type RuntimeConfig = {\n\tassessmentId?: string;\n\tplayerType?: string;\n\tplayer?: PlayerOverrides | null;\n\tlazyInit?: boolean;\n\ttools?: Record<string, unknown> | null;\n\ttoolContextResolvers?: Record<string, unknown> | null;\n\taccessibility?: Record<string, unknown> | null;\n\tcoordinator?: unknown;\n\tcreateSectionController?: unknown;\n\tisolation?: string;\n\tenv?: Record<string, unknown>;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\n\t// Canonical framework-error callback.\n\tonFrameworkError?: FrameworkErrorHandler;\n\n\t// Canonical stage-change callback. The DOM event\n\t// `pie-stage-change` remains the primary channel; this callback is\n\t// the convenience surface that mirrors the event one-to-one.\n\tonStageChange?: StageChangeHandler;\n\n\t// Canonical loading-complete callback. Mirrors the\n\t// `pie-loading-complete` DOM event, which the engine dispatches\n\t// once per cohort when every item has finished loading.\n\tonLoadingComplete?: LoadingCompleteHandler;\n};\n\nexport type RuntimeInputs = {\n\tassessmentId?: string;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n\truntime: RuntimeConfig | null;\n};\n\n/**\n * Pick the runtime-tier value when defined, otherwise the prop/attribute\n * value. The strict mirror rule means every tier-1 surface is resolved\n * with this single helper; per-feature special-casing is forbidden.\n */\nfunction pick<T>(\n\truntimeVal: T | undefined,\n\tattrVal: T | undefined,\n): T | undefined {\n\treturn runtimeVal !== undefined ? runtimeVal : attrVal;\n}\n\n/**\n * Resolve the canonical `onFrameworkError` handler from the two-tier\n * surface. Precedence (highest first): `runtime.onFrameworkError`,\n * then top-level `onFrameworkError`. Layout CEs and the kernel call\n * this so every entry point converges on the same handler.\n */\nexport function resolveOnFrameworkError(args: {\n\truntime: RuntimeConfig | null;\n\tonFrameworkError?: FrameworkErrorHandler;\n}): FrameworkErrorHandler | undefined {\n\tconst r = args.runtime ?? {};\n\tif (r.onFrameworkError !== undefined) return r.onFrameworkError;\n\treturn args.onFrameworkError;\n}\n\nexport function resolveToolsConfig(args: { runtime: RuntimeConfig | null }) {\n\tconst runtimeTools = (args.runtime?.tools || {}) as Record<string, unknown>;\n\tconst placement = (runtimeTools.placement || {}) as Record<string, unknown>;\n\tconst overlayToolsConfig = { ...runtimeTools, placement: { ...placement } };\n\t// Keep host-provided shape intact; framework-owned validation surfaces malformed config.\n\treturn overlayToolsConfig;\n}\n\nexport function resolveRuntime(args: {\n\tassessmentId: string;\n\truntime: RuntimeConfig | null;\n\teffectiveToolsConfig: unknown;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n}) {\n\tconst r = args.runtime || {};\n\tconst runtimePlayer = r.player ? { ...r.player } : null;\n\treturn {\n\t\t...r,\n\t\tassessmentId: pick(r.assessmentId, args.assessmentId),\n\t\tplayerType: r.playerType ?? DEFAULT_PLAYER_TYPE,\n\t\tplayer: runtimePlayer,\n\t\tlazyInit: r.lazyInit ?? DEFAULT_LAZY_INIT,\n\t\taccessibility: r.accessibility ?? null,\n\t\tcoordinator: r.coordinator ?? null,\n\t\tcreateSectionController: r.createSectionController,\n\t\tisolation: r.isolation ?? DEFAULT_ISOLATION,\n\t\tenv: r.env ?? DEFAULT_ENV,\n\t\ttoolConfigStrictness:\n\t\t\tpick(r.toolConfigStrictness, args.toolConfigStrictness) ?? \"error\",\n\n\t\t// Runtime callback wins; top-level callback remains a layout CE event\n\t\t// convenience for hosts that do not use DOM listeners.\n\t\tonFrameworkError: resolveOnFrameworkError({\n\t\t\truntime: args.runtime,\n\t\t\tonFrameworkError: args.onFrameworkError,\n\t\t}),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonStageChange: pick(r.onStageChange, args.onStageChange),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonLoadingComplete: pick(r.onLoadingComplete, args.onLoadingComplete),\n\n\t\ttools: args.effectiveToolsConfig,\n\t};\n}\n\n/**\n * Effective runtime returned by `resolveRuntime`. The shape is exposed\n * as `unknown` at the public boundary because consumers spread it into\n * arbitrary host props; downstream call sites narrow with the specific\n * keys they need.\n */\nexport type EffectiveRuntime = ReturnType<typeof resolveRuntime>;\n\n/**\n * Engine-side orchestrator that powers `resolveSectionPlayerRuntimeState`\n * from section-player and takes\n * `resolvePlayerRuntime` as an injected callable so the toolkit core\n * stays free of host-coupled defaults (`DEFAULT_PLAYER_DEFINITIONS`).\n */\nexport function resolveSectionEngineRuntimeState<P>(\n\targs: RuntimeInputs,\n\tdeps: {\n\t\tresolvePlayerRuntime: (resolverArgs: {\n\t\t\teffectiveRuntime: Record<string, unknown>;\n\t\t\tplayerType: string;\n\t\t\tenv: Record<string, unknown> | null;\n\t\t}) => P;\n\t},\n): {\n\teffectiveToolsConfig: unknown;\n\teffectiveRuntime: EffectiveRuntime;\n\tplayerRuntime: P;\n} {\n\tconst assessmentId = args.assessmentId ?? DEFAULT_ASSESSMENT_ID;\n\n\tconst effectiveToolsConfig = resolveToolsConfig({\n\t\truntime: args.runtime,\n\t});\n\tconst effectiveRuntime = resolveRuntime({\n\t\tassessmentId,\n\t\truntime: args.runtime,\n\t\teffectiveToolsConfig,\n\t\ttoolConfigStrictness: args.toolConfigStrictness,\n\t\tonFrameworkError: args.onFrameworkError,\n\t\tonStageChange: args.onStageChange,\n\t\tonLoadingComplete: args.onLoadingComplete,\n\t});\n\tconst playerRuntime = deps.resolvePlayerRuntime({\n\t\teffectiveRuntime: effectiveRuntime as Record<string, unknown>,\n\t\tplayerType: String(effectiveRuntime.playerType ?? DEFAULT_PLAYER_TYPE),\n\t\tenv: (effectiveRuntime.env as Record<string, unknown> | null) ?? null,\n\t});\n\treturn {\n\t\teffectiveToolsConfig,\n\t\teffectiveRuntime,\n\t\tplayerRuntime,\n\t};\n}\n"]}
@@ -86,9 +86,7 @@ function applyReadinessUpdate(state, args) {
86
86
  // Canonical `loading-complete` emission. One-shot per cohort, gated
87
87
  // on the readiness signals indicating every item has finished
88
88
  // loading.
89
- if (detail.allLoadingComplete &&
90
- state.cohort &&
91
- !loadingCompleteEmitted) {
89
+ if (detail.allLoadingComplete && state.cohort && !loadingCompleteEmitted) {
92
90
  loadingCompleteEmitted = true;
93
91
  outputs.push({
94
92
  kind: "loading-complete",
@@ -1 +1 @@
1
- {"version":3,"file":"engine-transition.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-transition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure transition function for the section runtime engine (M7 — Variant\n * C, layered core).\n *\n * `transition(state, input)` is total over `(state, input)` pairs and\n * returns:\n * - the next `SectionEngineState` (immutable; the input state object\n * is never mutated);\n * - the ordered list of `SectionEngineOutput`s the adapter must\n * dispatch (DOM events, framework-error fan-out, etc.).\n *\n * The function imports nothing from Svelte, the DOM, or the\n * coordinator. The `core/` constraint is enforced by the per-PR audit\n * step in the M7 implementation plan.\n *\n * Phase machine (per `engine-state.ts`):\n * idle → booting-section → engine-ready → interactive → disposed\n * (cohort-change rolls back to booting-section for the new cohort\n * after emitting `disposed` for the outgoing cohort)\n *\n * Output ordering invariants:\n * 1. `stage-change` for stage advancement fires before any\n * `loading-complete` triggered by the same input.\n * 2. `loading-complete` fires once per cohort, gated on\n * `state.loadingCompleteEmitted`.\n * 3. `framework-error` outputs are independent of the stage chain\n * and do not move the phase.\n *\n * Readiness alias output kinds (`readiness-change`,\n * `interaction-ready`, `ready`) and their DOM-event bridge were\n * removed in the broad architecture review compat sweep. Hosts that\n * need the readiness detail read it via the kernel's `selectReadiness`\n * / `getSnapshot` selectors or via `SectionEngineCore.getState()`.\n */\n\nimport { cohortsEqual, type CohortKey } from \"./cohort.js\";\nimport type { SectionEngineInput } from \"./engine-input.js\";\nimport type { SectionEngineOutput } from \"./engine-output.js\";\nimport {\n\tcreateReadinessDetail,\n\ttype EngineReadinessSignals,\n} from \"./engine-readiness.js\";\nimport { phaseToStage } from \"./engine-stage-derivation.js\";\nimport {\n\tcreateInitialEngineState,\n\ttype SectionEnginePhase,\n\ttype SectionEngineState,\n} from \"./engine-state.js\";\n\nexport interface TransitionResult {\n\tstate: SectionEngineState;\n\toutputs: SectionEngineOutput[];\n}\n\nfunction emitStageChange(\n\toutputs: SectionEngineOutput[],\n\tphase: SectionEnginePhase,\n\tcohort: CohortKey | null,\n\tstatus: \"entered\" | \"skipped\" | \"failed\" = \"entered\",\n): void {\n\tconst stage = phaseToStage(phase);\n\tif (!stage) return;\n\toutputs.push({ kind: \"stage-change\", stage, status, cohort });\n}\n\n/**\n * Transition the engine after `initialize` / `cohort-change`. Sets\n * the new cohort, resets latches, stores the resolved runtime/tools,\n * and emits the `composed` stage.\n */\nfunction startCohort(args: {\n\tstate: SectionEngineState;\n\tcohort: CohortKey;\n\teffectiveRuntime: SectionEngineState[\"effectiveRuntime\"];\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n}): { state: SectionEngineState; outputs: SectionEngineOutput[] } {\n\tconst next: SectionEngineState = {\n\t\t...createInitialEngineState(),\n\t\tphase: \"booting-section\",\n\t\tcohort: args.cohort,\n\t\teffectiveRuntime: args.effectiveRuntime,\n\t\teffectiveToolsConfig: args.effectiveToolsConfig,\n\t\titemCount: args.itemCount,\n\t};\n\tconst outputs: SectionEngineOutput[] = [];\n\temitStageChange(outputs, \"booting-section\", args.cohort);\n\treturn { state: next, outputs };\n}\n\n/**\n * Apply a readiness update: store new signals, derive the detail in\n * the requested mode, advance the phase to `interactive` when gated,\n * and emit `loading-complete` once per cohort.\n */\nfunction applyReadinessUpdate(\n\tstate: SectionEngineState,\n\targs: {\n\t\tsignals: EngineReadinessSignals;\n\t\tmode: \"progressive\" | \"strict\";\n\t\tloadedCount: number;\n\t\titemCount: number;\n\t},\n): TransitionResult {\n\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t// No cohort to update; ignore.\n\t\treturn { state, outputs: [] };\n\t}\n\n\tconst detail = createReadinessDetail({\n\t\tmode: args.mode,\n\t\tsignals: args.signals,\n\t});\n\tconst outputs: SectionEngineOutput[] = [];\n\n\tlet phase = state.phase;\n\tlet loadingCompleteEmitted = state.loadingCompleteEmitted;\n\n\t// Stage advancement: engine-ready → interactive when readiness\n\t// satisfies `interactionReady` (mode-aware via `createReadinessDetail`).\n\tif (phase === \"engine-ready\" && detail.interactionReady) {\n\t\tphase = \"interactive\";\n\t\temitStageChange(outputs, phase, state.cohort);\n\t}\n\n\t// Canonical `loading-complete` emission. One-shot per cohort, gated\n\t// on the readiness signals indicating every item has finished\n\t// loading.\n\tif (\n\t\tdetail.allLoadingComplete &&\n\t\tstate.cohort &&\n\t\t!loadingCompleteEmitted\n\t) {\n\t\tloadingCompleteEmitted = true;\n\t\toutputs.push({\n\t\t\tkind: \"loading-complete\",\n\t\t\tcohort: state.cohort,\n\t\t\titemCount: args.itemCount,\n\t\t\tloadedCount: args.loadedCount,\n\t\t});\n\t}\n\n\tconst nextState: SectionEngineState = {\n\t\t...state,\n\t\tphase,\n\t\treadinessSignals: args.signals,\n\t\tloadedCount: args.loadedCount,\n\t\titemCount: args.itemCount,\n\t\tloadingCompleteEmitted,\n\t};\n\treturn { state: nextState, outputs };\n}\n\n/**\n * Pure transition. Total over `(state, input)`; never mutates inputs;\n * never throws. Unhandled inputs after `disposed` fall through to a\n * no-op (the adapter is responsible for not feeding them in, but the\n * core stays safe by design).\n */\nexport function transition(\n\tstate: SectionEngineState,\n\tinput: SectionEngineInput,\n): TransitionResult {\n\tswitch (input.kind) {\n\t\tcase \"initialize\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\t// The engine has been disposed; ignore.\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Already initialized. Treat as `update-runtime` for the\n\t\t\t\t// current cohort if the cohort matches; otherwise treat as\n\t\t\t\t// a `cohort-change`.\n\t\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t\treturn transition(state, {\n\t\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"cohort-change\",\n\t\t\t\t\tcohort: input.cohort,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\titemCount: input.itemCount,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"update-runtime\": {\n\t\t\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t},\n\t\t\t\toutputs: [],\n\t\t\t};\n\t\t}\n\n\t\tcase \"cohort-change\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t// No-op cohort change; fall back to a runtime update.\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Emit `disposed` for the outgoing cohort before we wipe state.\n\t\t\t\toutputs.push({\n\t\t\t\t\tkind: \"stage-change\",\n\t\t\t\t\tstage: \"disposed\",\n\t\t\t\t\tstatus: \"entered\",\n\t\t\t\t\tcohort: state.cohort,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst started = startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tstate: started.state,\n\t\t\t\toutputs: [...outputs, ...started.outputs],\n\t\t\t};\n\t\t}\n\n\t\tcase \"section-controller-resolved\": {\n\t\t\tif (state.phase !== \"booting-section\") {\n\t\t\t\t// Either too early (idle), too late (interactive / disposed),\n\t\t\t\t// or a duplicate notification; the FSM is monotonic.\n\t\t\t\treturn {\n\t\t\t\t\tstate: { ...state, controllerResolved: true },\n\t\t\t\t\toutputs: [],\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\temitStageChange(outputs, \"engine-ready\", state.cohort);\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"engine-ready\",\n\t\t\t\t\tcontrollerResolved: true,\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tcase \"update-readiness-signals\": {\n\t\t\treturn applyReadinessUpdate(state, {\n\t\t\t\tsignals: input.signals,\n\t\t\t\tmode: input.mode,\n\t\t\t\tloadedCount: input.loadedCount,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"framework-error\": {\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tlastFrameworkError: input.error,\n\t\t\t\t\treadinessSignals: {\n\t\t\t\t\t\t...state.readinessSignals,\n\t\t\t\t\t\truntimeError: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toutputs: [{ kind: \"framework-error\", error: input.error }],\n\t\t\t};\n\t\t}\n\n\t\tcase \"dispose\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\temitStageChange(outputs, \"disposed\", state.cohort);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"disposed\",\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst exhaustive: never = input;\n\t\t\tvoid exhaustive;\n\t\t\treturn { state, outputs: [] };\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-transition.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-transition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure transition function for the section runtime engine (M7 — Variant\n * C, layered core).\n *\n * `transition(state, input)` is total over `(state, input)` pairs and\n * returns:\n * - the next `SectionEngineState` (immutable; the input state object\n * is never mutated);\n * - the ordered list of `SectionEngineOutput`s the adapter must\n * dispatch (DOM events, framework-error fan-out, etc.).\n *\n * The function imports nothing from Svelte, the DOM, or the\n * coordinator. The `core/` constraint is enforced by the per-PR audit\n * step in the M7 implementation plan.\n *\n * Phase machine (per `engine-state.ts`):\n * idle → booting-section → engine-ready → interactive → disposed\n * (cohort-change rolls back to booting-section for the new cohort\n * after emitting `disposed` for the outgoing cohort)\n *\n * Output ordering invariants:\n * 1. `stage-change` for stage advancement fires before any\n * `loading-complete` triggered by the same input.\n * 2. `loading-complete` fires once per cohort, gated on\n * `state.loadingCompleteEmitted`.\n * 3. `framework-error` outputs are independent of the stage chain\n * and do not move the phase.\n *\n * Readiness alias output kinds (`readiness-change`,\n * `interaction-ready`, `ready`) and their DOM-event bridge were\n * removed in the broad architecture review compat sweep. Hosts that\n * need the readiness detail read it via the kernel's `selectReadiness`\n * / `getSnapshot` selectors or via `SectionEngineCore.getState()`.\n */\n\nimport { cohortsEqual, type CohortKey } from \"./cohort.js\";\nimport type { SectionEngineInput } from \"./engine-input.js\";\nimport type { SectionEngineOutput } from \"./engine-output.js\";\nimport {\n\tcreateReadinessDetail,\n\ttype EngineReadinessSignals,\n} from \"./engine-readiness.js\";\nimport { phaseToStage } from \"./engine-stage-derivation.js\";\nimport {\n\tcreateInitialEngineState,\n\ttype SectionEnginePhase,\n\ttype SectionEngineState,\n} from \"./engine-state.js\";\n\nexport interface TransitionResult {\n\tstate: SectionEngineState;\n\toutputs: SectionEngineOutput[];\n}\n\nfunction emitStageChange(\n\toutputs: SectionEngineOutput[],\n\tphase: SectionEnginePhase,\n\tcohort: CohortKey | null,\n\tstatus: \"entered\" | \"skipped\" | \"failed\" = \"entered\",\n): void {\n\tconst stage = phaseToStage(phase);\n\tif (!stage) return;\n\toutputs.push({ kind: \"stage-change\", stage, status, cohort });\n}\n\n/**\n * Transition the engine after `initialize` / `cohort-change`. Sets\n * the new cohort, resets latches, stores the resolved runtime/tools,\n * and emits the `composed` stage.\n */\nfunction startCohort(args: {\n\tstate: SectionEngineState;\n\tcohort: CohortKey;\n\teffectiveRuntime: SectionEngineState[\"effectiveRuntime\"];\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n}): { state: SectionEngineState; outputs: SectionEngineOutput[] } {\n\tconst next: SectionEngineState = {\n\t\t...createInitialEngineState(),\n\t\tphase: \"booting-section\",\n\t\tcohort: args.cohort,\n\t\teffectiveRuntime: args.effectiveRuntime,\n\t\teffectiveToolsConfig: args.effectiveToolsConfig,\n\t\titemCount: args.itemCount,\n\t};\n\tconst outputs: SectionEngineOutput[] = [];\n\temitStageChange(outputs, \"booting-section\", args.cohort);\n\treturn { state: next, outputs };\n}\n\n/**\n * Apply a readiness update: store new signals, derive the detail in\n * the requested mode, advance the phase to `interactive` when gated,\n * and emit `loading-complete` once per cohort.\n */\nfunction applyReadinessUpdate(\n\tstate: SectionEngineState,\n\targs: {\n\t\tsignals: EngineReadinessSignals;\n\t\tmode: \"progressive\" | \"strict\";\n\t\tloadedCount: number;\n\t\titemCount: number;\n\t},\n): TransitionResult {\n\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t// No cohort to update; ignore.\n\t\treturn { state, outputs: [] };\n\t}\n\n\tconst detail = createReadinessDetail({\n\t\tmode: args.mode,\n\t\tsignals: args.signals,\n\t});\n\tconst outputs: SectionEngineOutput[] = [];\n\n\tlet phase = state.phase;\n\tlet loadingCompleteEmitted = state.loadingCompleteEmitted;\n\n\t// Stage advancement: engine-ready → interactive when readiness\n\t// satisfies `interactionReady` (mode-aware via `createReadinessDetail`).\n\tif (phase === \"engine-ready\" && detail.interactionReady) {\n\t\tphase = \"interactive\";\n\t\temitStageChange(outputs, phase, state.cohort);\n\t}\n\n\t// Canonical `loading-complete` emission. One-shot per cohort, gated\n\t// on the readiness signals indicating every item has finished\n\t// loading.\n\tif (detail.allLoadingComplete && state.cohort && !loadingCompleteEmitted) {\n\t\tloadingCompleteEmitted = true;\n\t\toutputs.push({\n\t\t\tkind: \"loading-complete\",\n\t\t\tcohort: state.cohort,\n\t\t\titemCount: args.itemCount,\n\t\t\tloadedCount: args.loadedCount,\n\t\t});\n\t}\n\n\tconst nextState: SectionEngineState = {\n\t\t...state,\n\t\tphase,\n\t\treadinessSignals: args.signals,\n\t\tloadedCount: args.loadedCount,\n\t\titemCount: args.itemCount,\n\t\tloadingCompleteEmitted,\n\t};\n\treturn { state: nextState, outputs };\n}\n\n/**\n * Pure transition. Total over `(state, input)`; never mutates inputs;\n * never throws. Unhandled inputs after `disposed` fall through to a\n * no-op (the adapter is responsible for not feeding them in, but the\n * core stays safe by design).\n */\nexport function transition(\n\tstate: SectionEngineState,\n\tinput: SectionEngineInput,\n): TransitionResult {\n\tswitch (input.kind) {\n\t\tcase \"initialize\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\t// The engine has been disposed; ignore.\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Already initialized. Treat as `update-runtime` for the\n\t\t\t\t// current cohort if the cohort matches; otherwise treat as\n\t\t\t\t// a `cohort-change`.\n\t\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t\treturn transition(state, {\n\t\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"cohort-change\",\n\t\t\t\t\tcohort: input.cohort,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\titemCount: input.itemCount,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"update-runtime\": {\n\t\t\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t},\n\t\t\t\toutputs: [],\n\t\t\t};\n\t\t}\n\n\t\tcase \"cohort-change\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t// No-op cohort change; fall back to a runtime update.\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Emit `disposed` for the outgoing cohort before we wipe state.\n\t\t\t\toutputs.push({\n\t\t\t\t\tkind: \"stage-change\",\n\t\t\t\t\tstage: \"disposed\",\n\t\t\t\t\tstatus: \"entered\",\n\t\t\t\t\tcohort: state.cohort,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst started = startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tstate: started.state,\n\t\t\t\toutputs: [...outputs, ...started.outputs],\n\t\t\t};\n\t\t}\n\n\t\tcase \"section-controller-resolved\": {\n\t\t\tif (state.phase !== \"booting-section\") {\n\t\t\t\t// Either too early (idle), too late (interactive / disposed),\n\t\t\t\t// or a duplicate notification; the FSM is monotonic.\n\t\t\t\treturn {\n\t\t\t\t\tstate: { ...state, controllerResolved: true },\n\t\t\t\t\toutputs: [],\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\temitStageChange(outputs, \"engine-ready\", state.cohort);\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"engine-ready\",\n\t\t\t\t\tcontrollerResolved: true,\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tcase \"update-readiness-signals\": {\n\t\t\treturn applyReadinessUpdate(state, {\n\t\t\t\tsignals: input.signals,\n\t\t\t\tmode: input.mode,\n\t\t\t\tloadedCount: input.loadedCount,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"framework-error\": {\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tlastFrameworkError: input.error,\n\t\t\t\t\treadinessSignals: {\n\t\t\t\t\t\t...state.readinessSignals,\n\t\t\t\t\t\truntimeError: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toutputs: [{ kind: \"framework-error\", error: input.error }],\n\t\t\t};\n\t\t}\n\n\t\tcase \"dispose\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\temitStageChange(outputs, \"disposed\", state.cohort);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"disposed\",\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst exhaustive: never = input;\n\t\t\tvoid exhaustive;\n\t\t\treturn { state, outputs: [] };\n\t\t}\n\t}\n}\n"]}