@vue-skuilder/platform-ui 0.2.34 → 0.2.36
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.
- package/dist/assets/{About-sUaZ0Srj.js → About-74htcNLT.js} +2 -2
- package/dist/assets/{About-sUaZ0Srj.js.map → About-74htcNLT.js.map} +1 -1
- package/dist/assets/AdminDashboard-B00qno2M.js +2 -0
- package/dist/assets/{AdminDashboard-cKNlDTB2.js.map → AdminDashboard-B00qno2M.js.map} +1 -1
- package/dist/assets/AdminLearner-SJNtSyJ_.js +2 -0
- package/dist/assets/{AdminLearner-DXeevw2h.js.map → AdminLearner-SJNtSyJ_.js.map} +1 -1
- package/dist/assets/BaseUserDB-CV2ZPZOR.js +1 -0
- package/dist/assets/ClassroomCtrlPanel-BSAG3h8B.js +2 -0
- package/dist/assets/{ClassroomCtrlPanel-BeSz_WX4.js.map → ClassroomCtrlPanel-BSAG3h8B.js.map} +1 -1
- package/dist/assets/{Classrooms-DTBqomQE.js → Classrooms-DXNEbtsM.js} +3 -3
- package/dist/assets/{Classrooms-DTBqomQE.js.map → Classrooms-DXNEbtsM.js.map} +1 -1
- package/dist/assets/CouchDBSyncStrategy-BjM7ROXC.js +1 -0
- package/dist/assets/CourseRouter-CsVa_92r.js +7 -0
- package/dist/assets/{CourseRouter-CL8v2Zdk.js.map → CourseRouter-CsVa_92r.js.map} +1 -1
- package/dist/assets/CourseSyncService-CPU_Ll1h.js +1 -0
- package/dist/assets/CourseWare-BTFRjgBR-DBp_fIwH.js +3 -0
- package/dist/assets/{CourseWare-BTFRjgBR-C3GJRVef.js.map → CourseWare-BTFRjgBR-DBp_fIwH.js.map} +1 -1
- package/dist/assets/{Courses-CUff-WLk.js → Courses-CB6GGtdm.js} +3 -3
- package/dist/assets/{Courses-CUff-WLk.js.map → Courses-CB6GGtdm.js.map} +1 -1
- package/dist/assets/EloModeration-DUBgs-Vh.js +2 -0
- package/dist/assets/{EloModeration-6MUDz-Mu.js.map → EloModeration-DUBgs-Vh.js.map} +1 -1
- package/dist/assets/{JoinCode-CW9Lk23D.js → JoinCode-BBvYapCA.js} +2 -2
- package/dist/assets/{JoinCode-CW9Lk23D.js.map → JoinCode-BBvYapCA.js.map} +1 -1
- package/dist/assets/MarkdownRenderer-WG9YrHpe.js +1 -0
- package/dist/assets/MarkdownRenderer-borh39Lq.js +53 -0
- package/dist/assets/MarkdownRenderer-borh39Lq.js.map +1 -0
- package/dist/assets/NewCourseDialog-DBgFVnt3.js +2 -0
- package/dist/assets/{NewCourseDialog-CLm1rQyB.js.map → NewCourseDialog-DBgFVnt3.js.map} +1 -1
- package/dist/assets/PipelineDebugger-BHaqzqZw.js +177 -0
- package/dist/assets/PipelineDebugger-BHaqzqZw.js.map +1 -0
- package/dist/assets/PouchDataLayerProvider-DxsnSIKd.js +2 -0
- package/dist/assets/PouchDataLayerProvider-DxsnSIKd.js.map +1 -0
- package/dist/assets/{ReleaseNotes-CmITE6hd.js → ReleaseNotes-Dg6mLL1C.js} +2 -2
- package/dist/assets/{ReleaseNotes-CmITE6hd.js.map → ReleaseNotes-Dg6mLL1C.js.map} +1 -1
- package/dist/assets/RequestPasswordReset-CcFMTnTc.js +2 -0
- package/dist/assets/{RequestPasswordReset-DPE6S2dU.js.map → RequestPasswordReset-CcFMTnTc.js.map} +1 -1
- package/dist/assets/ResetPassword-Dw_cBJU2.js +2 -0
- package/dist/assets/{ResetPassword-Dl6nj4jF.js.map → ResetPassword-Dw_cBJU2.js.map} +1 -1
- package/dist/assets/StaticDataLayerProvider-CtgU3VBh.js +2 -0
- package/dist/assets/StaticDataLayerProvider-CtgU3VBh.js.map +1 -0
- package/dist/assets/Study-DDsGQCTJ.js +2 -0
- package/dist/assets/{Study-Cf5yVLaY.js.map → Study-DDsGQCTJ.js.map} +1 -1
- package/dist/assets/TagInformation-DBLoXA2a.js +2 -0
- package/dist/assets/{TagInformation-tqHJGkyw.js.map → TagInformation-DBLoXA2a.js.map} +1 -1
- package/dist/assets/User-DfXUXjFb.js +2 -0
- package/dist/assets/User-DfXUXjFb.js.map +1 -0
- package/dist/assets/UserDBDebugger-DPqlc4O_.js +23 -0
- package/dist/assets/UserDBDebugger-DPqlc4O_.js.map +1 -0
- package/dist/assets/UserDBDebugger-xmycWjck.js +1 -0
- package/dist/assets/UserStats-C04YVYv7.js +2 -0
- package/dist/assets/{UserStats-B25DZy-D.js.map → UserStats-C04YVYv7.js.map} +1 -1
- package/dist/assets/VerifyEmail-Y05BSR57.js +2 -0
- package/dist/assets/{VerifyEmail-DyWRQweA.js.map → VerifyEmail-Y05BSR57.js.map} +1 -1
- package/dist/assets/{admin-Cfzt4Vei.css → admin-CMwKoROX.css} +1 -1
- package/dist/assets/admin-DcFjvYJw.js +21 -0
- package/dist/assets/admin-DcFjvYJw.js.map +1 -0
- package/dist/assets/chess-E2uOAyQS-BZi0vihz.js +7 -0
- package/dist/assets/{chess-E2uOAyQS-CP3XwSpG.js.map → chess-E2uOAyQS-BZi0vihz.js.map} +1 -1
- package/dist/assets/chess-Lfm7Fsvs-DgN08Qx9.js +1 -0
- package/dist/assets/contentSource-DwznMSMs.js +34 -0
- package/dist/assets/contentSource-DwznMSMs.js.map +1 -0
- package/dist/assets/defineProperty-y9rbOPYz.js +1 -0
- package/dist/assets/dist-BcwaOf54.js +1 -0
- package/dist/assets/dist-BsRvt0gH.js +38 -0
- package/dist/assets/dist-BsRvt0gH.js.map +1 -0
- package/dist/assets/dist-CAHkbl3M.js +18 -0
- package/dist/assets/dist-CAHkbl3M.js.map +1 -0
- package/dist/assets/dist-CgW7D_Gh.js +1 -0
- package/dist/assets/dist-Dnehy0sn.js +1 -0
- package/dist/assets/dist-Dp6eBE2S.js +64 -0
- package/dist/assets/dist-Dp6eBE2S.js.map +1 -0
- package/dist/assets/edit-ui.es-BWqvElsJ.js +1 -0
- package/dist/assets/edit-ui.es-UaQFL_My.js +41 -0
- package/dist/assets/edit-ui.es-UaQFL_My.js.map +1 -0
- package/dist/assets/elo-B5qCwvSC.js +2 -0
- package/dist/assets/elo-B5qCwvSC.js.map +1 -0
- package/dist/assets/elo-COgu6Hu5.js +2 -0
- package/dist/assets/elo-COgu6Hu5.js.map +1 -0
- package/dist/assets/elo-Cwa8a3Yo.js +1 -0
- package/dist/assets/eloDistance-BV7vfiK5.js +2 -0
- package/dist/assets/eloDistance-BV7vfiK5.js.map +1 -0
- package/dist/assets/eloDistance-MReQeAuj.js +1 -0
- package/dist/assets/french-Dk7YG8Td-CD7Hms2j.js +2 -0
- package/dist/assets/{french-Dk7YG8Td-Bfl4cirn.js.map → french-Dk7YG8Td-CD7Hms2j.js.map} +1 -1
- package/dist/assets/french-evUMlbbq-nGCjilG6.js +1 -0
- package/dist/assets/hierarchyDefinition-DLC5DjaA.js +2 -0
- package/dist/assets/hierarchyDefinition-DLC5DjaA.js.map +1 -0
- package/dist/assets/{index-NFrxkZjT.css → index-B7mmpKZd.css} +1 -1
- package/dist/assets/index-CK-rfSIx.js +4 -0
- package/dist/assets/{index-JRi1udkz.js.map → index-CK-rfSIx.js.map} +1 -1
- package/dist/assets/interferenceMitigator-D78KgOxz.js +2 -0
- package/dist/assets/interferenceMitigator-D78KgOxz.js.map +1 -0
- package/dist/assets/logshim-YQI0WloD.js +2 -0
- package/dist/assets/logshim-YQI0WloD.js.map +1 -0
- package/dist/assets/math-DR3fXDcX-C9KfHLHP.js +1 -0
- package/dist/assets/math-D_8HiEQR-E4QDLrWp.js +34 -0
- package/dist/assets/{math-D_8HiEQR-B9oNpF-3.js.map → math-D_8HiEQR-E4QDLrWp.js.map} +1 -1
- package/dist/assets/moment-DbT30ZpG.js +5 -0
- package/dist/assets/moment-DbT30ZpG.js.map +1 -0
- package/dist/assets/piano-BN5Btq91-CnKhyLGE.js +1 -0
- package/dist/assets/piano-DF1g6yaX-Ck3BH5EK.js +2 -0
- package/dist/assets/{piano-DF1g6yaX-CjD06Qz8.js.map → piano-DF1g6yaX-Ck3BH5EK.js.map} +1 -1
- package/dist/assets/pitch-CgGJFkZ1-Dd0LzmEe.js +2 -0
- package/dist/assets/{pitch-CgGJFkZ1-C-2hdk99.js.map → pitch-CgGJFkZ1-Dd0LzmEe.js.map} +1 -1
- package/dist/assets/pitch-Dn0iNqiS-BxAdpDDb.js +1 -0
- package/dist/assets/prescribed-BWO17Gan.js +2 -0
- package/dist/assets/prescribed-BWO17Gan.js.map +1 -0
- package/dist/assets/relativePriority-DwPMECAp.js +2 -0
- package/dist/assets/relativePriority-DwPMECAp.js.map +1 -0
- package/dist/assets/server-CqR7xtQy.js +2 -0
- package/dist/assets/server-CqR7xtQy.js.map +1 -0
- package/dist/assets/{sightsing-BFQ7HRig-8K5qd7-K.js → sightsing-BFQ7HRig-DV69ELZf.js} +23 -23
- package/dist/assets/{sightsing-BFQ7HRig-8K5qd7-K.js.map → sightsing-BFQ7HRig-DV69ELZf.js.map} +1 -1
- package/dist/assets/sightsing-CJX3k0Fd-CG94OiDr.js +1 -0
- package/dist/assets/srs-DGscV6W4.js +1 -0
- package/dist/assets/srs-DOsG9Y-i.js +2 -0
- package/dist/assets/srs-DOsG9Y-i.js.map +1 -0
- package/dist/assets/tagRoles-jR-PJAgj.js +2 -0
- package/dist/assets/tagRoles-jR-PJAgj.js.map +1 -0
- package/dist/assets/typing-BevtfWlp-CvStu5BY.js +2 -0
- package/dist/assets/{typing-BevtfWlp-BT263ZFw.js.map → typing-BevtfWlp-CvStu5BY.js.map} +1 -1
- package/dist/assets/typing-k-ojjO7G-AF8vU_q7.js +1 -0
- package/dist/assets/userDBKeys-DYLGKnVC.js +4 -0
- package/dist/assets/userDBKeys-DYLGKnVC.js.map +1 -0
- package/dist/assets/userTagPreference-cZCPqadC.js +2 -0
- package/dist/assets/userTagPreference-cZCPqadC.js.map +1 -0
- package/dist/assets/validators-lpYAHmRR.js +2 -0
- package/dist/assets/validators-lpYAHmRR.js.map +1 -0
- package/dist/assets/word-work-BOnRlZgd-CCGZdwyf.js +2 -0
- package/dist/assets/{word-work-BOnRlZgd-BFwc1KBd.js.map → word-work-BOnRlZgd-CCGZdwyf.js.map} +1 -1
- package/dist/assets/word-work-Dd6tIKrt-BNTSCq5F.js +1 -0
- package/dist/assets/{workbox-window.prod.es5-r2bRTooK.js → workbox-window.prod.es5-YsLcd14J.js} +1 -1
- package/dist/assets/{workbox-window.prod.es5-r2bRTooK.js.map → workbox-window.prod.es5-YsLcd14J.js.map} +1 -1
- package/dist/index.html +17 -7
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/package.json +7 -7
- package/dist/assets/AdminDashboard-cKNlDTB2.js +0 -2
- package/dist/assets/AdminLearner-DXeevw2h.js +0 -2
- package/dist/assets/ClassroomCtrlPanel-BeSz_WX4.js +0 -2
- package/dist/assets/CourseRouter-CL8v2Zdk.js +0 -7
- package/dist/assets/CourseWare-BTFRjgBR-C3GJRVef.js +0 -3
- package/dist/assets/EloModeration-6MUDz-Mu.js +0 -2
- package/dist/assets/MarkdownRenderer-U_iPiA2x-DDruDu7E.js +0 -53
- package/dist/assets/MarkdownRenderer-U_iPiA2x-DDruDu7E.js.map +0 -1
- package/dist/assets/MarkdownRenderer-U_iPiA2x-VCa5mXh1.js +0 -1
- package/dist/assets/NewCourseDialog-CLm1rQyB.js +0 -2
- package/dist/assets/RequestPasswordReset-DPE6S2dU.js +0 -2
- package/dist/assets/ResetPassword-Dl6nj4jF.js +0 -2
- package/dist/assets/Study-Cf5yVLaY.js +0 -2
- package/dist/assets/TagInformation-tqHJGkyw.js +0 -2
- package/dist/assets/User-DCoA5JMB.js +0 -3
- package/dist/assets/User-DCoA5JMB.js.map +0 -1
- package/dist/assets/UserStats-B25DZy-D.js +0 -2
- package/dist/assets/VerifyEmail-DyWRQweA.js +0 -2
- package/dist/assets/admin-DCvFP6sY.js +0 -4
- package/dist/assets/admin-DCvFP6sY.js.map +0 -1
- package/dist/assets/chess-E2uOAyQS-CP3XwSpG.js +0 -7
- package/dist/assets/chess-Lfm7Fsvs-RoJ69a0B.js +0 -1
- package/dist/assets/common-ui.es-DHzI_ZVr.js +0 -1
- package/dist/assets/common-ui.es-te1li8kU.js +0 -38
- package/dist/assets/common-ui.es-te1li8kU.js.map +0 -1
- package/dist/assets/dist-BnMJdH50.js +0 -380
- package/dist/assets/dist-BnMJdH50.js.map +0 -1
- package/dist/assets/dist-CtnPlm6M.js +0 -18
- package/dist/assets/dist-CtnPlm6M.js.map +0 -1
- package/dist/assets/dist-D4MdLcof.js +0 -1
- package/dist/assets/dist-Db-U8O3Z.js +0 -1
- package/dist/assets/dist-V9Xbab2f.js +0 -12
- package/dist/assets/dist-V9Xbab2f.js.map +0 -1
- package/dist/assets/edit-ui.es-C7TI7NmB.js +0 -36
- package/dist/assets/edit-ui.es-C7TI7NmB.js.map +0 -1
- package/dist/assets/edit-ui.es-CiY2oEH8.js +0 -1
- package/dist/assets/french-Dk7YG8Td-Bfl4cirn.js +0 -2
- package/dist/assets/french-evUMlbbq-DuW1vCaS.js +0 -1
- package/dist/assets/index-JRi1udkz.js +0 -4
- package/dist/assets/math-DR3fXDcX-BFIht0j2.js +0 -1
- package/dist/assets/math-D_8HiEQR-B9oNpF-3.js +0 -34
- package/dist/assets/piano-BN5Btq91-Jqe2eqme.js +0 -1
- package/dist/assets/piano-DF1g6yaX-CjD06Qz8.js +0 -2
- package/dist/assets/pitch-CgGJFkZ1-C-2hdk99.js +0 -2
- package/dist/assets/pitch-Dn0iNqiS-DpEcsscT.js +0 -1
- package/dist/assets/server-D4lhkoe2.js +0 -2
- package/dist/assets/server-D4lhkoe2.js.map +0 -1
- package/dist/assets/sightsing-CJX3k0Fd-CA3ntnlE.js +0 -1
- package/dist/assets/typing-BevtfWlp-BT263ZFw.js +0 -2
- package/dist/assets/typing-k-ojjO7G-Bq4IfdFx.js +0 -1
- package/dist/assets/word-work-BOnRlZgd-BFwc1KBd.js +0 -2
- package/dist/assets/word-work-Dd6tIKrt-tFtMeyu1.js +0 -1
- /package/dist/assets/{common-ui-BY2Ut5jf.css → dist-BY2Ut5jf.css} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dist-Dp6eBE2S.js","names":["moment"],"sources":["../../../common/dist/interfaces/ViewData.mjs","../../../db/dist/core/types/studySession.mjs","../../../db/dist/study/SourceMixer.mjs","../../../db/dist/study/MixerDebugger.mjs","../../../db/dist/study/SessionOverlay.mjs","../../../db/dist/study/SessionDebugger.mjs","../../../db/dist/study/services/SrsService.mjs","../../../db/dist/study/services/tagRecent.mjs","../../../db/dist/study/services/EloService.mjs","../../../db/dist/study/services/ResponseProcessor.mjs","../../../db/dist/study/services/CardHydrationService.mjs","../../../db/dist/study/ItemQueue.mjs","../../../db/dist/study/SessionController.mjs","../../../db/dist/core/bulkImport/cardProcessor.mjs"],"sourcesContent":["export function displayableDataToViewData(data) {\n const ret = {};\n data.data.forEach((field) => {\n ret[field.name] = field.data;\n });\n if (data._attachments) {\n Object.getOwnPropertyNames(data._attachments).forEach((attachment) => {\n // this 2nd check shouldn't be necessary, but TS is insisting\n if (data._attachments) {\n ret[attachment] = data._attachments[attachment].data;\n }\n });\n }\n return ret;\n}\n//# sourceMappingURL=ViewData.mjs.map\n","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { DocType, DocTypePrefixes } from \"./types-legacy.mjs\";\n//#region src/core/types/studySession.ts\n/** Stable across the open and close writes, unlike a timestamp-keyed id. */\nfunction makeStudySessionId(courseId, userId, sessionId) {\n\treturn `${DocTypePrefixes[DocType.STUDY_SESSION]}::${courseId}::${userId}::${sessionId}`;\n}\nfunction newSessionId() {\n\treturn `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n//#endregion\nexport { makeStudySessionId, newSessionId };\n\n//# sourceMappingURL=studySession.mjs.map","import \"../_virtual/_rolldown/runtime.mjs\";\n//#region src/study/SourceMixer.ts\n/**\n* Quota-based mixer with interleaved output.\n*\n* Allocates equal representation to each source (top-N by score), then\n* interleaves the results by dealing from a randomly-shuffled source order.\n* Within each source, cards are dealt in score-descending order.\n*\n* This ensures that cards from different courses are spread throughout the\n* queue rather than clustered by score bands, which matters because\n* SessionController consumes queues front-to-back and sessions often end\n* before reaching the tail.\n*/\nvar QuotaRoundRobinMixer = class {\n\tmix(batches, limit) {\n\t\tif (batches.length === 0) return [];\n\t\tconst quotaPerSource = Math.ceil(limit / batches.length);\n\t\tconst sourceStacks = batches.map((batch) => {\n\t\t\treturn [...batch.weighted].sort((a, b) => b.score - a.score).slice(0, quotaPerSource);\n\t\t});\n\t\tfor (let i = sourceStacks.length - 1; i > 0; i--) {\n\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t[sourceStacks[i], sourceStacks[j]] = [sourceStacks[j], sourceStacks[i]];\n\t\t}\n\t\tconst result = [];\n\t\tlet exhausted = 0;\n\t\tconst cursors = new Array(sourceStacks.length).fill(0);\n\t\twhile (result.length < limit && exhausted < sourceStacks.length) {\n\t\t\texhausted = 0;\n\t\t\tfor (let s = 0; s < sourceStacks.length; s++) {\n\t\t\t\tif (result.length >= limit) break;\n\t\t\t\tif (cursors[s] < sourceStacks[s].length) {\n\t\t\t\t\tresult.push(sourceStacks[s][cursors[s]]);\n\t\t\t\t\tcursors[s]++;\n\t\t\t\t} else exhausted++;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n};\n//#endregion\nexport { QuotaRoundRobinMixer };\n\n//# sourceMappingURL=SourceMixer.mjs.map","import \"../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../util/logger.mjs\";\nimport { getCardOrigin } from \"../core/navigators/index.mjs\";\n//#region src/study/MixerDebugger.ts\n/**\n* Ring buffer for storing recent mixer runs.\n*/\nconst MAX_RUNS = 10;\nconst runHistory = [];\n/**\n* Build source summary from a batch.\n*/\nfunction buildSourceSummary(batch, sourceId, sourceName) {\n\tconst scores = batch.weighted.map((c) => c.score);\n\tconst reviewCount = batch.weighted.filter((c) => getCardOrigin(c) === \"review\").length;\n\tconst newCount = batch.weighted.filter((c) => getCardOrigin(c) === \"new\").length;\n\treturn {\n\t\tsourceIndex: batch.sourceIndex,\n\t\tsourceId,\n\t\tsourceName,\n\t\ttotalCards: batch.weighted.length,\n\t\treviewCount,\n\t\tnewCount,\n\t\ttopScore: scores.length > 0 ? Math.max(...scores) : 0,\n\t\tbottomScore: scores.length > 0 ? Math.min(...scores) : 0,\n\t\tscoreRange: scores.length > 0 ? [Math.min(...scores), Math.max(...scores)] : [0, 0],\n\t\tavgScore: scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0\n\t};\n}\n/**\n* Build source selection breakdown.\n*/\nfunction buildSourceBreakdown(sourceId, sourceName, allCards) {\n\tconst sourceCards = allCards.filter((c) => c.courseId === sourceId);\n\tconst selectedCards = sourceCards.filter((c) => c.selected);\n\treturn {\n\t\tsourceId,\n\t\tsourceName,\n\t\treviewsProvided: sourceCards.filter((c) => c.origin === \"review\").length,\n\t\tnewProvided: sourceCards.filter((c) => c.origin === \"new\").length,\n\t\treviewsSelected: selectedCards.filter((c) => c.origin === \"review\").length,\n\t\tnewSelected: selectedCards.filter((c) => c.origin === \"new\").length,\n\t\ttotalSelected: selectedCards.length,\n\t\tselectionRate: sourceCards.length > 0 ? selectedCards.length / sourceCards.length * 100 : 0\n\t};\n}\n/**\n* Capture a mixer run for later inspection.\n*/\nfunction captureMixerRun(mixerType, batches, sourceIds, sourceNames, requestedLimit, quotaPerSource, mixedResult) {\n\tconst sourceSummaries = batches.map((batch, idx) => buildSourceSummary(batch, sourceIds[idx] || `source-${idx}`, sourceNames[idx]));\n\tconst selectedIds = new Set(mixedResult.map((c) => c.cardId));\n\tconst sourceRankings = /* @__PURE__ */ new Map();\n\tbatches.forEach((batch) => {\n\t\tconst sorted = [...batch.weighted].sort((a, b) => b.score - a.score);\n\t\tconst rankings = /* @__PURE__ */ new Map();\n\t\tsorted.forEach((card, idx) => {\n\t\t\trankings.set(card.cardId, idx + 1);\n\t\t});\n\t\tsourceRankings.set(sourceIds[batch.sourceIndex] || `source-${batch.sourceIndex}`, rankings);\n\t});\n\tconst mixRankings = /* @__PURE__ */ new Map();\n\tmixedResult.forEach((card, idx) => {\n\t\tmixRankings.set(card.cardId, idx + 1);\n\t});\n\tconst allCardsMap = /* @__PURE__ */ new Map();\n\tbatches.forEach((batch) => {\n\t\tbatch.weighted.forEach((card) => {\n\t\t\tallCardsMap.set(card.cardId, card);\n\t\t});\n\t});\n\tconst cards = Array.from(allCardsMap.values()).map((card) => ({\n\t\tcardId: card.cardId,\n\t\tcourseId: card.courseId,\n\t\torigin: getCardOrigin(card),\n\t\tscore: card.score,\n\t\tsourceIndex: batches.findIndex((b) => b.weighted.some((c) => c.cardId === card.cardId)),\n\t\tselected: selectedIds.has(card.cardId),\n\t\trankInSource: sourceRankings.get(card.courseId)?.get(card.cardId),\n\t\trankInMix: mixRankings.get(card.cardId)\n\t}));\n\tconst sourceBreakdowns = Array.from(new Set(sourceIds.filter((id) => id))).map((sourceId, idx) => buildSourceBreakdown(sourceId, sourceNames[idx], cards));\n\tconst report = {\n\t\trunId: `mix-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n\t\ttimestamp: /* @__PURE__ */ new Date(),\n\t\tmixerType,\n\t\trequestedLimit,\n\t\tquotaPerSource,\n\t\tsourceSummaries,\n\t\tcards,\n\t\tfinalCount: mixedResult.length,\n\t\treviewsSelected: mixedResult.filter((c) => getCardOrigin(c) === \"review\").length,\n\t\tnewSelected: mixedResult.filter((c) => getCardOrigin(c) === \"new\").length,\n\t\tsourceBreakdowns\n\t};\n\trunHistory.unshift(report);\n\tif (runHistory.length > MAX_RUNS) runHistory.pop();\n}\n/**\n* Print summary of a single mixer run.\n*/\nfunction printMixerSummary(run) {\n\tconsole.group(`🎨 Mixer Run: ${run.mixerType}`);\n\tlogger.print(`Run ID: ${run.runId}`);\n\tlogger.print(`Time: ${run.timestamp.toISOString()}`);\n\tlogger.print(`Config: limit=${run.requestedLimit}${run.quotaPerSource ? `, quota/source=${run.quotaPerSource}` : \"\"}`);\n\tconsole.group(`📥 Input: ${run.sourceSummaries.length} sources`);\n\tfor (const src of run.sourceSummaries) {\n\t\tlogger.print(` ${src.sourceName || src.sourceId}: ${src.totalCards} cards (${src.reviewCount} reviews, ${src.newCount} new)`);\n\t\tlogger.print(` Score range: [${src.scoreRange[0].toFixed(2)}, ${src.scoreRange[1].toFixed(2)}], avg: ${src.avgScore.toFixed(2)}`);\n\t}\n\tconsole.groupEnd();\n\tconsole.group(`📤 Output: ${run.finalCount} cards selected (${run.reviewsSelected} reviews, ${run.newSelected} new)`);\n\tfor (const breakdown of run.sourceBreakdowns) {\n\t\tconst name = breakdown.sourceName || breakdown.sourceId;\n\t\tlogger.print(` ${name}: ${breakdown.totalSelected} selected (${breakdown.reviewsSelected} reviews, ${breakdown.newSelected} new) - ${breakdown.selectionRate.toFixed(1)}% selection rate`);\n\t}\n\tconsole.groupEnd();\n\tconsole.groupEnd();\n}\n/**\n* Console API object exposed on window.skuilder.mixer\n*/\nconst mixerDebugAPI = {\n\tget runs() {\n\t\treturn [...runHistory];\n\t},\n\tshowRun(idOrIndex = 0) {\n\t\tif (runHistory.length === 0) {\n\t\t\tlogger.print(\"[Mixer Debug] No runs captured yet.\");\n\t\t\treturn;\n\t\t}\n\t\tlet run;\n\t\tif (typeof idOrIndex === \"number\") {\n\t\t\trun = runHistory[idOrIndex];\n\t\t\tif (!run) {\n\t\t\t\tlogger.print(`[Mixer Debug] No run found at index ${idOrIndex}. History length: ${runHistory.length}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\trun = runHistory.find((r) => r.runId.endsWith(idOrIndex));\n\t\t\tif (!run) {\n\t\t\t\tlogger.print(`[Mixer Debug] No run found matching ID '${idOrIndex}'.`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tprintMixerSummary(run);\n\t},\n\tshowLastMix() {\n\t\tthis.showRun(0);\n\t},\n\texplainSourceBalance() {\n\t\tif (runHistory.length === 0) {\n\t\t\tlogger.print(\"[Mixer Debug] No runs captured yet.\");\n\t\t\treturn;\n\t\t}\n\t\tconst run = runHistory[0];\n\t\tconsole.group(\"⚖️ Source Balance Analysis\");\n\t\tlogger.print(`Mixer: ${run.mixerType}`);\n\t\tlogger.print(`Requested limit: ${run.requestedLimit}`);\n\t\tif (run.quotaPerSource) logger.print(`Quota per source: ${run.quotaPerSource}`);\n\t\tconsole.group(\"Input Distribution:\");\n\t\tfor (const src of run.sourceSummaries) {\n\t\t\tconst name = src.sourceName || src.sourceId;\n\t\t\tlogger.print(`${name}:`);\n\t\t\tlogger.print(` Provided: ${src.totalCards} cards (${src.reviewCount} reviews, ${src.newCount} new)`);\n\t\t\tlogger.print(` Score range: [${src.scoreRange[0].toFixed(2)}, ${src.scoreRange[1].toFixed(2)}]`);\n\t\t}\n\t\tconsole.groupEnd();\n\t\tconsole.group(\"Selection Results:\");\n\t\tfor (const breakdown of run.sourceBreakdowns) {\n\t\t\tconst name = breakdown.sourceName || breakdown.sourceId;\n\t\t\tlogger.print(`${name}:`);\n\t\t\tlogger.print(` Selected: ${breakdown.totalSelected}/${breakdown.reviewsProvided + breakdown.newProvided} (${breakdown.selectionRate.toFixed(1)}%)`);\n\t\t\tlogger.print(` Reviews: ${breakdown.reviewsSelected}/${breakdown.reviewsProvided}`);\n\t\t\tlogger.print(` New: ${breakdown.newSelected}/${breakdown.newProvided}`);\n\t\t\tif (breakdown.reviewsProvided > 0 && breakdown.reviewsSelected === 0) logger.print(` ⚠️ Had reviews but none selected!`);\n\t\t\tif (breakdown.totalSelected === 0 && breakdown.reviewsProvided + breakdown.newProvided > 0) logger.print(` ⚠️ Had cards but none selected!`);\n\t\t}\n\t\tconsole.groupEnd();\n\t\tconst selectionRates = run.sourceBreakdowns.map((b) => b.selectionRate);\n\t\tconst avgRate = selectionRates.reduce((a, b) => a + b, 0) / selectionRates.length;\n\t\tconst maxDeviation = Math.max(...selectionRates.map((r) => Math.abs(r - avgRate)));\n\t\tif (maxDeviation > 20) {\n\t\t\tlogger.print(`\\n⚠️ Significant imbalance detected (max deviation: ${maxDeviation.toFixed(1)}%)`);\n\t\t\tlogger.print(\"Possible causes:\");\n\t\t\tlogger.print(\" - Score range differences between sources\");\n\t\t\tlogger.print(\" - One source has much better quality cards\");\n\t\t\tlogger.print(\" - Different card availability (reviews vs new)\");\n\t\t}\n\t\tconsole.groupEnd();\n\t},\n\tcompareScores() {\n\t\tif (runHistory.length === 0) {\n\t\t\tlogger.print(\"[Mixer Debug] No runs captured yet.\");\n\t\t\treturn;\n\t\t}\n\t\tconst run = runHistory[0];\n\t\tconsole.group(\"📊 Score Distribution Comparison\");\n\t\tconsole.table(run.sourceSummaries.map((src) => ({\n\t\t\tsource: src.sourceName || src.sourceId,\n\t\t\tcards: src.totalCards,\n\t\t\tmin: src.bottomScore.toFixed(3),\n\t\t\tmax: src.topScore.toFixed(3),\n\t\t\tavg: src.avgScore.toFixed(3),\n\t\t\trange: (src.topScore - src.bottomScore).toFixed(3)\n\t\t})));\n\t\tconst ranges = run.sourceSummaries.map((s) => s.topScore - s.bottomScore);\n\t\tconst avgScores = run.sourceSummaries.map((s) => s.avgScore);\n\t\tconst rangeDiff = Math.max(...ranges) - Math.min(...ranges);\n\t\tconst avgDiff = Math.max(...avgScores) - Math.min(...avgScores);\n\t\tif (rangeDiff > .3 || avgDiff > .2) {\n\t\t\tlogger.print(\"\\n⚠️ Significant score distribution differences detected\");\n\t\t\tlogger.print(\"This may cause one source to dominate selection if using global sorting (not quota-based)\");\n\t\t}\n\t\tconsole.groupEnd();\n\t},\n\tshowCard(cardId) {\n\t\tfor (const run of runHistory) {\n\t\t\tconst card = run.cards.find((c) => c.cardId === cardId);\n\t\t\tif (card) {\n\t\t\t\tconst source = run.sourceSummaries.find((s) => s.sourceIndex === card.sourceIndex);\n\t\t\t\tconsole.group(`🎴 Card: ${cardId}`);\n\t\t\t\tlogger.print(`Course: ${card.courseId}`);\n\t\t\t\tlogger.print(`Source: ${source?.sourceName || source?.sourceId || \"unknown\"}`);\n\t\t\t\tlogger.print(`Origin: ${card.origin}`);\n\t\t\t\tlogger.print(`Score: ${card.score.toFixed(3)}`);\n\t\t\t\tif (card.rankInSource) logger.print(`Rank in source: #${card.rankInSource}`);\n\t\t\t\tif (card.rankInMix) logger.print(`Rank in mixed results: #${card.rankInMix}`);\n\t\t\t\tlogger.print(`Selected: ${card.selected ? \"Yes ✅\" : \"No ❌\"}`);\n\t\t\t\tif (!card.selected && card.rankInSource) {\n\t\t\t\t\tlogger.print(\"\\nWhy not selected:\");\n\t\t\t\t\tif (run.quotaPerSource && card.rankInSource > run.quotaPerSource) logger.print(` - Ranked #${card.rankInSource} in source, but quota was ${run.quotaPerSource}`);\n\t\t\t\t\tlogger.print(\" - Check score compared to selected cards using .showRun()\");\n\t\t\t\t}\n\t\t\t\tconsole.groupEnd();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tlogger.print(`[Mixer Debug] Card '${cardId}' not found in recent runs.`);\n\t},\n\tlistRuns() {\n\t\tif (runHistory.length === 0) {\n\t\t\tlogger.print(\"[Mixer Debug] No runs captured yet.\");\n\t\t\treturn;\n\t\t}\n\t\tconsole.table(runHistory.map((r) => ({\n\t\t\tid: r.runId.slice(-8),\n\t\t\ttime: r.timestamp.toLocaleTimeString(),\n\t\t\tmixer: r.mixerType,\n\t\t\tsources: r.sourceSummaries.length,\n\t\t\tselected: r.finalCount,\n\t\t\treviews: r.reviewsSelected,\n\t\t\tnew: r.newSelected\n\t\t})));\n\t},\n\texport() {\n\t\tconst json = JSON.stringify(runHistory, null, 2);\n\t\tlogger.print(\"[Mixer Debug] Run history exported. Copy the returned string or use:\");\n\t\tlogger.print(\" copy(window.skuilder.mixer.export())\");\n\t\treturn json;\n\t},\n\tclear() {\n\t\trunHistory.length = 0;\n\t\tlogger.print(\"[Mixer Debug] Run history cleared.\");\n\t},\n\thelp() {\n\t\tlogger.print(`\n🎨 Mixer Debug API\n\nCommands:\n .showLastMix() Show summary of most recent mixer run\n .showRun(id|index) Show summary of a specific run (by index or ID suffix)\n .explainSourceBalance() Analyze source balance and selection patterns\n .compareScores() Compare score distributions across sources\n .showCard(cardId) Show mixer decisions for a specific card\n .listRuns() List all captured runs in table format\n .export() Export run history as JSON for bug reports\n .clear() Clear run history\n .runs Access raw run history array\n .help() Show this help message\n\nExample:\n window.skuilder.mixer.showLastMix()\n window.skuilder.mixer.explainSourceBalance()\n window.skuilder.mixer.compareScores()\n`);\n\t}\n};\n/**\n* Mount the debug API on window.skuilder.mixer\n*/\nfunction mountMixerDebugger() {\n\tif (typeof window === \"undefined\") return;\n\tconst win = window;\n\twin.skuilder = win.skuilder || {};\n\twin.skuilder.mixer = mixerDebugAPI;\n}\nmountMixerDebugger();\n//#endregion\nexport { captureMixerRun, mixerDebugAPI, mountMixerDebugger };\n\n//# sourceMappingURL=MixerDebugger.mjs.map","import \"../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../util/logger.mjs\";\n//#region src/study/SessionOverlay.ts\nlet activeController = null;\n/** Called by SessionController's constructor. Pass `null` to deregister. */\nfunction registerActiveController(controller) {\n\tactiveController = controller;\n}\nfunction getActiveController() {\n\treturn activeController;\n}\nconst OVERLAY_ID = \"skuilder-session-overlay\";\nconst POLL_MS = 300;\n/**\n* Cap on how many cards a queue lists by default. Queues at or below this show\n* in full; larger ones show the first INLINE_THRESHOLD then a clickable\n* \"… +N more\" affordance that expands to the full list (and back).\n*/\nconst INLINE_THRESHOLD = 5;\n/** Braille spinner frames, advanced once per render tick (≈POLL_MS cadence). */\nconst SPINNER_FRAMES = [\n\t\"⠋\",\n\t\"⠙\",\n\t\"⠹\",\n\t\"⠸\",\n\t\"⠼\",\n\t\"⠴\",\n\t\"⠦\",\n\t\"⠧\",\n\t\"⠇\",\n\t\"⠏\"\n];\nlet spinnerFrame = 0;\nlet overlayEl = null;\nlet pollHandle = null;\n/**\n* Most recent snapshot rendered, retained so the click-to-copy button can\n* serialise exactly what is on screen at click time (decoupled from the poll).\n*/\nlet lastSnapshot = null;\n/** Epoch ms until which the copy button shows its \"copied\" confirmation. */\nlet copyFlashUntil = 0;\n/**\n* When minified, the overlay collapses to just its header bar (title + copy +\n* restore button), suppressing all body sections. The poll keeps running so\n* `lastSnapshot` — and therefore the copy button — stays current underneath.\n*/\nlet minified = false;\n/** Expansion state for collapsible (large) lists, preserved across re-renders. */\nconst expanded = {\n\tsupplyQ: false,\n\tfailedQ: false,\n\tdrawn: false\n};\n/**\n* Toggle the pinned overlay on/off. No-ops (with a console hint) when there is\n* no DOM, so it is safe to call from any host environment.\n*/\nfunction toggleSessionOverlay() {\n\tif (typeof document === \"undefined\") {\n\t\tlogger.print(\"[Session Overlay] No DOM available (non-browser host); overlay unavailable.\");\n\t\treturn;\n\t}\n\tif (overlayEl) {\n\t\tteardown();\n\t\tlogger.print(\"[Session Overlay] Hidden.\");\n\t} else {\n\t\tmount();\n\t\tlogger.print(\"[Session Overlay] Shown. Toggle off with window.skuilder.session.dbgOverlay().\");\n\t}\n}\nfunction mount() {\n\tminified = false;\n\toverlayEl = document.createElement(\"div\");\n\toverlayEl.id = OVERLAY_ID;\n\tObject.assign(overlayEl.style, {\n\t\tposition: \"fixed\",\n\t\ttop: \"8px\",\n\t\tleft: \"8px\",\n\t\tzIndex: \"2147483647\",\n\t\tmaxWidth: \"320px\",\n\t\tmaxHeight: \"90vh\",\n\t\toverflowY: \"auto\",\n\t\tpadding: \"8px 10px\",\n\t\tbackground: \"rgba(17, 24, 39, 0.92)\",\n\t\tcolor: \"#e5e7eb\",\n\t\tfont: \"11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace\",\n\t\tborderRadius: \"6px\",\n\t\tboxShadow: \"0 4px 16px rgba(0,0,0,0.4)\",\n\t\tpointerEvents: \"auto\",\n\t\tuserSelect: \"none\"\n\t});\n\tdocument.body.appendChild(overlayEl);\n\trender();\n\tpollHandle = setInterval(render, POLL_MS);\n}\nfunction teardown() {\n\tif (pollHandle !== null) {\n\t\tclearInterval(pollHandle);\n\t\tpollHandle = null;\n\t}\n\tif (overlayEl?.parentNode) overlayEl.parentNode.removeChild(overlayEl);\n\toverlayEl = null;\n}\nfunction render() {\n\tif (!overlayEl) return;\n\tspinnerFrame++;\n\tconst ctrl = getActiveController();\n\tif (!ctrl) {\n\t\tlastSnapshot = null;\n\t\toverlayEl.innerHTML = headerHtml() + (minified ? \"\" : `<div style=\"opacity:.65\">No active session.</div>`);\n\t\tattachHandlers();\n\t\treturn;\n\t}\n\tconst s = ctrl.getDebugSnapshot();\n\tlastSnapshot = s;\n\tif (minified) {\n\t\toverlayEl.innerHTML = headerHtml();\n\t\tattachHandlers();\n\t\treturn;\n\t}\n\toverlayEl.innerHTML = headerHtml() + replanHtml(s) + metaHtml(s) + hintsHtml(s.sessionHints) + backlogHtml(s.reviewBacklog) + strategyPressureHtml(s.strategyPressure) + queueHtml(\"supplyQ\", \"supplyQ\", s.supplyQ) + queueHtml(\"failedQ\", \"failedQ\", s.failedQ) + drawnHtml(\"drawn\", s.drawnCards);\n\tattachHandlers();\n}\n/** (Re-)bind click handlers after each innerHTML rewrite. */\nfunction attachHandlers() {\n\tif (!overlayEl) return;\n\toverlayEl.querySelectorAll(\"[data-q]\").forEach((el) => {\n\t\tel.onclick = () => {\n\t\t\tconst key = el.dataset.q;\n\t\t\tif (!key) return;\n\t\t\texpanded[key] = !expanded[key];\n\t\t\trender();\n\t\t};\n\t});\n\tconst copyBtn = overlayEl.querySelector(\"[data-copy]\");\n\tif (copyBtn) copyBtn.onclick = (ev) => {\n\t\tev.stopPropagation();\n\t\tcopySnapshot();\n\t};\n\tconst minBtn = overlayEl.querySelector(\"[data-min]\");\n\tif (minBtn) minBtn.onclick = (ev) => {\n\t\tev.stopPropagation();\n\t\tminified = !minified;\n\t\trender();\n\t};\n}\n/** Serialise the on-screen snapshot to the clipboard, with a transient flash. */\nfunction copySnapshot() {\n\tconst text = snapshotToText(lastSnapshot);\n\tconst flash = () => {\n\t\tcopyFlashUntil = Date.now() + 1200;\n\t\trender();\n\t};\n\tconst clip = typeof navigator !== \"undefined\" ? navigator.clipboard : void 0;\n\tif (clip?.writeText) clip.writeText(text).then(flash, (err) => {\n\t\tlogger.warn(`[Session Overlay] Clipboard write failed: ${String(err)}`);\n\t});\n\telse logger.print(`[Session Overlay] Clipboard unavailable; snapshot follows:\\n${text}`);\n}\nfunction headerHtml() {\n\tconst flashing = Date.now() < copyFlashUntil;\n\treturn `<div style=\"font-weight:600;color:#93c5fd;margin-bottom:${minified ? 0 : 4}px\">${`<span data-copy style=\"cursor:pointer;float:right;font-weight:400;color:${flashing ? \"#86efac\" : \"#93c5fd\"};border:1px solid currentColor;border-radius:4px;padding:0 4px;line-height:1.3\">${flashing ? \"✓ copied\" : \"⎘ copy\"}</span>`}${`<span data-min title=\"${minified ? \"Restore\" : \"Minify\"}\" style=\"cursor:pointer;float:right;font-weight:400;color:#93c5fd;border:1px solid currentColor;border-radius:4px;padding:0 5px;margin-right:4px;line-height:1.3\">${minified ? \"▢\" : \"—\"}</span>`}⚙ SessionController</div>`;\n}\nfunction replanHtml(s) {\n\tif (!s.replanActive) return `<div style=\"margin-bottom:6px;opacity:.45\">○ idle</div>`;\n\treturn `<div style=\"margin-bottom:6px;color:#fde047\">${SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length]} replanning <span style=\"opacity:.85\">[${esc(s.replanLabel ?? \"(auto)\")}]</span></div>`;\n}\nfunction metaHtml(s) {\n\treturn `<div style=\"margin-bottom:6px\">${[\n\t\t`time ${formatTime(s.secondsRemaining)}${s.hasCardGuarantee ? ` · <span style=\"color:#fbbf24\">guarantee ${s.minCardsGuarantee}</span>` : \"\"}`,\n\t\t`well-indicated left: ${s.wellIndicatedRemaining}`,\n\t\t`current: ${s.currentCard ? esc(s.currentCard) : \"<span style=\\\"opacity:.6\\\">—</span>\"}`\n\t].map((r) => `<div>${r}</div>`).join(\"\")}</div>`;\n}\nfunction hintsHtml(h) {\n\tconst parts = [];\n\tif (h) {\n\t\tif (h.boostTags && Object.keys(h.boostTags).length) parts.push(`boost: ` + Object.entries(h.boostTags).map(([k, v]) => `${esc(k)}<span style=\"opacity:.6\">×${v}</span>`).join(\", \"));\n\t\tif (h.boostCards && Object.keys(h.boostCards).length) parts.push(`boostCards: ` + Object.entries(h.boostCards).map(([k, v]) => `${esc(k)}<span style=\"opacity:.6\">×${v}</span>`).join(\", \"));\n\t\tif (h.requireCards?.length) parts.push(`require: ${h.requireCards.map(esc).join(\", \")}`);\n\t\tif (h.requireTags?.length) parts.push(`requireTags: ${h.requireTags.map(esc).join(\", \")}`);\n\t\tif (h.excludeTags?.length) parts.push(`exclude: ${h.excludeTags.map(esc).join(\", \")}`);\n\t\tif (h.excludeCards?.length) parts.push(`excludeCards: ${h.excludeCards.map(esc).join(\", \")}`);\n\t}\n\treturn `<div style=\"margin-bottom:6px\"><div style=\"color:#86efac\">sessionHints</div>${parts.length ? parts.map((p) => `<div style=\"margin-left:6px\">${p}</div>`).join(\"\") : `<div style=\"margin-left:6px;opacity:.6\">none</div>`}</div>`;\n}\n/**\n* SRS backlog panel — answers \"is review starvation permanent?\". Backlog\n* pressure is a multiplier (×1.0 healthy → exponential, uncapped) on review\n* urgency; reviews are no longer clamped to 1.0, so under a heavy backlog they\n* scale up to compete with (and exceed) new cards. There's no ceiling, so\n* reviews always win eventually — the panel shows how far the current\n* multiplier is from that crossover, not whether it's \"maxed\": compare\n* `top review` here against the supplyQ head score to see how much further\n* the backlog needs to grow (or the boosts need to relax) before reviews win\n* slots.\n*/\nfunction backlogHtml(backlog) {\n\tif (!backlog.length) return \"\";\n\treturn `<div style=\"margin-bottom:6px\"><div style=\"color:#93c5fd\">review backpressure</div>${backlog.map((b) => {\n\t\tconst hot = b.backlogMultiplier >= 3;\n\t\tconst multColor = b.backlogMultiplier <= 1 ? \"#86efac\" : hot ? \"#fca5a5\" : \"#fcd34d\";\n\t\tconst headroom = b.backlogMultiplier > 1 ? `climbing (×${b.backlogGrowthRate.toFixed(2)} per ${b.healthyBacklog} of mass in excess, unbounded)` : \"healthy — no pressure\";\n\t\tconst mass = b.reviewMass !== null ? ` · mass ${b.reviewMass.toFixed(1)}` : \"\";\n\t\tconst top = b.topReviewScore !== null ? b.topReviewScore.toFixed(2) : \"—\";\n\t\tconst next = b.nextDueIn ? ` <span style=\"opacity:.6\">· next due ${esc(b.nextDueIn)}</span>` : \"\";\n\t\treturn `<div style=\"margin-left:6px\"><span style=\"opacity:.7\">${esc(b.courseId.slice(0, 8))}</span> due ${b.dueNow}/${b.scheduledTotal}${mass} <span style=\"opacity:.6\">(healthy mass ${b.healthyBacklog})</span>${next}<div style=\"margin-left:6px\">pressure <span style=\"color:${multColor}\">×${b.backlogMultiplier.toFixed(2)}</span> <span style=\"opacity:.6\">${headroom} · top review ${top}</span></div></div>`;\n\t}).join(\"\")}</div>`;\n}\n/**\n* Colour for a pressure multiplier. Green at ×1.0 (no pressure); when the\n* gauge is capped, amber → red by fraction of headroom used; when unbounded,\n* fall back to the SRS panel's absolute threshold (×3 = hot).\n*/\nfunction pressureColor(multiplier, max) {\n\tif (multiplier <= 1.001) return \"#86efac\";\n\tif (max !== void 0 && max > 1) return (multiplier - 1) / (max - 1) >= .75 ? \"#fca5a5\" : \"#fcd34d\";\n\treturn multiplier >= 3 ? \"#fca5a5\" : \"#fcd34d\";\n}\n/** data-q keys land in HTML attributes; strip anything outside a safe set. */\nfunction toggleKey(raw) {\n\treturn raw.replace(/[^\\w:.|-]/g, \"_\");\n}\n/**\n* One gauge row: `label ×2.50/8 — detail`, with an item list underneath that\n* mirrors the queues' collapse behaviour (INLINE_THRESHOLD shown, \"+N more\"\n* expands).\n*/\nfunction gaugeHtml(sectionKey, g) {\n\tconst cap = g.max !== void 0 ? `<span style=\"opacity:.5\">/${g.max}</span>` : \"\";\n\tconst detail = g.detail ? ` <span style=\"opacity:.6\">${esc(g.detail)}</span>` : \"\";\n\tlet html = `<div style=\"margin-left:6px\">${esc(g.label)} <span style=\"color:${pressureColor(g.multiplier, g.max)}\">×${g.multiplier.toFixed(2)}</span>${cap}${detail}`;\n\tconst items = g.items ?? [];\n\tif (items.length > 0) {\n\t\tconst key = toggleKey(`sp|${sectionKey}|${g.id}`);\n\t\tconst isOpen = !!expanded[key];\n\t\tconst shown = isOpen ? items : items.slice(0, INLINE_THRESHOLD);\n\t\thtml += `<div style=\"margin-left:6px\">` + shown.map((it) => `<div style=\"white-space:nowrap;opacity:.75\">${esc(it.label)}${it.value ? ` <span style=\"opacity:.6\">${esc(it.value)}</span>` : \"\"}</div>`).join(\"\");\n\t\tif (items.length > INLINE_THRESHOLD) {\n\t\t\tconst footer = isOpen ? \"▾ show less\" : `… +${items.length - shown.length} more`;\n\t\t\thtml += `<div data-q=\"${key}\" style=\"cursor:pointer;opacity:.6\">${footer}</div>`;\n\t\t}\n\t\thtml += `</div>`;\n\t}\n\treturn html + `</div>`;\n}\n/**\n* Strategy backpressure panel — the generic counterpart of the SRS panel\n* above, fed by `captureStrategyPressure` pushes from navigation strategies\n* (built-in prescribed, or consumer-registered). Per source: gauge rows with\n* cap-aware colour, then a `top score` line that reads against the supplyQ\n* head exactly like the SRS panel's `top review`.\n*/\nfunction strategyPressureHtml(list) {\n\tif (!list.length) return \"\";\n\treturn `<div style=\"margin-bottom:6px\"><div style=\"color:#fdba74\">strategy backpressure</div>${list.map((s) => {\n\t\tconst sectionKey = `${s.source}:${s.courseId.slice(0, 8)}`;\n\t\tconst top = s.topScore !== null && s.topScore !== void 0 ? s.topScore.toFixed(2) : \"—\";\n\t\tconst hints = s.hintsLabel ? `<div style=\"margin-left:6px;opacity:.6\">hints: ${esc(s.hintsLabel)}</div>` : \"\";\n\t\treturn `<div style=\"margin-left:6px\"><span style=\"opacity:.7\">${esc(s.source)} · ${esc(s.courseId.slice(0, 8))}</span> <span style=\"opacity:.6\">top score ${top}</span>` + s.gauges.map((g) => gaugeHtml(sectionKey, g)).join(\"\") + hints + `</div>`;\n\t}).join(\"\")}</div>`;\n}\n/** Format a rank score for display: finite → 2dp, `+INF` → REQ (required). */\nfunction fmtScore(score) {\n\tif (score === void 0) return \"\";\n\tif (!Number.isFinite(score)) return \"REQ\";\n\treturn score.toFixed(2);\n}\n/** One supply/failed queue line: `cardID [r 0.82]` with origin-coloured tag. */\nfunction queueItemHtml(item) {\n\tconst tagColor = item.origin === \"review\" ? \"#93c5fd\" : \"#fcd34d\";\n\tconst score = fmtScore(item.score);\n\tconst label = `${item.origin === \"review\" ? \"r\" : \"n\"}${score ? \" \" + score : \"\"}`;\n\treturn `${esc(item.cardID)}<span style=\"color:${tagColor};opacity:.85\"> [${label}]</span>`;\n}\nfunction queueHtml(key, label, q) {\n\tconst collapsible = q.length > INLINE_THRESHOLD;\n\tconst isOpen = collapsible && expanded[key];\n\tconst caret = collapsible ? expanded[key] ? \"▾ \" : \"▸ \" : \"\";\n\tconst drawn = q.dequeueCount ? ` <span style=\"opacity:.5\">drawn ${q.dequeueCount}</span>` : \"\";\n\tconst titleStyle = collapsible ? \"cursor:pointer;color:#f9a8d4\" : \"color:#f9a8d4\";\n\tconst title = `<div${collapsible ? ` data-q=\"${key}\"` : \"\"} style=\"${titleStyle}\">${caret}${label}: ${q.length}${drawn}</div>`;\n\tif (!q.cards.length) return title + `<div style=\"margin:1px 0 6px 6px;opacity:.5\">empty</div>`;\n\tconst shown = isOpen ? q.cards : q.cards.slice(0, INLINE_THRESHOLD);\n\tconst hiddenCount = q.length - shown.length;\n\tlet body = `<ol style=\"margin:2px 0 ${collapsible ? 2 : 6}px 0;padding-left:20px\">` + shown.map((c) => `<li style=\"white-space:nowrap\">${queueItemHtml(c)}</li>`).join(\"\") + `</ol>`;\n\tif (collapsible) {\n\t\tconst footer = isOpen ? \"▾ show less\" : `… +${hiddenCount} more`;\n\t\tbody += `<div data-q=\"${key}\" style=\"cursor:pointer;margin:0 0 6px 20px;opacity:.6\">${footer}</div>`;\n\t}\n\treturn title + body;\n}\n/** Compact, colour-coded per-card glyph: ✓ correct, ✗ wrong, · info-only. */\nfunction outcomeGlyph(correct) {\n\tif (correct === true) return `<span style=\"color:#86efac\">✓</span>`;\n\tif (correct === false) return `<span style=\"color:#fca5a5\">✗</span>`;\n\treturn `<span style=\"opacity:.5\">·</span>`;\n}\n/**\n* Expandable list of every card the learner has interacted with this session.\n* Mirrors `queueHtml`'s collapse behaviour but renders richer per-card detail\n* (status, outcome, attempt count) since this is the audit trail, not a queue.\n*/\nfunction drawnHtml(key, drawn) {\n\tconst collapsible = drawn.length > INLINE_THRESHOLD;\n\tconst isOpen = collapsible && expanded[key];\n\tconst caret = collapsible ? expanded[key] ? \"▾ \" : \"▸ \" : \"\";\n\tconst titleStyle = collapsible ? \"cursor:pointer;color:#c4b5fd\" : \"color:#c4b5fd\";\n\tconst title = `<div${collapsible ? ` data-q=\"${key}\"` : \"\"} style=\"${titleStyle}\">${caret}drawn: ${drawn.length}</div>`;\n\tif (!drawn.length) return title + `<div style=\"margin:1px 0 6px 6px;opacity:.5\">none yet</div>`;\n\tconst shown = isOpen ? drawn : drawn.slice(0, INLINE_THRESHOLD);\n\tconst hiddenCount = drawn.length - shown.length;\n\tlet body = `<ol style=\"margin:2px 0 ${collapsible ? 2 : 6}px 0;padding-left:20px\">${shown.map((d) => {\n\t\tconst retries = d.attempts > 1 ? `<span style=\"opacity:.5\"> ×${d.attempts}</span>` : \"\";\n\t\tconst time = `<span style=\"opacity:.45\"> ${Math.round(d.timeSpentMs / 100) / 10}s</span>`;\n\t\treturn `<li style=\"white-space:nowrap\">${outcomeGlyph(d.correct)} ${esc(d.cardID)}<span style=\"opacity:.5\"> [${esc(d.status)}]</span>${retries}${time}</li>`;\n\t}).join(\"\")}</ol>`;\n\tif (collapsible) {\n\t\tconst footer = isOpen ? \"▾ show less\" : `… +${hiddenCount} more`;\n\t\tbody += `<div data-q=\"${key}\" style=\"cursor:pointer;margin:0 0 6px 20px;opacity:.6\">${footer}</div>`;\n\t}\n\treturn title + body;\n}\n/**\n* Plain-text rendering of a snapshot for the clipboard. Mirrors the on-screen\n* sections (without truncation) so a copied dump is a complete, paste-able\n* picture of session state at the moment of the click.\n*/\nfunction snapshotToText(s) {\n\tif (!s) return \"SessionController — no active session.\";\n\tconst lines = [];\n\tlines.push(\"=== SessionController ===\");\n\tlines.push(`time ${formatTime(s.secondsRemaining)}`);\n\tif (s.hasCardGuarantee) lines.push(`guarantee: ${s.minCardsGuarantee}`);\n\tlines.push(`well-indicated left: ${s.wellIndicatedRemaining}`);\n\tlines.push(`current: ${s.currentCard ?? \"—\"}`);\n\tlines.push(s.replanActive ? `replan: ACTIVE [${s.replanLabel ?? \"(auto)\"}]` : \"replan: idle\");\n\tlines.push(\"\");\n\tlines.push(\"sessionHints:\");\n\tconst h = s.sessionHints;\n\tconst hintParts = [];\n\tif (h) {\n\t\tif (h.boostTags && Object.keys(h.boostTags).length) hintParts.push(` boost: ${Object.entries(h.boostTags).map(([k, v]) => `${k}×${v}`).join(\", \")}`);\n\t\tif (h.boostCards && Object.keys(h.boostCards).length) hintParts.push(` boostCards: ${Object.entries(h.boostCards).map(([k, v]) => `${k}×${v}`).join(\", \")}`);\n\t\tif (h.requireCards?.length) hintParts.push(` require: ${h.requireCards.join(\", \")}`);\n\t\tif (h.requireTags?.length) hintParts.push(` requireTags: ${h.requireTags.join(\", \")}`);\n\t\tif (h.excludeTags?.length) hintParts.push(` exclude: ${h.excludeTags.join(\", \")}`);\n\t\tif (h.excludeCards?.length) hintParts.push(` excludeCards: ${h.excludeCards.join(\", \")}`);\n\t}\n\tlines.push(hintParts.length ? hintParts.join(\"\\n\") : \" none\");\n\tif (s.reviewBacklog.length) {\n\t\tlines.push(\"\");\n\t\tlines.push(\"review backpressure:\");\n\t\tfor (const b of s.reviewBacklog) {\n\t\t\tconst headroom = b.backlogMultiplier > 1 ? \"climbing\" : \"healthy\";\n\t\t\tconst top = b.topReviewScore !== null ? b.topReviewScore.toFixed(2) : \"—\";\n\t\t\tconst next = b.nextDueIn ? `, next due ${b.nextDueIn}` : \"\";\n\t\t\tconst mass = b.reviewMass !== null ? `, mass ${b.reviewMass.toFixed(1)}` : \"\";\n\t\t\tlines.push(` ${b.courseId.slice(0, 8)}: due ${b.dueNow}/${b.scheduledTotal}${mass} (healthy mass ${b.healthyBacklog})${next}; pressure ×${b.backlogMultiplier.toFixed(2)} ${headroom}; top review ${top}`);\n\t\t}\n\t}\n\tif (s.strategyPressure.length) {\n\t\tlines.push(\"\");\n\t\tlines.push(\"strategy backpressure:\");\n\t\tfor (const sp of s.strategyPressure) {\n\t\t\tconst top = sp.topScore !== null && sp.topScore !== void 0 ? sp.topScore.toFixed(2) : \"—\";\n\t\t\tlines.push(` ${sp.source} (${sp.courseId.slice(0, 8)}): top score ${top}`);\n\t\t\tfor (const g of sp.gauges) {\n\t\t\t\tconst cap = g.max !== void 0 ? `/${g.max}` : \"\";\n\t\t\t\tlines.push(` ${g.label} ×${g.multiplier.toFixed(2)}${cap}${g.detail ? ` — ${g.detail}` : \"\"}`);\n\t\t\t\tfor (const it of g.items ?? []) lines.push(` ${it.label}${it.value ? ` (${it.value})` : \"\"}`);\n\t\t\t}\n\t\t\tif (sp.hintsLabel) lines.push(` hints: ${sp.hintsLabel}`);\n\t\t}\n\t}\n\tconst queueText = (label, q) => {\n\t\tlines.push(\"\");\n\t\tlines.push(`${label}: ${q.length} (drawn ${q.dequeueCount})`);\n\t\tq.cards.forEach((c, i) => {\n\t\t\tconst score = fmtScore(c.score);\n\t\t\tconst tag = `${c.origin === \"review\" ? \"r\" : \"n\"}${score ? \" \" + score : \"\"}`;\n\t\t\tlines.push(` ${i + 1}. ${c.cardID} [${tag}]`);\n\t\t});\n\t};\n\tqueueText(\"supplyQ\", s.supplyQ);\n\tqueueText(\"failedQ\", s.failedQ);\n\tlines.push(\"\");\n\tlines.push(`drawn: ${s.drawnCards.length}`);\n\ts.drawnCards.forEach((d, i) => {\n\t\tconst mark = d.correct === true ? \"✓\" : d.correct === false ? \"✗\" : \"·\";\n\t\tconst time = `${Math.round(d.timeSpentMs / 100) / 10}s`;\n\t\tlines.push(` ${i + 1}. ${mark} ${d.cardID} [${d.status}] ×${d.attempts} ${time}`);\n\t});\n\treturn lines.join(\"\\n\");\n}\nfunction formatTime(totalSeconds) {\n\tconst s = Math.max(0, Math.round(totalSeconds));\n\treturn `${Math.floor(s / 60)}:${(s % 60).toString().padStart(2, \"0\")}`;\n}\nfunction esc(value) {\n\treturn value.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n//#endregion\nexport { getActiveController, registerActiveController, toggleSessionOverlay };\n\n//# sourceMappingURL=SessionOverlay.mjs.map","import \"../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../util/logger.mjs\";\nimport { clearRunHistory } from \"../core/navigators/PipelineDebugger.mjs\";\nimport { clearSrsBacklogDebug } from \"../core/navigators/SrsDebugger.mjs\";\nimport { clearStrategyPressureDebug } from \"../core/navigators/StrategyPressureDebugger.mjs\";\nimport { toggleSessionOverlay } from \"./SessionOverlay.mjs\";\n//#region src/study/SessionDebugger.ts\n/**\n* Active session state.\n*/\nlet activeSession = null;\nconst sessionHistory = [];\nconst MAX_HISTORY = 5;\n/**\n* Release pipeline run-history / SRS backlog debug memory from the previous\n* session before this session begins piling new runs on top of it. Must be\n* called before the first pipeline run of the new session (including the\n* bootstrap run in prepareSession) — clearing on session START rather than\n* END keeps post-session inspection, the dominant debugging workflow, fully\n* functional: a finished session's run history sits intact until the user\n* actually begins another one. It's a separate call from startSessionTracking\n* because that function can't run until supplyQ/failedQ are populated by the\n* bootstrap pipeline run, which would otherwise be cleared out from under it.\n*/\nfunction clearStaleSessionDebugState() {\n\tclearRunHistory();\n\tclearSrsBacklogDebug();\n\tclearStrategyPressureDebug();\n}\n/**\n* Start tracking a new session. The id is owned by `SessionController` — it is\n* minted at construction so pipeline runs from `prepareSession()` onward can\n* carry it.\n*/\nfunction startSessionTracking(sessionId, supplyQLength, failedQLength) {\n\tactiveSession = {\n\t\tsessionId,\n\t\tstartTime: /* @__PURE__ */ new Date(),\n\t\tinitialQueues: {\n\t\t\ttimestamp: /* @__PURE__ */ new Date(),\n\t\t\tsupplyQLength,\n\t\t\tfailedQLength\n\t\t},\n\t\tpresentations: [],\n\t\tqueueSnapshots: []\n\t};\n\tlogger.debug(`[SessionDebugger] Started tracking session: ${sessionId}`);\n}\n/**\n* Record a card presentation.\n*/\nfunction recordCardPresentation(cardId, courseId, courseName, origin, queueSource, score) {\n\tif (!activeSession) {\n\t\tlogger.warn(\"[SessionDebugger] No active session to record presentation\");\n\t\treturn;\n\t}\n\tactiveSession.presentations.push({\n\t\ttimestamp: /* @__PURE__ */ new Date(),\n\t\tsequenceNumber: activeSession.presentations.length + 1,\n\t\tcardId,\n\t\tcourseId,\n\t\tcourseName,\n\t\torigin,\n\t\tqueueSource,\n\t\tscore\n\t});\n}\n/**\n* Take a snapshot of current queue state.\n*/\nfunction snapshotQueues(supplyQLength, failedQLength, supplyQNext3) {\n\tif (!activeSession) return;\n\tactiveSession.queueSnapshots.push({\n\t\ttimestamp: /* @__PURE__ */ new Date(),\n\t\tsupplyQLength,\n\t\tfailedQLength,\n\t\tsupplyQNext3\n\t});\n}\n/**\n* End the current session tracking.\n*/\nfunction endSessionTracking() {\n\tif (!activeSession) return;\n\tactiveSession.endTime = /* @__PURE__ */ new Date();\n\tsessionHistory.unshift(activeSession);\n\tif (sessionHistory.length > MAX_HISTORY) sessionHistory.pop();\n\tlogger.debug(`[SessionDebugger] Ended session: ${activeSession.sessionId}`);\n\tactiveSession = null;\n}\n/**\n* Show current queue state (if session active).\n*/\nfunction showCurrentQueue() {\n\tif (!activeSession) {\n\t\tlogger.print(\"[Session Debug] No active session.\");\n\t\treturn;\n\t}\n\tconst latest = activeSession.queueSnapshots[activeSession.queueSnapshots.length - 1] || activeSession.initialQueues;\n\tconsole.group(\"📊 Current Queue State\");\n\tlogger.print(`Supply Queue: ${latest.supplyQLength} cards`);\n\tif (latest.supplyQNext3 && latest.supplyQNext3.length > 0) logger.print(` Next: ${latest.supplyQNext3.join(\", \")}`);\n\tlogger.print(`Failed Queue: ${latest.failedQLength} cards`);\n\tconsole.groupEnd();\n}\n/**\n* Show presentation history for current or last session.\n*/\nfunction showPresentationHistory(sessionIndex = 0) {\n\tconst session = sessionIndex === 0 && activeSession ? activeSession : sessionHistory[sessionIndex];\n\tif (!session) {\n\t\tlogger.print(`[Session Debug] No session found at index ${sessionIndex}`);\n\t\treturn;\n\t}\n\tconsole.group(`📜 Session History: ${session.sessionId}`);\n\tlogger.print(`Started: ${session.startTime.toLocaleTimeString()}`);\n\tif (session.endTime) logger.print(`Ended: ${session.endTime.toLocaleTimeString()}`);\n\tlogger.print(`Cards presented: ${session.presentations.length}`);\n\tif (session.presentations.length > 0) console.table(session.presentations.map((p) => ({\n\t\t\"#\": p.sequenceNumber,\n\t\tcourse: p.courseName || p.courseId.slice(0, 8),\n\t\torigin: p.origin,\n\t\tqueue: p.queueSource,\n\t\tscore: p.score?.toFixed(3) || \"-\",\n\t\ttime: p.timestamp.toLocaleTimeString()\n\t})));\n\tconsole.groupEnd();\n}\n/**\n* Analyze course interleaving pattern.\n*/\nfunction showInterleaving(sessionIndex = 0) {\n\tconst session = sessionIndex === 0 && activeSession ? activeSession : sessionHistory[sessionIndex];\n\tif (!session) {\n\t\tlogger.print(`[Session Debug] No session found at index ${sessionIndex}`);\n\t\treturn;\n\t}\n\tconsole.group(\"🔀 Interleaving Analysis\");\n\tconst courseCounts = /* @__PURE__ */ new Map();\n\tconst courseOrigins = /* @__PURE__ */ new Map();\n\tsession.presentations.forEach((p) => {\n\t\tconst name = p.courseName || p.courseId;\n\t\tcourseCounts.set(name, (courseCounts.get(name) || 0) + 1);\n\t\tif (!courseOrigins.has(name)) courseOrigins.set(name, {\n\t\t\treview: 0,\n\t\t\tnew: 0,\n\t\t\tfailed: 0\n\t\t});\n\t\tconst origins = courseOrigins.get(name);\n\t\torigins[p.origin]++;\n\t});\n\tlogger.print(\"Course distribution:\");\n\tconsole.table(Array.from(courseCounts.entries()).map(([course, count]) => {\n\t\tconst origins = courseOrigins.get(course);\n\t\treturn {\n\t\t\tcourse,\n\t\t\ttotal: count,\n\t\t\treviews: origins.review,\n\t\t\tnew: origins.new,\n\t\t\tfailed: origins.failed,\n\t\t\tpercentage: (count / session.presentations.length * 100).toFixed(1) + \"%\"\n\t\t};\n\t}));\n\tif (session.presentations.length > 0) {\n\t\tlogger.print(\"\\nPresentation sequence (first 20):\");\n\t\tconst sequence = session.presentations.slice(0, 20).map((p, idx) => `${idx + 1}. ${p.courseName || p.courseId.slice(0, 8)} (${p.origin})`).join(\"\\n\");\n\t\tlogger.print(sequence);\n\t}\n\tlet maxCluster = 0;\n\tlet currentCluster = 1;\n\tlet currentCourse = session.presentations[0]?.courseId;\n\tfor (let i = 1; i < session.presentations.length; i++) if (session.presentations[i].courseId === currentCourse) {\n\t\tcurrentCluster++;\n\t\tmaxCluster = Math.max(maxCluster, currentCluster);\n\t} else {\n\t\tcurrentCourse = session.presentations[i].courseId;\n\t\tcurrentCluster = 1;\n\t}\n\tif (maxCluster > 3) {\n\t\tlogger.print(`\\n⚠️ Detected clustering: max ${maxCluster} cards from same course in a row`);\n\t\tlogger.print(\"This suggests cards are sorted by score rather than round-robin by course.\");\n\t}\n\tconsole.groupEnd();\n}\n/**\n* Console API object exposed on window.skuilder.session\n*/\nconst sessionDebugAPI = {\n\tget sessions() {\n\t\treturn [...sessionHistory];\n\t},\n\tget active() {\n\t\treturn activeSession;\n\t},\n\tshowQueue() {\n\t\tshowCurrentQueue();\n\t},\n\tdbgOverlay() {\n\t\ttoggleSessionOverlay();\n\t},\n\tshowHistory(sessionIndex = 0) {\n\t\tshowPresentationHistory(sessionIndex);\n\t},\n\tshowInterleaving(sessionIndex = 0) {\n\t\tshowInterleaving(sessionIndex);\n\t},\n\tlistSessions() {\n\t\tif (activeSession) logger.print(`Active session: ${activeSession.sessionId} (${activeSession.presentations.length} cards presented)`);\n\t\tif (sessionHistory.length === 0) {\n\t\t\tlogger.print(\"[Session Debug] No completed sessions in history.\");\n\t\t\treturn;\n\t\t}\n\t\tconsole.table(sessionHistory.map((s, idx) => ({\n\t\t\tindex: idx,\n\t\t\tid: s.sessionId.slice(-8),\n\t\t\tstarted: s.startTime.toLocaleTimeString(),\n\t\t\tended: s.endTime?.toLocaleTimeString() || \"incomplete\",\n\t\t\tcards: s.presentations.length\n\t\t})));\n\t},\n\texport() {\n\t\tconst data = {\n\t\t\tactive: activeSession,\n\t\t\thistory: sessionHistory\n\t\t};\n\t\tconst json = JSON.stringify(data, null, 2);\n\t\tlogger.print(\"[Session Debug] Session data exported. Copy the returned string or use:\");\n\t\tlogger.print(\" copy(window.skuilder.session.export())\");\n\t\treturn json;\n\t},\n\tclear() {\n\t\tsessionHistory.length = 0;\n\t\tlogger.print(\"[Session Debug] Session history cleared.\");\n\t},\n\thelp() {\n\t\tlogger.print(`\n🎯 Session Debug API\n\nCommands:\n .dbgOverlay() Toggle the pinned live overlay (queues, hints, timer)\n .showQueue() Show current queue state (active session only)\n .showHistory(index?) Show presentation history (0=current/last, 1=previous, etc)\n .showInterleaving(index?) Analyze course interleaving pattern\n .listSessions() List all tracked sessions\n .export() Export session data as JSON for bug reports\n .clear() Clear session history\n .sessions Access raw session history array\n .active Access active session (if any)\n .help() Show this help message\n\nExample:\n window.skuilder.session.showHistory()\n window.skuilder.session.showInterleaving()\n window.skuilder.session.showQueue()\n`);\n\t}\n};\n/**\n* Mount the debug API on window.skuilder.session\n*/\nfunction mountSessionDebugger() {\n\tif (typeof window === \"undefined\") return;\n\tconst win = window;\n\twin.skuilder = win.skuilder || {};\n\twin.skuilder.session = sessionDebugAPI;\n}\nmountSessionDebugger();\n//#endregion\nexport { clearStaleSessionDebugState, endSessionTracking, mountSessionDebugger, recordCardPresentation, sessionDebugAPI, snapshotQueues, startSessionTracking };\n\n//# sourceMappingURL=SessionDebugger.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { newInterval } from \"../SpacedRepetition.mjs\";\nimport { isReview } from \"../../core/interfaces/contentSource.mjs\";\nimport moment from \"moment\";\n//#region src/study/services/SrsService.ts\n/**\n* Service responsible for Spaced Repetition System (SRS) scheduling logic.\n*/\nvar SrsService = class {\n\tuser;\n\tconstructor(user) {\n\t\tthis.user = user;\n\t}\n\t/**\n\t* Remove a scheduled review from the user's database.\n\t* Used to clean up orphaned reviews (e.g., card deleted from course DB).\n\t*/\n\tremoveReview(reviewID) {\n\t\tlogger.info(`[SrsService] Removing orphaned scheduled review: ${reviewID}`);\n\t\tthis.user.removeScheduledCardReview(reviewID);\n\t}\n\t/**\n\t* Calculates the next review time for a card based on its history and\n\t* schedules it in the user's database.\n\t* @param history The full history of the card.\n\t* @param item The study session item, used to determine if a previous review needs to be cleared.\n\t*/\n\tasync scheduleReview(history, item) {\n\t\tconst nextInterval = newInterval(this.user, history);\n\t\tconst nextReviewTime = moment.utc().add(nextInterval, \"seconds\");\n\t\tif (isReview(item)) {\n\t\t\tlogger.info(`[SrsService] Removing previously scheduled review for: ${item.cardID}`);\n\t\t\tthis.user.removeScheduledCardReview(item.reviewID);\n\t\t}\n\t\tthis.user.scheduleCardReview({\n\t\t\tuser: this.user.getUsername(),\n\t\t\tcourse_id: history.courseID,\n\t\t\tcard_id: history.cardID,\n\t\t\ttime: nextReviewTime,\n\t\t\tscheduledFor: item.contentSourceType,\n\t\t\tschedulingAgentId: item.contentSourceID\n\t\t});\n\t}\n};\n//#endregion\nexport { SrsService };\n\n//# sourceMappingURL=SrsService.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { pushTagPresentation } from \"@vue-skuilder/common\";\n//#region src/study/services/tagRecent.ts\n/**\n* Mastery signal: per-tag ring buffer of recent presentations.\n*\n* Written on the same path as the per-tag ELO update, one entry per\n* *presentation* of a card. Retries within a presentation (a record with\n* `priorAttemps > 0`, or any record after the first on the current card)\n* are not evidence and add nothing — including the \"dismiss-failed\" final\n* penalty, which reaches the ELO path on a retry record.\n*\n* Only tags the question actually graded (numeric perf) get an entry;\n* count-only exposure tags (`null`) carry no correctness signal.\n*/\n/** The record for the presentation being graded, or null if none is visible. */\nfunction currentRecord(records) {\n\treturn records.length ? records[records.length - 1] : null;\n}\n/**\n* Whether the record under grading is the first attempt of its presentation.\n*\n* `priorAttemps` is the authoritative marker (written by the question view).\n* When it is absent (non-question records, or a caller that did not push the\n* record onto `currentCard.records`), fall back to the presentation's record\n* count. With no record visible at all we cannot tell, and say no.\n*/\nfunction isFirstAttempt(records) {\n\tconst rec = currentRecord(records);\n\tif (!rec) return false;\n\tconst prior = rec.priorAttemps;\n\tif (typeof prior === \"number\") return prior === 0;\n\treturn records.length === 1;\n}\n/**\n* Append a presentation entry to every scored tag in `perf`, mutating\n* `userElo.tags[tag]` in place (each rank object is replaced, not mutated).\n* No-op for retries. Returns the tags that received an entry.\n*/\nfunction recordTagPresentations(userElo, perf, records, cardId, at) {\n\tif (!isFirstAttempt(records)) return [];\n\tconst ok = currentRecord(records)?.isCorrect === true;\n\tconst written = [];\n\tfor (const [tag, score] of Object.entries(perf)) {\n\t\tif (tag === \"_global\") continue;\n\t\tif (typeof score !== \"number\") continue;\n\t\tconst rank = userElo.tags[tag] ?? {\n\t\t\tscore: userElo.global.score,\n\t\t\tcount: 0\n\t\t};\n\t\tconst entry = {\n\t\t\tat,\n\t\t\tok,\n\t\t\tperf: score,\n\t\t\tcard: cardId\n\t\t};\n\t\tuserElo.tags[tag] = pushTagPresentation(rank, entry);\n\t\twritten.push(tag);\n\t}\n\treturn written;\n}\n//#endregion\nexport { recordTagPresentations };\n\n//# sourceMappingURL=tagRecent.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { recordTagPresentations } from \"./tagRecent.mjs\";\nimport { adjustCourseScores, adjustCourseScoresPerTag, isCountOnlyTag, toCourseElo } from \"@vue-skuilder/common\";\n//#region src/study/services/EloService.ts\n/**\n* The question's performance with bookkeeping-role tags (`expose`, `intro`;\n* see common's tagRoles.ts) as count-only. A score sent for one is counted,\n* not graded, and logged: it's a question-side slip against the convention.\n*/\nfunction withCountOnlyRoles(perf, cardId) {\n\tconst out = { ...perf };\n\tconst counted = [];\n\tfor (const [tag, score] of Object.entries(perf)) {\n\t\tif (tag === \"_global\" || score === null || !isCountOnlyTag(tag)) continue;\n\t\tout[tag] = null;\n\t\tcounted.push(tag);\n\t}\n\tif (counted.length) logger.warn(`[EloService] ${cardId} sent scores for bookkeeping tags [${counted.join(\", \")}]; counted, not graded`);\n\treturn out;\n}\n/**\n* Service responsible for ELO rating calculations and updates.\n*/\nvar EloService = class {\n\tdataLayer;\n\tuser;\n\t/** Per course ID: its compiled `CourseConfig.qaUsernamePattern`, or null. */\n\tqaPatterns = /* @__PURE__ */ new Map();\n\tconstructor(dataLayer, user) {\n\t\tthis.dataLayer = dataLayer;\n\t\tthis.user = user;\n\t}\n\t/**\n\t* Whether the current user is one of the course's QA accounts\n\t* (`CourseConfig.qaUsernamePattern`), whose responses must not move card\n\t* ELO. The pattern is read once per course. If the config is unreadable or\n\t* the pattern doesn't compile, nobody is a QA account.\n\t*/\n\tasync isQaUser(courseDB) {\n\t\tconst courseId = courseDB.getCourseID();\n\t\tlet pattern = this.qaPatterns.get(courseId);\n\t\tif (!pattern) {\n\t\t\tpattern = courseDB.getCourseConfig().then((cfg) => cfg.qaUsernamePattern ? new RegExp(cfg.qaUsernamePattern, \"i\") : null).catch((e) => {\n\t\t\t\tlogger.warn(`[EloService] No QA username pattern for ${courseId}: ${e}`);\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\tthis.qaPatterns.set(courseId, pattern);\n\t\t}\n\t\treturn (await pattern)?.test(this.user.getUsername()) ?? false;\n\t}\n\t/**\n\t* Updates both user and card ELO ratings based on user performance.\n\t* @param userScore Score between 0-1 representing user performance\n\t* @param course_id Course identifier\n\t* @param card_id Card identifier\n\t* @param userCourseRegDoc User's course registration document (will be mutated)\n\t* @param currentCard Current card session record\n\t* @param k Optional K-factor for ELO calculation\n\t* @returns The captured before→after exchange for session logging, or null\n\t* if no update was applied (missing registration / unreadable ELO).\n\t*/\n\tasync updateUserAndCardElo(userScore, course_id, card_id, userCourseRegDoc, currentCard, k) {\n\t\tif (k) logger.warn(`k value interpretation not currently implemented`);\n\t\tconst courseDB = this.dataLayer.getCourseDB(currentCard.card.course_id);\n\t\tconst courseReg = userCourseRegDoc.courses.find((c) => c.courseID === course_id);\n\t\tif (!courseReg) {\n\t\t\tlogger.error(`[EloService] No registration for course ${course_id} on user's registration doc — skipping ELO update for card ${card_id}. (Is the user registered for this course?)`);\n\t\t\treturn null;\n\t\t}\n\t\tconst userElo = toCourseElo(courseReg.elo);\n\t\tconst cardElo = (await courseDB.getCardEloData([currentCard.card.card_id]))[0];\n\t\tif (cardElo && userElo) {\n\t\t\tconst writeCard = !await this.isQaUser(courseDB);\n\t\t\tconst beforeUserGlobal = userElo.global.score;\n\t\t\tconst beforeCardGlobal = cardElo.global.score;\n\t\t\tconst cardTagKeys = Object.keys(cardElo.tags);\n\t\t\tconst beforeUserTag = {};\n\t\t\tfor (const tag of cardTagKeys) beforeUserTag[tag] = userElo.tags[tag]?.score ?? userElo.global.score;\n\t\t\tconst eloUpdate = adjustCourseScores(userElo, cardElo, userScore);\n\t\t\tcourseReg.elo = eloUpdate.userElo;\n\t\t\tconst tags = {};\n\t\t\tfor (const tag of cardTagKeys) {\n\t\t\t\tconst countOnly = isCountOnlyTag(tag);\n\t\t\t\ttags[tag] = {\n\t\t\t\t\tbefore: beforeUserTag[tag],\n\t\t\t\t\tafter: countOnly ? beforeUserTag[tag] : eloUpdate.userElo.tags[tag].score,\n\t\t\t\t\tscore: countOnly ? null : userScore\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst event = {\n\t\t\t\tcardId: card_id,\n\t\t\t\tat: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tuserScore,\n\t\t\t\tglobal: {\n\t\t\t\t\tbefore: beforeUserGlobal,\n\t\t\t\t\tafter: eloUpdate.userElo.global.score\n\t\t\t\t},\n\t\t\t\tcard: {\n\t\t\t\t\tbefore: beforeCardGlobal,\n\t\t\t\t\tafter: writeCard ? eloUpdate.cardElo.global.score : beforeCardGlobal\n\t\t\t\t},\n\t\t\t\t...cardTagKeys.length ? { tags } : {}\n\t\t\t};\n\t\t\tif (!writeCard) logger.info(`[EloService] QA account: card ELO for ${card_id} not written`);\n\t\t\tconst results = await Promise.allSettled([this.user.updateUserElo(course_id, eloUpdate.userElo), writeCard ? courseDB.updateCardElo(card_id, eloUpdate.cardElo) : Promise.resolve(null)]);\n\t\t\tconst userEloStatus = results[0].status === \"fulfilled\";\n\t\t\tconst cardEloStatus = results[1].status === \"fulfilled\";\n\t\t\tif (userEloStatus && cardEloStatus) {\n\t\t\t\tconst user = results[0].value;\n\t\t\t\tconst card = results[1].value;\n\t\t\t\tif (user.ok && card && card.ok) logger.info(`[EloService] Updated ELOS:\n \\tUser: ${JSON.stringify(eloUpdate.userElo)})\n \\tCard: ${JSON.stringify(eloUpdate.cardElo)})\n `);\n\t\t\t} else {\n\t\t\t\tlogger.warn(`[EloService] Partial ELO update:\n \\tUser ELO update: ${userEloStatus ? \"SUCCESS\" : \"FAILED\"}\n \\tCard ELO update: ${cardEloStatus ? \"SUCCESS\" : \"FAILED\"}`);\n\t\t\t\tif (!userEloStatus && results[0].status === \"rejected\") logger.error(\"[EloService] User ELO update error:\", results[0].reason);\n\t\t\t\tif (!cardEloStatus && results[1].status === \"rejected\") logger.error(\"[EloService] Card ELO update error:\", results[1].reason);\n\t\t\t}\n\t\t\treturn event;\n\t\t}\n\t\treturn null;\n\t}\n\t/**\n\t* Updates both user and card ELO ratings with per-tag granularity.\n\t* Tags in taggedPerformance but not on card will be created dynamically.\n\t*\n\t* @param taggedPerformance Performance object with _global and per-tag scores\n\t* @param course_id Course identifier\n\t* @param card_id Card identifier\n\t* @param userCourseRegDoc User's course registration document (will be mutated)\n\t* @param currentCard Current card session record\n\t*/\n\tasync updateUserAndCardEloPerTag(taggedPerformance, course_id, card_id, userCourseRegDoc, currentCard) {\n\t\tconst courseDB = this.dataLayer.getCourseDB(currentCard.card.course_id);\n\t\tconst courseReg = userCourseRegDoc.courses.find((c) => c.courseID === course_id);\n\t\tif (!courseReg) {\n\t\t\tlogger.error(`[EloService] No registration for course ${course_id} on user's registration doc — skipping per-tag ELO update for card ${card_id}. (Is the user registered for this course?)`);\n\t\t\treturn null;\n\t\t}\n\t\tconst userElo = toCourseElo(courseReg.elo);\n\t\tconst [cardEloResults, cardTagsMap] = await Promise.all([courseDB.getCardEloData([currentCard.card.card_id]), courseDB.getAppliedTagsBatch([card_id])]);\n\t\tconst cardElo = cardEloResults[0];\n\t\tconst cardTags = cardTagsMap.get(card_id) ?? [];\n\t\tconst graded = withCountOnlyRoles(taggedPerformance, card_id);\n\t\tconst enriched = { ...graded };\n\t\tconst globalScore = taggedPerformance._global;\n\t\tfor (const tag of cardTags) if (!(tag in enriched)) enriched[tag] = isCountOnlyTag(tag) ? null : globalScore;\n\t\tif (cardElo && userElo) {\n\t\t\tconst writeCard = !await this.isQaUser(courseDB);\n\t\t\tconst beforeUserGlobal = userElo.global.score;\n\t\t\tconst beforeCardGlobal = cardElo.global.score;\n\t\t\tconst touchedTags = Object.keys(enriched).filter((key) => key !== \"_global\");\n\t\t\tconst beforeUserTag = {};\n\t\t\tfor (const tag of touchedTags) beforeUserTag[tag] = userElo.tags[tag]?.score ?? userElo.global.score;\n\t\t\tconst eloUpdate = adjustCourseScoresPerTag(userElo, cardElo, enriched);\n\t\t\tconst at = (/* @__PURE__ */ new Date()).toISOString();\n\t\t\tconst recorded = recordTagPresentations(eloUpdate.userElo, graded, currentCard.records, card_id, at);\n\t\t\tif (recorded.length) logger.info(`[EloService] recent-presentation entries for ${card_id}: [${recorded.join(\", \")}]`);\n\t\t\tcourseReg.elo = eloUpdate.userElo;\n\t\t\tconst tags = {};\n\t\t\tfor (const tag of touchedTags) {\n\t\t\t\tconst score = enriched[tag];\n\t\t\t\tconst after = score === null ? beforeUserTag[tag] : eloUpdate.userElo.tags[tag]?.score ?? beforeUserTag[tag];\n\t\t\t\ttags[tag] = {\n\t\t\t\t\tbefore: beforeUserTag[tag],\n\t\t\t\t\tafter,\n\t\t\t\t\tscore\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst event = {\n\t\t\t\tcardId: card_id,\n\t\t\t\tat,\n\t\t\t\tuserScore: globalScore,\n\t\t\t\tglobal: {\n\t\t\t\t\tbefore: beforeUserGlobal,\n\t\t\t\t\tafter: eloUpdate.userElo.global.score\n\t\t\t\t},\n\t\t\t\tcard: {\n\t\t\t\t\tbefore: beforeCardGlobal,\n\t\t\t\t\tafter: writeCard ? eloUpdate.cardElo.global.score : beforeCardGlobal\n\t\t\t\t},\n\t\t\t\t...touchedTags.length ? { tags } : {}\n\t\t\t};\n\t\t\tif (!writeCard) logger.info(`[EloService] QA account: card ELO for ${card_id} not written`);\n\t\t\tconst results = await Promise.allSettled([this.user.updateUserElo(course_id, eloUpdate.userElo), writeCard ? courseDB.updateCardElo(card_id, eloUpdate.cardElo) : Promise.resolve(null)]);\n\t\t\tconst userEloStatus = results[0].status === \"fulfilled\";\n\t\t\tconst cardEloStatus = results[1].status === \"fulfilled\";\n\t\t\tif (userEloStatus && cardEloStatus) {\n\t\t\t\tconst user = results[0].value;\n\t\t\t\tconst card = results[1].value;\n\t\t\t\tif (user.ok && card && card.ok) {\n\t\t\t\t\tconst tagCount = Object.keys(enriched).length - 1;\n\t\t\t\t\tlogger.info(`[EloService] Updated ELOS (per-tag, ${tagCount} tags):\n \\tUser: ${JSON.stringify(eloUpdate.userElo)})\n \\tCard: ${JSON.stringify(eloUpdate.cardElo)})\n `);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlogger.warn(`[EloService] Partial ELO update (per-tag):\n \\tUser ELO update: ${userEloStatus ? \"SUCCESS\" : \"FAILED\"}\n \\tCard ELO update: ${cardEloStatus ? \"SUCCESS\" : \"FAILED\"}`);\n\t\t\t\tif (!userEloStatus && results[0].status === \"rejected\") logger.error(\"[EloService] User ELO update error:\", results[0].reason);\n\t\t\t\tif (!cardEloStatus && results[1].status === \"rejected\") logger.error(\"[EloService] Card ELO update error:\", results[1].reason);\n\t\t\t}\n\t\t\treturn event;\n\t\t}\n\t\treturn null;\n\t}\n};\n//#endregion\nexport { EloService };\n\n//# sourceMappingURL=EloService.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { isQuestionRecord } from \"../../core/util/index.mjs\";\nimport { isTaggedPerformance } from \"@vue-skuilder/common\";\n//#region src/study/services/ResponseProcessor.ts\n/**\n* Service responsible for orchestrating the complete response processing workflow.\n* Coordinates SRS scheduling and ELO updates for user card interactions.\n*/\nvar ResponseProcessor = class {\n\tsrsService;\n\teloService;\n\t/** Sink for resolved ELO exchanges, wired to the session's in-memory log. */\n\tonEloEvent;\n\tconstructor(srsService, eloService, onEloEvent) {\n\t\tthis.srsService = srsService;\n\t\tthis.eloService = eloService;\n\t\tthis.onEloEvent = onEloEvent;\n\t}\n\t/**\n\t* ELO updates are fired without awaiting so response handling isn't blocked\n\t* on DB writes — but an unhandled rejection silently drops the update.\n\t* This produces a catch handler that surfaces the failure in logs.\n\t*/\n\tlogEloFailure(context, cardId) {\n\t\treturn (e) => logger.error(`[ResponseProcessor] ELO update failed (${context}) for ${cardId}:`, e);\n\t}\n\t/**\n\t* Fire an ELO update without blocking response handling, forwarding the\n\t* resolved exchange to the session log (if any) and surfacing failures.\n\t* Mirrors the previous `void update(...).catch(logEloFailure)` shape, with\n\t* the added `.then` capturing the before→after event for diagnostics.\n\t*/\n\ttrackElo(update, context, cardId) {\n\t\tupdate.then((event) => {\n\t\t\tif (event) this.onEloEvent?.(event);\n\t\t}).catch(this.logEloFailure(context, cardId));\n\t}\n\t/**\n\t* Parses performance data into global score and optional per-tag scores.\n\t*\n\t* @param performance - Numeric or structured performance from QuestionRecord\n\t* @returns Parsed performance with global score and optional tag scores\n\t*/\n\tparsePerformance(performance) {\n\t\tif (typeof performance === \"number\") return {\n\t\t\tglobalScore: performance,\n\t\t\ttaggedPerformance: null\n\t\t};\n\t\tif (isTaggedPerformance(performance)) return {\n\t\t\tglobalScore: performance._global,\n\t\t\ttaggedPerformance: performance\n\t\t};\n\t\tlogger.warn(\"[ResponseProcessor] Unexpected performance structure, using neutral score\", { performance });\n\t\treturn {\n\t\t\tglobalScore: .5,\n\t\t\ttaggedPerformance: null\n\t\t};\n\t}\n\t/**\n\t* Processes a user's response to a card, handling SRS scheduling and ELO updates.\n\t* @param cardRecord User's response record\n\t* @param cardHistory Promise resolving to the card's history\n\t* @param studySessionItem Current study session item\n\t* @param courseRegistrationDoc User's course registration (for ELO updates)\n\t* @param currentCard Current study session record\n\t* @param courseId Course identifier\n\t* @param cardId Card identifier\n\t* @param maxAttemptsPerView Maximum attempts allowed per view\n\t* @param maxSessionViews Maximum session views for this card\n\t* @param sessionViews Current number of session views\n\t* @returns ResponseResult with navigation and UI instructions\n\t*/\n\tasync processResponse(cardRecord, cardHistory, studySessionItem, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews) {\n\t\tif (!isQuestionRecord(cardRecord)) return {\n\t\t\tnextCardAction: \"dismiss-success\",\n\t\t\tshouldLoadNextCard: true,\n\t\t\tisCorrect: true,\n\t\t\tshouldClearFeedbackShadow: true\n\t\t};\n\t\ttry {\n\t\t\tconst history = await cardHistory;\n\t\t\tlet result;\n\t\t\tif (cardRecord.isCorrect) result = this.processCorrectResponse(cardRecord, history, studySessionItem, courseRegistrationDoc, currentCard, courseId, cardId, maxSessionViews, sessionViews);\n\t\t\telse result = this.processIncorrectResponse(cardRecord, history, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews);\n\t\t\tif (cardRecord.deferAdvance && result.shouldLoadNextCard) {\n\t\t\t\tlogger.info(\"[ResponseProcessor] deferAdvance requested — suppressing navigation, action stashed:\", { nextCardAction: result.nextCardAction });\n\t\t\t\tresult = {\n\t\t\t\t\t...result,\n\t\t\t\t\tshouldLoadNextCard: false,\n\t\t\t\t\tdeferred: true\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch (e) {\n\t\t\tlogger.error(\"[ResponseProcessor] Failed to load card history\", {\n\t\t\t\te,\n\t\t\t\tcardId\n\t\t\t});\n\t\t\tthrow e;\n\t\t}\n\t}\n\t/**\n\t* Handles processing for correct responses: SRS scheduling and ELO updates.\n\t*/\n\tprocessCorrectResponse(cardRecord, history, studySessionItem, courseRegistrationDoc, currentCard, courseId, cardId, maxSessionViews, sessionViews) {\n\t\tif (cardRecord.priorAttemps === 0) {\n\t\t\tif (!currentCard.card.tags.includes(\"srs:skip\")) this.srsService.scheduleReview(history, studySessionItem);\n\t\t\tconst { globalScore, taggedPerformance } = this.parsePerformance(cardRecord.performance);\n\t\t\tif (taggedPerformance) {\n\t\t\t\tconst tagKeys = Object.keys(taggedPerformance).filter((k) => k !== \"_global\");\n\t\t\t\tconst nullTags = tagKeys.filter((k) => taggedPerformance[k] === null);\n\t\t\t\tconst scoredTags = tagKeys.filter((k) => taggedPerformance[k] !== null);\n\t\t\t\tlogger.info(`[FirstContactElo] correct first-attempt per-tag ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps}): scored=[${scoredTags.join(\", \")}] count-only=[${nullTags.join(\", \")}]`);\n\t\t\t\tthis.trackElo(this.eloService.updateUserAndCardEloPerTag(taggedPerformance, courseId, cardId, courseRegistrationDoc, currentCard), \"correct per-tag\", cardId);\n\t\t\t} else {\n\t\t\t\tconst userScore = .5 + globalScore / 2;\n\t\t\t\tif (history.records.length === 1) this.trackElo(this.eloService.updateUserAndCardElo(userScore, courseId, cardId, courseRegistrationDoc, currentCard), \"correct\", cardId);\n\t\t\t\telse {\n\t\t\t\t\tconst k = Math.ceil(32 / history.records.length);\n\t\t\t\t\tthis.trackElo(this.eloService.updateUserAndCardElo(userScore, courseId, cardId, courseRegistrationDoc, currentCard, k), \"correct repeat-view\", cardId);\n\t\t\t\t}\n\t\t\t\tlogger.info(`[FirstContactElo] correct first-attempt ELO update (score=${userScore.toFixed(3)}) for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tnextCardAction: \"dismiss-success\",\n\t\t\t\tshouldLoadNextCard: true,\n\t\t\t\tisCorrect: true,\n\t\t\t\tperformanceScore: globalScore,\n\t\t\t\tshouldClearFeedbackShadow: true\n\t\t\t};\n\t\t} else {\n\t\t\tconst budgetSpent = sessionViews >= maxSessionViews;\n\t\t\tlogger.info(`[ResponseProcessor] Processed correct response (retry attempt - no scheduling/ELO); sessionViews=${sessionViews}/${maxSessionViews} -> ${budgetSpent ? \"dismiss-success\" : \"marked-failed\"}`);\n\t\t\tconst { globalScore } = this.parsePerformance(cardRecord.performance);\n\t\t\treturn {\n\t\t\t\tnextCardAction: budgetSpent ? \"dismiss-success\" : \"marked-failed\",\n\t\t\t\tshouldLoadNextCard: true,\n\t\t\t\tisCorrect: true,\n\t\t\t\tperformanceScore: globalScore,\n\t\t\t\tshouldClearFeedbackShadow: true\n\t\t\t};\n\t\t}\n\t}\n\t/**\n\t* Handles processing for incorrect responses: ELO updates only.\n\t*/\n\tprocessIncorrectResponse(cardRecord, history, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews) {\n\t\tconst { taggedPerformance } = this.parsePerformance(cardRecord.performance);\n\t\tlet eloUpdated = false;\n\t\tif (cardRecord.priorAttemps === 0) {\n\t\t\tif (taggedPerformance) {\n\t\t\t\tthis.trackElo(this.eloService.updateUserAndCardEloPerTag(taggedPerformance, courseId, cardId, courseRegistrationDoc, currentCard), \"incorrect per-tag\", cardId);\n\t\t\t\tlogger.info(`[FirstContactElo] incorrect first-attempt per-tag ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps}, tags=${Object.keys(taggedPerformance).length - 1})`);\n\t\t\t} else {\n\t\t\t\tthis.trackElo(this.eloService.updateUserAndCardElo(0, courseId, cardId, courseRegistrationDoc, currentCard), \"incorrect\", cardId);\n\t\t\t\tlogger.info(`[FirstContactElo] incorrect first-attempt ELO update (score=0) for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`);\n\t\t\t}\n\t\t\teloUpdated = true;\n\t\t} else logger.info(`[FirstContactElo] incorrect retry — no ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`);\n\t\tif (currentCard.records.length >= maxAttemptsPerView) if (sessionViews >= maxSessionViews) {\n\t\t\tif (!eloUpdated) {\n\t\t\t\tif (taggedPerformance) this.trackElo(this.eloService.updateUserAndCardEloPerTag(taggedPerformance, courseId, cardId, courseRegistrationDoc, currentCard), \"dismiss-failed per-tag\", cardId);\n\t\t\t\telse this.trackElo(this.eloService.updateUserAndCardElo(0, courseId, cardId, courseRegistrationDoc, currentCard), \"dismiss-failed\", cardId);\n\t\t\t\tlogger.info(`[FirstContactElo] dismiss-failed final ELO penalty for ${cardId} (historyLen=${history.records.length}, sessionViews=${sessionViews})`);\n\t\t\t} else logger.info(`[FirstContactElo] dismiss-failed — ELO already updated this response, skipping double penalty for ${cardId}`);\n\t\t\treturn {\n\t\t\t\tnextCardAction: \"dismiss-failed\",\n\t\t\t\tshouldLoadNextCard: true,\n\t\t\t\tisCorrect: false,\n\t\t\t\tshouldClearFeedbackShadow: true\n\t\t\t};\n\t\t} else return {\n\t\t\tnextCardAction: \"marked-failed\",\n\t\t\tshouldLoadNextCard: true,\n\t\t\tisCorrect: false,\n\t\t\tshouldClearFeedbackShadow: true\n\t\t};\n\t\telse return {\n\t\t\tnextCardAction: \"none\",\n\t\t\tshouldLoadNextCard: false,\n\t\t\tisCorrect: false,\n\t\t\tshouldClearFeedbackShadow: true\n\t\t};\n\t}\n};\n//#endregion\nexport { ResponseProcessor };\n\n//# sourceMappingURL=ResponseProcessor.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { displayableDataToViewData, isCourseElo, toCourseElo } from \"@vue-skuilder/common\";\n//#region src/study/services/CardHydrationService.ts\n/**\n* Extract audio URLs from arbitrary field data using heuristic pattern matching.\n* This is a \"worse is better\" approach - catches obvious URLs, silently ignores edge cases.\n*/\nfunction parseAudioURIs(data) {\n\tif (typeof data !== \"string\") return [];\n\treturn data.match(/https?:\\/\\/[^\\s\"'<>]+\\.(wav|mp3|ogg|m4a|aac|webm)/gi) ?? [];\n}\n/**\n* Prefetch an audio file by loading it into browser cache.\n* Resolves when the audio is ready to play (or on error, to avoid blocking).\n*/\nfunction prefetchAudio(url) {\n\treturn new Promise((resolve) => {\n\t\tconst audio = new Audio();\n\t\taudio.preload = \"auto\";\n\t\tconst cleanup = () => {\n\t\t\taudio.oncanplaythrough = null;\n\t\t\taudio.onerror = null;\n\t\t};\n\t\taudio.oncanplaythrough = () => {\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t};\n\t\taudio.onerror = () => {\n\t\t\tcleanup();\n\t\t\tlogger.warn(`[CardHydrationService] Failed to prefetch audio: ${url}`);\n\t\t\tresolve();\n\t\t};\n\t\taudio.src = url;\n\t});\n}\n/**\n* Service responsible for managing hydrated (ready-to-display) cards.\n* Uses a Map-based cache for direct ID lookup - no ordering assumptions.\n* SessionController owns all ordering decisions.\n*/\nvar CardHydrationService = class {\n\thydratedCards = /* @__PURE__ */ new Map();\n\thydrationInFlight = /* @__PURE__ */ new Set();\n\thydrationInProgress = false;\n\tconstructor(getViewComponent, getCourseDB, getItemsToHydrate) {\n\t\tthis.getViewComponent = getViewComponent;\n\t\tthis.getCourseDB = getCourseDB;\n\t\tthis.getItemsToHydrate = getItemsToHydrate;\n\t}\n\t/**\n\t* Get a hydrated card by ID.\n\t* @returns Hydrated card or null if not in cache\n\t*/\n\tgetHydratedCard(cardId) {\n\t\treturn this.hydratedCards.get(cardId) ?? null;\n\t}\n\t/**\n\t* Check if a card is hydrated.\n\t*/\n\thasHydratedCard(cardId) {\n\t\treturn this.hydratedCards.has(cardId);\n\t}\n\t/**\n\t* Remove a card from the cache (call on successful dismiss to free memory).\n\t*/\n\tremoveCard(cardId) {\n\t\tthis.hydratedCards.delete(cardId);\n\t}\n\t/**\n\t* Check if hydration should be triggered and start background hydration if needed.\n\t*/\n\tasync ensureHydratedCards() {\n\t\tthis.fillHydratedCards();\n\t}\n\t/**\n\t* Wait for a specific card to become hydrated.\n\t* @returns Promise that resolves to a hydrated card or null\n\t*/\n\tasync waitForCard(cardId) {\n\t\tif (this.hydratedCards.has(cardId)) return this.hydratedCards.get(cardId);\n\t\tif (!this.hydrationInProgress) this.fillHydratedCards();\n\t\tconst maxWaitMs = 1e4;\n\t\tconst pollIntervalMs = 25;\n\t\tlet elapsed = 0;\n\t\twhile (elapsed < maxWaitMs) {\n\t\t\tif (this.hydratedCards.has(cardId)) return this.hydratedCards.get(cardId);\n\t\t\tif (!this.hydrationInFlight.has(cardId) && !this.hydrationInProgress) break;\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n\t\t\telapsed += pollIntervalMs;\n\t\t}\n\t\treturn this.hydratedCards.get(cardId) ?? null;\n\t}\n\t/**\n\t* Get current hydrated cache size.\n\t*/\n\tget hydratedCount() {\n\t\treturn this.hydratedCards.size;\n\t}\n\t/**\n\t* Get list of currently hydrated card IDs (for debugging).\n\t*/\n\tgetHydratedCardIds() {\n\t\treturn Array.from(this.hydratedCards.keys());\n\t}\n\t/**\n\t* Fill the hydrated cache by hydrating items from getItemsToHydrate().\n\t* This is a pure cache-warming operation - no queue mutation.\n\t*/\n\tasync fillHydratedCards() {\n\t\tif (this.hydrationInProgress) return;\n\t\tthis.hydrationInProgress = true;\n\t\ttry {\n\t\t\tconst itemsToHydrate = this.getItemsToHydrate();\n\t\t\tfor (const item of itemsToHydrate) {\n\t\t\t\tif (this.hydratedCards.has(item.cardID) || this.hydrationInFlight.has(item.cardID)) continue;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.hydrateCard(item);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error(`[CardHydrationService] Error hydrating card ${item.cardID}:`, e);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.hydrationInProgress = false;\n\t\t}\n\t}\n\t/**\n\t* Hydrate a single card and add to cache.\n\t*/\n\tasync hydrateCard(item) {\n\t\tif (this.hydratedCards.has(item.cardID) || this.hydrationInFlight.has(item.cardID)) return;\n\t\tthis.hydrationInFlight.add(item.cardID);\n\t\ttry {\n\t\t\tconst courseDB = this.getCourseDB(item.courseID);\n\t\t\tconst [cardData, tagsByCard] = await Promise.all([courseDB.getCourseDoc(item.cardID), courseDB.getAppliedTagsBatch([item.cardID])]);\n\t\t\tif (!isCourseElo(cardData.elo)) cardData.elo = toCourseElo(cardData.elo);\n\t\t\tconst view = this.getViewComponent(cardData.id_view);\n\t\t\tconst dataDocs = await Promise.all(cardData.id_displayable_data.map((id) => courseDB.getCourseDoc(id, {\n\t\t\t\tattachments: true,\n\t\t\t\tbinary: true\n\t\t\t})));\n\t\t\tconst audioToPrefetch = [];\n\t\t\tdataDocs.forEach((dd) => {\n\t\t\t\tdd.data.forEach((f) => {\n\t\t\t\t\taudioToPrefetch.push(...parseAudioURIs(f.data));\n\t\t\t\t});\n\t\t\t});\n\t\t\tconst uniqueAudioUrls = [...new Set(audioToPrefetch)];\n\t\t\tif (uniqueAudioUrls.length > 0) {\n\t\t\t\tlogger.debug(`[CardHydrationService] Prefetching ${uniqueAudioUrls.length} audio files for card ${item.cardID}`);\n\t\t\t\tawait Promise.allSettled(uniqueAudioUrls.map(prefetchAudio));\n\t\t\t}\n\t\t\tconst data = dataDocs.map(displayableDataToViewData).reverse();\n\t\t\tthis.hydratedCards.set(item.cardID, {\n\t\t\t\titem: {\n\t\t\t\t\t...item,\n\t\t\t\t\telo: toCourseElo(cardData.elo).global.score\n\t\t\t\t},\n\t\t\t\tview,\n\t\t\t\tdata,\n\t\t\t\ttags: tagsByCard.get(item.cardID) ?? []\n\t\t\t});\n\t\t\tlogger.debug(`[CardHydrationService] Hydrated card ${item.cardID}`);\n\t\t} finally {\n\t\t\tthis.hydrationInFlight.delete(item.cardID);\n\t\t}\n\t}\n};\n//#endregion\nexport { CardHydrationService };\n\n//# sourceMappingURL=CardHydrationService.mjs.map","import \"../_virtual/_rolldown/runtime.mjs\";\n//#region src/study/ItemQueue.ts\nvar ItemQueue = class {\n\tq = [];\n\tseenCardIds = [];\n\t_dequeueCount = 0;\n\tget dequeueCount() {\n\t\treturn this._dequeueCount;\n\t}\n\tadd(item, cardId) {\n\t\tif (this.seenCardIds.find((d) => d === cardId)) return;\n\t\tthis.seenCardIds.push(cardId);\n\t\tthis.q.push(item);\n\t}\n\taddAll(items, cardIdExtractor) {\n\t\titems.forEach((i) => this.add(i, cardIdExtractor(i)));\n\t}\n\tget length() {\n\t\treturn this.q.length;\n\t}\n\tpeek(index) {\n\t\treturn this.q[index];\n\t}\n\tdequeue(cardIdExtractor) {\n\t\tif (this.q.length !== 0) {\n\t\t\tthis._dequeueCount++;\n\t\t\tconst item = this.q.splice(0, 1)[0];\n\t\t\tif (cardIdExtractor) {\n\t\t\t\tconst cardId = cardIdExtractor(item);\n\t\t\t\tconst index = this.seenCardIds.indexOf(cardId);\n\t\t\t\tif (index > -1) this.seenCardIds.splice(index, 1);\n\t\t\t}\n\t\t\treturn item;\n\t\t} else return null;\n\t}\n\t/**\n\t* Atomically replace all queue contents with new items.\n\t*\n\t* Used by mid-session replanning to swap the queue without a window where\n\t* it's empty (avoiding dead-air if nextCard() is called concurrently).\n\t*\n\t* Preserves dequeueCount (cumulative across the session).\n\t* Resets seenCardIds to match the new contents — cards from the old queue\n\t* that don't appear in the new set can be re-added in future replans.\n\t*/\n\treplaceAll(items, cardIdExtractor) {\n\t\tthis.q = [];\n\t\tthis.seenCardIds = [];\n\t\tfor (const item of items) {\n\t\t\tconst cardId = cardIdExtractor(item);\n\t\t\tif (!this.seenCardIds.includes(cardId)) {\n\t\t\t\tthis.seenCardIds.push(cardId);\n\t\t\t\tthis.q.push(item);\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Merge new items into the front of the queue, skipping duplicates.\n\t* Used by additive replans to inject high-quality candidates without\n\t* discarding the existing queue contents.\n\t*\n\t* `forceFrontIds` carries the mandatory (`+INF`) cards in this batch — a\n\t* durable `requireCard`/`requireTag` re-asserted by every replan. An ordinary\n\t* duplicate is left in place (skip), but a mandatory one that's *already*\n\t* queued is pulled out of its current slot so it rejoins at the front in batch\n\t* order. Without this, an additive merge unshifts fresh non-required cards\n\t* ahead of an already-present required card, steadily burying it until it never\n\t* gets drawn — defeating the \"must appear\" guarantee. Returns the count of\n\t* genuinely new cards added (re-fronted duplicates are not counted).\n\t*/\n\tmergeToFront(items, cardIdExtractor, forceFrontIds) {\n\t\tlet added = 0;\n\t\tconst toInsert = [];\n\t\tfor (const item of items) {\n\t\t\tconst cardId = cardIdExtractor(item);\n\t\t\tif (!this.seenCardIds.includes(cardId)) {\n\t\t\t\tthis.seenCardIds.push(cardId);\n\t\t\t\ttoInsert.push(item);\n\t\t\t\tadded++;\n\t\t\t} else if (forceFrontIds?.has(cardId)) {\n\t\t\t\tconst idx = this.q.findIndex((qi) => cardIdExtractor(qi) === cardId);\n\t\t\t\tif (idx >= 0) toInsert.push(...this.q.splice(idx, 1));\n\t\t\t}\n\t\t}\n\t\tthis.q.unshift(...toInsert);\n\t\treturn added;\n\t}\n\tget toString() {\n\t\treturn `${typeof this.q[0]}:\\n` + this.q.map((i) => `\\t${i.courseID}+${i.cardID}: ${i.status}`).join(\"\\n\");\n\t}\n};\n//#endregion\nexport { ItemQueue };\n\n//# sourceMappingURL=ItemQueue.mjs.map","import \"../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../util/logger.mjs\";\nimport { drainCapturedRuns, setDebugSessionId } from \"../core/navigators/PipelineDebugger.mjs\";\nimport { getSrsBacklogDebug } from \"../core/navigators/SrsDebugger.mjs\";\nimport { getStrategyPressureDebug } from \"../core/navigators/StrategyPressureDebugger.mjs\";\nimport { getCardOrigin } from \"../core/navigators/index.mjs\";\nimport { sessionVersions } from \"../core/versionStamps.mjs\";\nimport { DocType } from \"../core/types/types-legacy.mjs\";\nimport { Loggable } from \"../util/Loggable.mjs\";\nimport { recordUserOutcome } from \"../core/orchestration/recording.mjs\";\nimport { mergeHints } from \"../core/navigators/Pipeline.mjs\";\nimport { isQuestionRecord } from \"../core/util/index.mjs\";\nimport { SrsService } from \"./services/SrsService.mjs\";\nimport { EloService } from \"./services/EloService.mjs\";\nimport { ResponseProcessor } from \"./services/ResponseProcessor.mjs\";\nimport { CardHydrationService } from \"./services/CardHydrationService.mjs\";\nimport { ItemQueue } from \"./ItemQueue.mjs\";\nimport { makeStudySessionId, newSessionId } from \"../core/types/studySession.mjs\";\nimport { QuotaRoundRobinMixer } from \"./SourceMixer.mjs\";\nimport { captureMixerRun } from \"./MixerDebugger.mjs\";\nimport { registerActiveController } from \"./SessionOverlay.mjs\";\nimport { clearStaleSessionDebugState, endSessionTracking, recordCardPresentation, snapshotQueues, startSessionTracking } from \"./SessionDebugger.mjs\";\nimport { isReview } from \"../core/interfaces/contentSource.mjs\";\n//#region src/study/SessionController.ts\n/** Unselected cards persisted per run, after the selected ones. */\nconst PERSISTED_RUNNERS_UP = 5;\n/** 4 significant figures: keeps 6.4e-7 distinguishable from 0 without 17-digit floats. */\nfunction sig4(x) {\n\treturn Number(x.toPrecision(4));\n}\nfunction toRunCard(c) {\n\treturn {\n\t\tcardId: c.cardId,\n\t\torigin: c.origin,\n\t\t...c.generator ? { generator: c.generator } : {},\n\t\t...c.required ? { required: c.required } : {},\n\t\tscore: Number.isFinite(c.finalScore) ? sig4(c.finalScore) : null,\n\t\tselected: c.selected\n\t};\n}\nfunction toRunCardTrail(c) {\n\treturn {\n\t\t...toRunCard(c),\n\t\ttrail: c.provenance.filter((p) => p.action !== \"passed\").map((p) => ({\n\t\t\tstrategyName: p.strategyName,\n\t\t\taction: p.action,\n\t\t\tscore: sig4(p.score),\n\t\t\treason: p.reason\n\t\t}))\n\t};\n}\nfunction persistedReading(r) {\n\treturn {\n\t\t...r,\n\t\turgency: sig4(r.urgency),\n\t\tmultiplier: sig4(r.multiplier),\n\t\tinputs: Object.fromEntries(Object.entries(r.inputs).map(([k, v]) => [k, sig4(v)]))\n\t};\n}\n/** `run.cards` is selected-then-near-misses, each in score order. */\nfunction persistedRunCards(run) {\n\tconst selected = run.cards.filter((c) => c.selected);\n\tconst runnersUp = run.cards.filter((c) => !c.selected).slice(0, PERSISTED_RUNNERS_UP);\n\treturn [...selected, ...runnersUp].map(toRunCard);\n}\nfunction persistedUnselectedNew(u) {\n\treturn {\n\t\t...u.nextInLine ? { nextInLine: toRunCardTrail(u.nextInLine) } : {},\n\t\t...u.topGenerated ? { topGenerated: toRunCardTrail(u.topGenerated) } : {}\n\t};\n}\nvar SessionController = class SessionController extends Loggable {\n\t_className = \"SessionController\";\n\tservices;\n\tsrsService;\n\teloService;\n\thydrationService;\n\tmixer;\n\tdataLayer;\n\tcourseNameCache = /* @__PURE__ */ new Map();\n\t/**\n\t* Default pipeline batch size for new-card planning.\n\t* Set via constructor options; falls back to 20 when not specified.\n\t* Individual replans can override via `ReplanOptions.limit`.\n\t*/\n\t_defaultBatchLimit = 20;\n\tsources;\n\t_sessionRecord = [];\n\tset sessionRecord(r) {\n\t\tthis._sessionRecord = r;\n\t}\n\t_currentCard = null;\n\t/**\n\t* The single supply queue: `new` + `review` items interleaved in pipeline\n\t* rank order (the mixer's score-ordered, source-interleaved output, with\n\t* `+INF` required cards floated to the front). Drawn front-to-back; reviews\n\t* and new compete on one cross-comparable scale rather than being re-mixed\n\t* by a probability gate. Replaced/re-ranked wholesale on replan. See\n\t* `docs/decision-single-supply-queue.md`.\n\t*/\n\tsupplyQ = new ItemQueue();\n\tfailedQ = new ItemQueue();\n\t/**\n\t* Supply draws since the last failed-queue *event* (a failed draw, or a card\n\t* entering failedQ on failure). Drives the light steady failed-interleave\n\t* (§7): after this many consecutive supply draws, a pending failed card is\n\t* drawn so remediation doesn't starve mid-session. Incremented on each supply\n\t* draw; reset to 0 both when a failed card is drawn AND when one is added to\n\t* failedQ — the latter gives a just-failed card spacing instead of an instant\n\t* retry (the counter would otherwise already be ≥ threshold from the preceding\n\t* supply run).\n\t*/\n\t_supplyDrawsSinceFailed = 0;\n\t/**\n\t* Promise tracking a currently in-progress replan, or null if idle.\n\t* Used by nextCard() to await completion before drawing from queues.\n\t*/\n\t_replanPromise = null;\n\t/**\n\t* Reason for the replan currently executing in `_runReplan`, surfaced by the\n\t* debug overlay's spinner. The caller's `opts.label` when present, else\n\t* `'(auto)'`. Only meaningful while `_replanPromise` is non-null; cleared\n\t* when the in-flight chain settles.\n\t*/\n\t_activeReplanLabel = null;\n\t/**\n\t* Number of well-indicated supply cards remaining before the queue\n\t* degrades to poorly-indicated content. Decremented on each supplyQ\n\t* draw; when it hits 0, a replan is triggered automatically\n\t* (user state has changed from completing good cards).\n\t*/\n\t_wellIndicatedRemaining = 0;\n\t/**\n\t* When true, suppresses the quality-based auto-replan trigger in\n\t* nextCard(). Set after a burst replan (small limit) to prevent the\n\t* auto-replan from clobbering the burst cards before they're consumed.\n\t* Cleared when the depletion-triggered replan fires (supplyQ exhausted).\n\t*/\n\t_suppressQualityReplan = false;\n\t/**\n\t* When > 0, the session timer cannot end the session. Decremented on\n\t* each nextCard() draw. Set by replans that include `minFollowUpCards`.\n\t*/\n\t_minCardsGuarantee = 0;\n\t/**\n\t* Session-durable scoring hints. Re-merged into every pipeline run for\n\t* the rest of the session (initial plan + every replan, including bare\n\t* auto-replans and the wedge-breaker), via `_applyHintsToSources`.\n\t*\n\t* Set by `setSessionHints()` (e.g. session-start post-lesson boost) or by\n\t* any replan carrying `ReplanOptions.sessionHints` (e.g. a just-failed\n\t* concept boost). Replace semantics, no decay — lives until overwritten\n\t* or session end. See `ReplanOptions.sessionHints` for rationale.\n\t*\n\t* Note: the controller-managed auto-excludes (current card, session\n\t* record, imminent draw) are intentionally NOT folded in here — those are\n\t* recomputed per-run in `_runReplan` and would otherwise go stale.\n\t*/\n\t_sessionHints = null;\n\t/**\n\t* Card IDs that have been *served* (drawn/consumed) this session. Populated\n\t* at the single consumption choke-point (removeItemFromQueue), so it reflects\n\t* a draw the instant it happens — earlier than `_sessionRecord`, which only\n\t* lands once the card is *responded to*.\n\t*\n\t* Used to keep already-served cards out of supplyQ on every (re)plan, across\n\t* ALL origins: a `new` card shown once must never re-enter, and once replans\n\t* re-pull reviews, an answered/in-flight review must not re-enter the supply\n\t* before its SRS reschedule clears the due-window (the review-loop guard,\n\t* decision doc §4). This is the general guard against re-presentation —\n\t* including the case where a replan in flight captured a now-drawn card (e.g.\n\t* a +INF require-injected follow-up the depletion prefetch grabbed just before\n\t* it was drawn). failedQ is separate and controller-owned, so failed cards\n\t* legitimately recur there without being gated here.\n\t*/\n\t_servedCardIds = /* @__PURE__ */ new Set();\n\t/**\n\t* Consumer-supplied hooks invoked after each question response is processed.\n\t* Seeded from constructor options (threaded from\n\t* `StudySessionConfig.outcomeObservers`). See {@link OutcomeObserver}.\n\t*/\n\t_outcomeObservers = [];\n\t/**\n\t* Lazily-built, stable capability object handed to observers. Bound to\n\t* `this`; constructed once so observers can rely on referential identity.\n\t*/\n\t_sessionControls = null;\n\t/**\n\t* Minted at construction so the bootstrap pipeline run in `prepareSession()`\n\t* can carry it. Stamped onto every CardRecord and pipeline run this session.\n\t*/\n\tsessionId;\n\t/** Host-supplied. Without it, no durable session doc is written. */\n\t_courseId;\n\t_stateSnapshotProvider;\n\t_sessionDoc = null;\n\t/**\n\t* Awaited by the close path — the open write is slow (time-boxed snapshot)\n\t* and would otherwise land last, leaving a finished session marked `open`.\n\t*/\n\t_openDocPromise = null;\n\t_runLog = [];\n\tstatic MAX_LOGGED_RUNS = 100;\n\t/**\n\t* Per-response ELO exchanges as they resolve (see `SessionEloEvent`). Fed by\n\t* the ResponseProcessor's `onEloEvent` sink; flushed to the session doc at\n\t* close. Bounded so a runaway session can't grow it without limit.\n\t*/\n\t_eloLog = [];\n\tstatic MAX_LOGGED_ELO_EVENTS = 2e3;\n\t/** Guards `endSession()` against the several termination paths racing it. */\n\t_sessionClosed = false;\n\tstartTime;\n\tendTime;\n\t_secondsRemaining;\n\tget secondsRemaining() {\n\t\treturn this._secondsRemaining;\n\t}\n\t/** True when a card guarantee is active, preventing timer-based session end. */\n\tget hasCardGuarantee() {\n\t\treturn this._minCardsGuarantee > 0;\n\t}\n\tget report() {\n\t\tconst supplyCount = this.supplyQ.dequeueCount;\n\t\treturn `${supplyCount} supply ${supplyCount === 1 ? \"card\" : \"cards\"} drawn`;\n\t}\n\tget detailedReport() {\n\t\treturn this.supplyQ.toString + \"\\n\" + this.failedQ.toString;\n\t}\n\t_intervalHandle;\n\t/**\n\t* @param sources - Array of content sources to mix for the session\n\t* @param time - Session duration in seconds\n\t* @param dataLayer - Data layer provider\n\t* @param getViewComponent - Function to resolve view components\n\t* @param mixer - Optional source mixer strategy (defaults to QuotaRoundRobinMixer)\n\t* @param options - Optional session-level configuration\n\t* @param options.defaultBatchLimit - Default supply working-set size (default: 20).\n\t* Smaller values for newer users cause more frequent replans, keeping plans\n\t* aligned with rapidly-changing user state.\n\t*/\n\tconstructor(sources, time, dataLayer, getViewComponent, mixer, options) {\n\t\tsuper();\n\t\tthis.sessionId = newSessionId();\n\t\tsetDebugSessionId(this.sessionId);\n\t\tthis.dataLayer = dataLayer;\n\t\tthis.mixer = mixer || new QuotaRoundRobinMixer();\n\t\tthis.srsService = new SrsService(dataLayer.getUserDB());\n\t\tthis.eloService = new EloService(dataLayer, dataLayer.getUserDB());\n\t\tthis.hydrationService = new CardHydrationService(getViewComponent, (courseId) => dataLayer.getCourseDB(courseId), () => this._getItemsToHydrate());\n\t\tthis.services = { response: new ResponseProcessor(this.srsService, this.eloService, (event) => this._recordEloEvent(event)) };\n\t\tthis.sources = sources;\n\t\tthis.startTime = /* @__PURE__ */ new Date();\n\t\tthis._secondsRemaining = time;\n\t\tthis.endTime = new Date(this.startTime.valueOf() + 1e3 * this._secondsRemaining);\n\t\tif (options?.defaultBatchLimit !== void 0) this._defaultBatchLimit = options.defaultBatchLimit;\n\t\tif (options?.outcomeObservers?.length) this._outcomeObservers = [...options.outcomeObservers];\n\t\tthis._courseId = options?.courseId;\n\t\tthis._stateSnapshotProvider = options?.stateSnapshotProvider;\n\t\tthis.log(`Session constructed:\n sessionId: ${this.sessionId}\n startTime: ${this.startTime}\n endTime: ${this.endTime}\n defaultBatchLimit: ${this._defaultBatchLimit}`);\n\t\tregisterActiveController(this);\n\t}\n\ttick() {\n\t\tthis._secondsRemaining = Math.floor((this.endTime.valueOf() - Date.now()) / 1e3);\n\t\tif (this._secondsRemaining <= 0) clearInterval(this._intervalHandle);\n\t}\n\t/**\n\t* Returns a rough, erring toward conservative, guess at\n\t* the amount of time the failed cards queue will require\n\t* to clean up.\n\t*\n\t* (seconds)\n\t*/\n\testimateCleanupTime() {\n\t\tlet time = 0;\n\t\tfor (let i = 0; i < this.failedQ.length; i++) {\n\t\t\tconst c = this.failedQ.peek(i);\n\t\t\tconst record = this._sessionRecord.find((r) => r.item.cardID === c.cardID);\n\t\t\tlet cardTime = 0;\n\t\t\tif (record) {\n\t\t\t\tfor (let j = 0; j < record.records.length; j++) cardTime += record.records[j].timeSpent;\n\t\t\t\tcardTime = cardTime / record.records.length;\n\t\t\t\ttime += cardTime;\n\t\t\t}\n\t\t}\n\t\tconst ret = time / 1e3;\n\t\tthis.log(`Failed card cleanup estimate: ${Math.round(ret)}`);\n\t\treturn ret;\n\t}\n\tasync prepareSession() {\n\t\tif (this.sources.some((s) => typeof s.getWeightedCards !== \"function\")) throw new Error(\"[SessionController] All content sources must implement getWeightedCards().\");\n\t\tclearStaleSessionDebugState();\n\t\tconst wellIndicated = await this.getWeightedContent();\n\t\tthis._recordRuns(\"bootstrap\");\n\t\tthis._wellIndicatedRemaining = wellIndicated;\n\t\tif (wellIndicated >= 0 && wellIndicated < SessionController.MIN_WELL_INDICATED) this.log(`[Init] Only ${wellIndicated}/${SessionController.MIN_WELL_INDICATED} well-indicated cards in initial load`);\n\t\tawait this.hydrationService.ensureHydratedCards();\n\t\tstartSessionTracking(this.sessionId, this.supplyQ.length, this.failedQ.length);\n\t\tthis._openDocPromise = this._openSessionDoc();\n\t\tthis._intervalHandle = setInterval(() => {\n\t\t\tthis.tick();\n\t\t}, 1e3);\n\t}\n\t/** Label the runs the last plan produced. The pipeline can't know the why. */\n\t_recordRuns(label, mode) {\n\t\tfor (const run of drainCapturedRuns()) {\n\t\t\tif (this._runLog.length >= SessionController.MAX_LOGGED_RUNS) break;\n\t\t\tthis._runLog.push({\n\t\t\t\trunId: run.runId,\n\t\t\t\tat: run.timestamp.toISOString(),\n\t\t\t\tlabel,\n\t\t\t\t...mode ? { mode } : {},\n\t\t\t\tgeneratedCount: run.generatedCount,\n\t\t\t\tfinalCount: run.finalCount,\n\t\t\t\treviewsSelected: run.reviewsSelected,\n\t\t\t\tnewSelected: run.newSelected,\n\t\t\t\t...typeof run.userElo === \"number\" ? { userElo: run.userElo } : {},\n\t\t\t\t...run.generators ? { generators: run.generators } : {},\n\t\t\t\t...run.filters ? { filters: run.filters } : {},\n\t\t\t\t...run.hints ? { hints: run.hints } : {},\n\t\t\t\t...run.discardedTail ? { discardedTail: run.discardedTail } : {},\n\t\t\t\tcards: persistedRunCards(run),\n\t\t\t\t...run.unselectedNew ? { unselectedNew: persistedUnselectedNew(run.unselectedNew) } : {},\n\t\t\t\t...run.regulators ? { regulators: run.regulators.map(persistedReading) } : {},\n\t\t\t\t...run.versions ? { versions: run.versions } : {}\n\t\t\t});\n\t\t}\n\t}\n\t/** Time-boxed and isolated — a bad provider degrades the record, not the session. */\n\tasync _captureState(phase) {\n\t\tif (!this._stateSnapshotProvider) return void 0;\n\t\tconst TIMEOUT_MS = 3e3;\n\t\ttry {\n\t\t\treturn await Promise.race([Promise.resolve(this._stateSnapshotProvider(phase)), new Promise((resolve) => setTimeout(() => resolve(void 0), TIMEOUT_MS))]);\n\t\t} catch (e) {\n\t\t\tthis.log(`[Session] state snapshot (${phase}) failed: ${e}`);\n\t\t\treturn;\n\t\t}\n\t}\n\t/** Writing at open is what makes an unclosed session visible at all. */\n\tasync _openSessionDoc() {\n\t\tif (!this._courseId) return;\n\t\ttry {\n\t\t\tconst user = this.dataLayer.getUserDB();\n\t\t\tconst doc = {\n\t\t\t\t_id: makeStudySessionId(this._courseId, user.getUsername(), this.sessionId),\n\t\t\t\tdocType: DocType.STUDY_SESSION,\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\tcourseId: this._courseId,\n\t\t\t\tuserId: user.getUsername(),\n\t\t\t\tstartTime: this.startTime.toISOString(),\n\t\t\t\tstatus: \"open\",\n\t\t\t\tplannedSeconds: Math.round((this.endTime.valueOf() - this.startTime.valueOf()) / 1e3),\n\t\t\t\tconfig: {\n\t\t\t\t\tdefaultBatchLimit: this._defaultBatchLimit,\n\t\t\t\t\tsourceCount: this.sources.length,\n\t\t\t\t\tinitHints: this._sessionHints\n\t\t\t\t},\n\t\t\t\tversions: sessionVersions(),\n\t\t\t\tinitialQueues: {\n\t\t\t\t\tsupplyQ: this.supplyQ.length,\n\t\t\t\t\tfailedQ: this.failedQ.length\n\t\t\t\t},\n\t\t\t\truns: [...this._runLog],\n\t\t\t\tstateAtStart: await this._captureState(\"start\")\n\t\t\t};\n\t\t\tthis._sessionDoc = doc;\n\t\t\tawait user.putStudySession(doc);\n\t\t\tthis.log(`[Session] Opened session record ${doc._id}`);\n\t\t} catch (e) {\n\t\t\tlogger.warn(`[SessionController] Failed to open session record: ${e}`);\n\t\t}\n\t}\n\t/**\n\t* Request a mid-session replan. Re-runs the pipeline with current user state\n\t* and atomically replaces (or merges into) the supplyQ contents. Safe to call\n\t* at any time during a session.\n\t*\n\t* Concurrency policy:\n\t* - Two unhinted auto-replans never run in parallel; the second coalesces\n\t* into the first (returns the same promise).\n\t* - A hint-bearing replan that arrives while another replan is in flight\n\t* is queued to run **after** the in-flight one rather than dropped.\n\t* This preserves caller intent (label, requireCards, excludeTags,\n\t* limit, minFollowUpCards) instead of silently discarding it. Without\n\t* queueing, a background auto-replan that started just before a\n\t* completion-triggered replan would clobber the queue with unhinted\n\t* results (e.g. surfacing another gpc-intro card right after one\n\t* completed, skipping the prescribed `c-wst-*` follow-up).\n\t*\n\t* Re-pulls and re-ranks the whole supply (including reviews); does NOT affect\n\t* failedQ (controller-owned remediation).\n\t*\n\t* If nextCard() is called while a replan is in flight, it will automatically\n\t* await the replan before drawing from queues, ensuring the user always sees\n\t* cards scored against their latest state.\n\t*\n\t* Typical trigger: application-level code (e.g. after a GPC intro completion)\n\t* calls this to ensure newly-unlocked content appears in the session.\n\t*/\n\tasync requestReplan(options) {\n\t\tconst opts = this.normalizeReplanOptions(options);\n\t\tconst hasIntent = this._replanHasIntent(opts);\n\t\tif (this._replanPromise) {\n\t\t\tif (!hasIntent) {\n\t\t\t\tthis.log(\"Replan already in progress, coalescing unhinted auto-replan\");\n\t\t\t\treturn this._replanPromise;\n\t\t\t}\n\t\t\tconst labelTag = opts.label ? ` [${opts.label}]` : \"\";\n\t\t\tthis.log(`Replan in progress; queueing hint-bearing replan${labelTag} behind in-flight run`);\n\t\t\tconst queued = this._replanPromise.catch(() => void 0).then(() => this._runReplan(opts));\n\t\t\tconst tracked = queued.finally(() => {\n\t\t\t\tif (this._replanPromise === tracked) {\n\t\t\t\t\tthis._replanPromise = null;\n\t\t\t\t\tthis._activeReplanLabel = null;\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis._replanPromise = tracked;\n\t\t\treturn queued;\n\t\t}\n\t\tconst run = this._runReplan(opts);\n\t\tconst tracked = run.finally(() => {\n\t\t\tif (this._replanPromise === tracked) {\n\t\t\t\tthis._replanPromise = null;\n\t\t\t\tthis._activeReplanLabel = null;\n\t\t\t}\n\t\t});\n\t\tthis._replanPromise = tracked;\n\t\tawait run;\n\t}\n\t/**\n\t* True when a requestReplan call carries caller intent that must not be\n\t* silently dropped. Bare unhinted auto-replans (depletion / quality\n\t* triggers in nextCard) return false and may coalesce.\n\t*/\n\t_replanHasIntent(opts) {\n\t\tif (opts.limit !== void 0) return true;\n\t\tif (opts.minFollowUpCards !== void 0) return true;\n\t\tif (opts.mode && opts.mode !== \"replace\") return true;\n\t\tif (opts.hints && Object.keys(opts.hints).length > 0) return true;\n\t\tif (opts.sessionHints !== void 0) return true;\n\t\tif (opts.mergeSessionHints !== void 0) return true;\n\t\treturn false;\n\t}\n\t/**\n\t* Body of a single replan: populate auto-excludes, stash hints on\n\t* sources, log, then run the pipeline. Extracted so it can be invoked\n\t* either immediately (no in-flight replan) or queued (chained after\n\t* the in-flight one resolves).\n\t*\n\t* IMPORTANT: hint stash and the queue-state snapshot used to build\n\t* excludeCards happen at *invocation* time, not at *queue* time. For a\n\t* queued replan that means excludes reflect the state after the prior\n\t* replan landed — which is what we want, since the prior replan's\n\t* supplyQ.peek(0) is the imminent draw we need to exclude.\n\t*/\n\tasync _runReplan(opts) {\n\t\tthis._activeReplanLabel = opts.label ?? \"(auto)\";\n\t\tif (!opts.hints) opts.hints = {};\n\t\tconst hints = opts.hints;\n\t\tconst excludeSet = new Set(hints.excludeCards ?? []);\n\t\tif (this._currentCard?.item.cardID) excludeSet.add(this._currentCard.item.cardID);\n\t\tfor (const rec of this._sessionRecord) excludeSet.add(rec.card.card_id);\n\t\tif (this.supplyQ.length > 0) excludeSet.add(this.supplyQ.peek(0).cardID);\n\t\thints.excludeCards = [...excludeSet];\n\t\tif (opts.sessionHints !== void 0) {\n\t\t\tthis._sessionHints = opts.sessionHints;\n\t\t\tthis.log(`[Replan] Session hints ${opts.sessionHints ? \"set\" : \"cleared\"}: ${JSON.stringify(opts.sessionHints)}`);\n\t\t}\n\t\tif (opts.mergeSessionHints !== void 0) {\n\t\t\tthis._sessionHints = mergeHints([this._sessionHints, opts.mergeSessionHints]) ?? null;\n\t\t\tthis.log(`[Replan] Session hints merged: ${JSON.stringify(this._sessionHints)}`);\n\t\t}\n\t\tthis._applyHintsToSources(opts.hints, opts.label);\n\t\tconst labelTag = opts.label ? ` [${opts.label}]` : \"\";\n\t\tthis.log(`Mid-session replan requested${labelTag} (limit: ${opts.limit ?? \"default\"}, mode: ${opts.mode ?? \"replace\"}${opts.hints ? \", with hints\" : \"\"})`);\n\t\tif (opts.minFollowUpCards !== void 0 && opts.minFollowUpCards > 0) {\n\t\t\tthis._minCardsGuarantee = Math.max(this._minCardsGuarantee, opts.minFollowUpCards);\n\t\t\tthis.log(`[Replan] Card guarantee set to ${this._minCardsGuarantee}`);\n\t\t}\n\t\tawait this._executeReplan(opts);\n\t}\n\t/**\n\t* Set the session-durable scoring hints (replace semantics, no decay).\n\t*\n\t* Unlike a one-shot replan hint, these are re-merged into every pipeline\n\t* run for the rest of the session — including the initial plan when set\n\t* before `prepareSession()`, every replan, the bare auto-replans, and the\n\t* wedge-breaker. Pass `null` to clear.\n\t*\n\t* Typical callers:\n\t* - `StudySession` at session start, threading `StudySessionConfig.initHints`\n\t* (e.g. a post-lesson concept boost) — so the boost outlives the first\n\t* queue rebuild instead of being clobbered by the first auto-replan.\n\t* - A consumer view on a failure, boosting the just-failed concept tag.\n\t*\n\t* Does not itself trigger a replan; the next plan/replan picks it up.\n\t*/\n\tsetSessionHints(hints) {\n\t\tthis._sessionHints = hints;\n\t\tthis.log(`Session hints ${hints ? \"set\" : \"cleared\"}: ${JSON.stringify(hints)}`);\n\t}\n\t/**\n\t* Read the current session-durable hints (for read-modify-write callers,\n\t* e.g. an outcome observer that clamps a compounding boost).\n\t*/\n\tgetSessionHints() {\n\t\treturn this._sessionHints;\n\t}\n\t/**\n\t* Live state snapshot for the debug overlay (window.skuilder.session\n\t* .dbgOverlay()). Reads directly from the private queues and hints, so it\n\t* always reflects the current moment — unlike the passive SessionDebugger\n\t* snapshots, which only capture what was explicitly pushed to them.\n\t*/\n\tgetDebugSnapshot() {\n\t\tconst describe = (q) => {\n\t\t\tconst cards = [];\n\t\t\tfor (let i = 0; i < q.length; i++) {\n\t\t\t\tconst item = q.peek(i);\n\t\t\t\tcards.push({\n\t\t\t\t\tcardID: item.cardID,\n\t\t\t\t\tstatus: item.status,\n\t\t\t\t\torigin: isReview(item) ? \"review\" : \"new\",\n\t\t\t\t\tscore: item.score\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlength: q.length,\n\t\t\t\tdequeueCount: q.dequeueCount,\n\t\t\t\tcards\n\t\t\t};\n\t\t};\n\t\tconst drawnCards = this._sessionRecord.map((r) => {\n\t\t\tconst last = r.records[r.records.length - 1];\n\t\t\treturn {\n\t\t\t\tcardID: r.item.cardID,\n\t\t\t\tstatus: r.item.status,\n\t\t\t\tattempts: r.records.length,\n\t\t\t\tcorrect: last && isQuestionRecord(last) ? last.isCorrect : null,\n\t\t\t\ttimeSpentMs: r.records.reduce((sum, rec) => sum + rec.timeSpent, 0)\n\t\t\t};\n\t\t});\n\t\treturn {\n\t\t\tsessionId: this.sessionId,\n\t\t\tsecondsRemaining: this.secondsRemaining,\n\t\t\thasCardGuarantee: this.hasCardGuarantee,\n\t\t\tminCardsGuarantee: this._minCardsGuarantee,\n\t\t\twellIndicatedRemaining: this._wellIndicatedRemaining,\n\t\t\tcurrentCard: this._currentCard?.item.cardID ?? null,\n\t\t\tsessionHints: this._sessionHints,\n\t\t\treplanActive: this._replanPromise !== null,\n\t\t\treplanLabel: this._activeReplanLabel,\n\t\t\tsupplyQ: describe(this.supplyQ),\n\t\t\tfailedQ: describe(this.failedQ),\n\t\t\treviewBacklog: getSrsBacklogDebug(),\n\t\t\tstrategyPressure: getStrategyPressureDebug(),\n\t\t\tdrawnCards\n\t\t};\n\t}\n\t/**\n\t* Merge `hints` into the durable session hints via the pipeline's\n\t* `mergeHints` (boosts multiply, require/exclude lists concat-dedup).\n\t* Convenience over get-then-set for the common additive case. Note the\n\t* multiplicative, no-decay semantics — clamp boost factors at the call\n\t* site if a repeatedly-emphasised tag could compound unboundedly.\n\t*/\n\tmergeSessionHints(hints) {\n\t\tthis._sessionHints = mergeHints([this._sessionHints, hints]) ?? null;\n\t\tthis.log(`Session hints merged: ${JSON.stringify(this._sessionHints)}`);\n\t}\n\t/**\n\t* Merge the durable `_sessionHints` with this run's one-shot hints and\n\t* push the result to every source for consumption on the next pipeline\n\t* run. Centralised so the initial plan and all replan paths apply session\n\t* emphasis identically. No-op when there are no hints of either kind.\n\t*/\n\t_applyHintsToSources(oneShot, label) {\n\t\tconst oneShotWithLabel = oneShot && label ? {\n\t\t\t...oneShot,\n\t\t\t_label: label\n\t\t} : oneShot;\n\t\tconst merged = mergeHints([this._sessionHints, oneShotWithLabel]);\n\t\tif (!merged) return;\n\t\tfor (const source of this.sources) source.setEphemeralHints?.(merged);\n\t}\n\t/**\n\t* Build (once) the stable capability object handed to outcome observers.\n\t* Methods are bound to `this`; the object identity is stable across calls\n\t* so observers may key off it.\n\t*/\n\t_getSessionControls() {\n\t\tif (!this._sessionControls) this._sessionControls = {\n\t\t\tgetSessionHints: () => this.getSessionHints(),\n\t\t\tsetSessionHints: (h) => this.setSessionHints(h),\n\t\t\tmergeSessionHints: (h) => this.mergeSessionHints(h),\n\t\t\trequestReplan: (opts) => this.requestReplan(opts)\n\t\t};\n\t\treturn this._sessionControls;\n\t}\n\t/**\n\t* Notify registered outcome observers about a processed response.\n\t*\n\t* Only question records are surfaced (non-question dismisses are skipped).\n\t* Observers run after ELO/SRS are recorded and before navigation. Each is\n\t* awaited but isolated in try/catch — a throwing observer is logged and\n\t* skipped, never wedging the session. Keep observers cheap and `void` any\n\t* long work (e.g. a triggered replan) to avoid stalling the draw.\n\t*/\n\t/**\n\t* Append a resolved ELO exchange to the in-memory log. Fires async (the ELO\n\t* update is non-blocking), so an event can land after the response that\n\t* produced it has returned — but well before close, which is when the log is\n\t* persisted. Bounded to avoid unbounded growth.\n\t*/\n\t_recordEloEvent(event) {\n\t\tif (this._eloLog.length >= SessionController.MAX_LOGGED_ELO_EVENTS) return;\n\t\tthis._eloLog.push(event);\n\t}\n\tasync _notifyOutcomeObservers(record, currentCard, result) {\n\t\tif (this._outcomeObservers.length === 0) return;\n\t\tif (!isQuestionRecord(record)) return;\n\t\tconst outcome = {\n\t\t\trecord,\n\t\t\tcard: currentCard.card,\n\t\t\tresult\n\t\t};\n\t\tconst controls = this._getSessionControls();\n\t\tfor (const observer of this._outcomeObservers) try {\n\t\t\tawait observer(outcome, controls);\n\t\t} catch (e) {\n\t\t\tthis.error(\"[OutcomeObserver] observer threw; ignoring\", e);\n\t\t}\n\t}\n\t/**\n\t* Run a replan, bypassing requestReplan()'s coalesce logic.\n\t*\n\t* Use this when correctness depends on a *fresh* pipeline run, not on\n\t* the existence of *some* in-flight replan. Specifically: the\n\t* wedge-breaker path in nextCard(), where coalescing into a previous\n\t* run that we now know produced insufficient content would re-create\n\t* the bug we're trying to prevent.\n\t*\n\t* Still tracks _replanPromise like requestReplan() does so concurrent\n\t* observers (auto-trigger guards in nextCard()) see consistent state.\n\t*/\n\tasync _replanUncoalesced(opts) {\n\t\tconst run = this._runReplan(opts);\n\t\tconst tracked = run.finally(() => {\n\t\t\tif (this._replanPromise === tracked) {\n\t\t\t\tthis._replanPromise = null;\n\t\t\t\tthis._activeReplanLabel = null;\n\t\t\t}\n\t\t});\n\t\tthis._replanPromise = tracked;\n\t\tawait run;\n\t}\n\t/**\n\t* Normalise the requestReplan argument. Accepts either a ReplanOptions\n\t* object (new API) or a plain Record<string, unknown> (legacy callers\n\t* that passed hints directly). Distinguishes the two by checking for\n\t* the presence of ReplanOptions-specific keys.\n\t*/\n\tnormalizeReplanOptions(input) {\n\t\tif (!input) return {};\n\t\tconst replanKeys = [\n\t\t\t\"hints\",\n\t\t\t\"sessionHints\",\n\t\t\t\"limit\",\n\t\t\t\"mode\",\n\t\t\t\"label\",\n\t\t\t\"minFollowUpCards\"\n\t\t];\n\t\tif (Object.keys(input).some((k) => replanKeys.includes(k))) return input;\n\t\treturn { hints: input };\n\t}\n\t/** Minimum well-indicated cards before an additive retry is attempted */\n\tstatic MIN_WELL_INDICATED = 5;\n\t/**\n\t* Score threshold for considering a card \"well-indicated.\"\n\t* Cards below this score are treated as fallback filler — present only\n\t* because no strategy hard-removed them, but likely penalized by one\n\t* or more filters. Strategy-agnostic: the SessionController doesn't\n\t* know or care which strategy assigned the score.\n\t*/\n\tstatic WELL_INDICATED_SCORE = .1;\n\t/**\n\t* supplyQ length at or below which the opportunistic depletion-prefetch\n\t* fires. Sets the lead time available for the background replan to land\n\t* before the user actually empties the queue and falls into the\n\t* (synchronous) wedge-breaker path.\n\t*\n\t* Set to a small absolute value (not a fraction of batch limit) because\n\t* pipeline latency is roughly fixed regardless of batch size — what\n\t* matters is \"how many cards of user-pace do we have left.\" 3 cards\n\t* × ~3-5s/card = ~10-15s of lead time, comfortably exceeding typical\n\t* pipeline latency.\n\t*/\n\tstatic DEPLETION_PREFETCH_THRESHOLD = 3;\n\t/**\n\t* Internal replan execution. Runs the pipeline, rebuilds the supplyQ,\n\t* atomically swaps it in, and triggers hydration for the new contents.\n\t*\n\t* If the initial replan produces fewer than MIN_WELL_INDICATED cards that\n\t* pass all hierarchy filters, one additive retry is attempted — merging\n\t* any new high-quality candidates into the front of the queue.\n\t*/\n\tasync _executeReplan(opts = {}) {\n\t\tconst limit = opts.limit;\n\t\tconst mode = opts.mode ?? \"replace\";\n\t\tconst wellIndicated = await this.getWeightedContent({\n\t\t\treplan: true,\n\t\t\tadditive: mode === \"merge\",\n\t\t\tlimit\n\t\t});\n\t\tthis._recordRuns(opts.label ?? \"(auto)\", mode);\n\t\tthis._wellIndicatedRemaining = wellIndicated;\n\t\tif (limit !== void 0 && limit < this._defaultBatchLimit) {\n\t\t\tthis._suppressQualityReplan = true;\n\t\t\tthis.log(`[Replan] Burst mode (limit=${limit}): suppressing quality-based auto-replan`);\n\t\t} else this._suppressQualityReplan = false;\n\t\tif (wellIndicated >= 0 && wellIndicated < SessionController.MIN_WELL_INDICATED) this.log(`[Replan] Only ${wellIndicated}/${SessionController.MIN_WELL_INDICATED} well-indicated cards after replan`);\n\t\tawait this.hydrationService.ensureHydratedCards();\n\t\tconst labelTag = opts.label ? ` [${opts.label}]` : \"\";\n\t\tthis.log(`Replan complete${labelTag}: supplyQ now has ${this.supplyQ.length} cards (mode=${mode})`);\n\t\tsnapshotQueues(this.supplyQ.length, this.failedQ.length);\n\t}\n\taddTime(seconds) {\n\t\tthis.endTime = new Date(this.endTime.valueOf() + 1e3 * seconds);\n\t}\n\tget failedCount() {\n\t\treturn this.failedQ.length;\n\t}\n\ttoString() {\n\t\treturn `Session: ${this.supplyQ.length} supply, ${this.failedQ.length} failed`;\n\t}\n\treportString() {\n\t\treturn `${this.supplyQ.dequeueCount} supply, ${this.failedQ.dequeueCount} failed`;\n\t}\n\t/**\n\t* Returns debug information about the current session state.\n\t* Used by SessionControllerDebug component for runtime inspection.\n\t*/\n\tgetDebugInfo() {\n\t\tconst supportsWeightedCards = this.sources.some((s) => typeof s.getWeightedCards === \"function\");\n\t\tconst extractQueueItems = (queue, limit = 10) => {\n\t\t\tconst items = [];\n\t\t\tfor (let i = 0; i < Math.min(queue.length, limit); i++) {\n\t\t\t\tconst item = queue.peek(i);\n\t\t\t\titems.push({\n\t\t\t\t\tcourseID: item.courseID || \"unknown\",\n\t\t\t\t\tcardID: item.cardID || \"unknown\",\n\t\t\t\t\tstatus: item.status || \"unknown\",\n\t\t\t\t\tscore: item.score\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn items;\n\t\t};\n\t\treturn {\n\t\t\tapi: {\n\t\t\t\tmode: supportsWeightedCards ? \"weighted\" : \"legacy\",\n\t\t\t\tdescription: supportsWeightedCards ? \"Using getWeightedCards() API with scored candidates\" : \"ERROR: getWeightedCards() not a function.\"\n\t\t\t},\n\t\t\tsupplyQueue: {\n\t\t\t\tlength: this.supplyQ.length,\n\t\t\t\tdequeueCount: this.supplyQ.dequeueCount,\n\t\t\t\titems: extractQueueItems(this.supplyQ)\n\t\t\t},\n\t\t\tfailedQueue: {\n\t\t\t\tlength: this.failedQ.length,\n\t\t\t\tdequeueCount: this.failedQ.dequeueCount,\n\t\t\t\titems: extractQueueItems(this.failedQ)\n\t\t\t},\n\t\t\thydratedCache: {\n\t\t\t\tcount: this.hydrationService.hydratedCount,\n\t\t\t\tcardIds: this.hydrationService.getHydratedCardIds()\n\t\t\t},\n\t\t\treplan: {\n\t\t\t\tinProgress: this._replanPromise !== null,\n\t\t\t\tsuppressQualityReplan: this._suppressQualityReplan,\n\t\t\t\tdefaultBatchLimit: this._defaultBatchLimit,\n\t\t\t\tminCardsGuarantee: this._minCardsGuarantee\n\t\t\t}\n\t\t};\n\t}\n\t/**\n\t* Fetch weighted content from all sources, mix across sources, and populate\n\t* the single supply queue in pipeline rank order.\n\t*\n\t* Reviews and new cards compete on one cross-comparable scale (SRS 0.5–1.0\n\t* w/ backlog pressure vs ELO 0.0–1.0) — there is no origin split and no\n\t* second mixer. The working set is `supplyLimit` cards (the top of the mixed\n\t* ranking, plus any `+INF` required cards floated to the front); replans\n\t* re-pull and re-rank the whole supply, so a heavy review backlog surfaces as\n\t* a refreshed top-ranked working set rather than a frozen 200-card snapshot.\n\t*\n\t* @param options.replan - If true, this is a mid-session replan rather than\n\t* initial session setup. Atomically replaces supplyQ contents and treats\n\t* empty results as non-fatal.\n\t* @param options.additive - If true (replan only), merge high-quality\n\t* candidates into the front of the existing supplyQ instead of replacing it.\n\t* @returns Number of \"well-indicated\" cards (passed all hierarchy filters)\n\t* in the new content. Returns -1 if no content was loaded.\n\t*/\n\tasync getWeightedContent(options) {\n\t\tconst replan = options?.replan ?? false;\n\t\tconst additive = options?.additive ?? false;\n\t\tconst supplyLimit = options?.limit ?? this._defaultBatchLimit;\n\t\tconst fetchLimit = supplyLimit;\n\t\tif (!replan) this._applyHintsToSources();\n\t\tconst batches = [];\n\t\tfor (let i = 0; i < this.sources.length; i++) {\n\t\t\tconst source = this.sources[i];\n\t\t\ttry {\n\t\t\t\tconst weighted = (await source.getWeightedCards(fetchLimit)).cards;\n\t\t\t\tbatches.push({\n\t\t\t\t\tsourceIndex: i,\n\t\t\t\t\tweighted\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthis.error(`Failed to get content from source ${i}:`, error);\n\t\t\t\tif (this.sources.length === 1 && !replan) throw new Error(`Cannot start session: failed to load content from source ${i}`);\n\t\t\t}\n\t\t}\n\t\tif (batches.length === 0) {\n\t\t\tif (replan) {\n\t\t\t\tthis.log(\"Replan: no content from any source, keeping existing supplyQ\");\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tthrow new Error(`Cannot start session: failed to load content from all ${this.sources.length} source(s). Check logs for details.`);\n\t\t}\n\t\tconst mixedWeighted = this.mixer.mix(batches, fetchLimit * this.sources.length);\n\t\tconst sourceIds = batches.map((b) => {\n\t\t\treturn b.weighted[0]?.courseId || `source-${b.sourceIndex}`;\n\t\t});\n\t\tawait Promise.all(sourceIds.map(async (id) => {\n\t\t\tif (!this.courseNameCache.has(id)) try {\n\t\t\t\tconst config = await this.dataLayer.getCoursesDB().getCourseConfig(id);\n\t\t\t\tthis.courseNameCache.set(id, config.name);\n\t\t\t} catch {}\n\t\t}));\n\t\tconst sourceNames = sourceIds.map((id) => this.courseNameCache.get(id));\n\t\tconst quotaPerSource = this.mixer instanceof QuotaRoundRobinMixer ? Math.ceil(fetchLimit * this.sources.length / batches.length) : void 0;\n\t\tcaptureMixerRun(this.mixer.constructor.name, batches, sourceIds, sourceNames, fetchLimit * this.sources.length, quotaPerSource, mixedWeighted);\n\t\tconst candidates = mixedWeighted.filter((w) => !this._servedCardIds.has(w.cardId));\n\t\tconst mandatoryWeighted = candidates.filter((w) => w.score === Number.POSITIVE_INFINITY);\n\t\tconst optionalWeighted = candidates.filter((w) => w.score !== Number.POSITIVE_INFINITY);\n\t\tconst supplyWeighted = [...mandatoryWeighted, ...optionalWeighted.slice(0, Math.max(0, supplyLimit - mandatoryWeighted.length))];\n\t\tconst mandatoryIds = new Set(mandatoryWeighted.map((w) => w.cardId));\n\t\tconst wellIndicated = supplyWeighted.filter((w) => w.score >= SessionController.WELL_INDICATED_SCORE).length;\n\t\tlet report = replan ? \"Replan content:\\n\" : \"Mixed content session created with:\\n\";\n\t\tconst supplyItems = supplyWeighted.map((w) => {\n\t\t\tconst origin = getCardOrigin(w);\n\t\t\tconst scoreStr = Number.isFinite(w.score) ? w.score.toFixed(2) : \"+INF\";\n\t\t\treport += `${origin === \"review\" ? \"Review\" : \"New\"}: ${w.courseId}::${w.cardId} (score: ${scoreStr})\\n`;\n\t\t\treturn this._buildSupplyItem(w, origin);\n\t\t});\n\t\tif (additive) {\n\t\t\tconst added = this.supplyQ.mergeToFront(supplyItems, (item) => item.cardID, mandatoryIds);\n\t\t\treport += `Additive merge: ${added} cards added to front of supplyQ\\n`;\n\t\t} else if (replan) this.supplyQ.replaceAll(supplyItems, (item) => item.cardID);\n\t\telse for (const item of supplyItems) this.supplyQ.add(item, item.cardID);\n\t\tthis.log(report);\n\t\treturn wellIndicated;\n\t}\n\t/**\n\t* Build a supply item from a weighted candidate. Review-origin cards carry\n\t* their `reviewID` so SRS outcome tracking and re-presentation work; new\n\t* cards do not. `score` is carried on both for the debug overlay.\n\t*/\n\t_buildSupplyItem(w, origin = getCardOrigin(w)) {\n\t\tconst base = {\n\t\t\tcardID: w.cardId,\n\t\t\tcourseID: w.courseId,\n\t\t\tcontentSourceType: \"course\",\n\t\t\tcontentSourceID: w.courseId,\n\t\t\tscore: w.score\n\t\t};\n\t\tif (origin === \"review\") return {\n\t\t\t...base,\n\t\t\tstatus: \"review\",\n\t\t\treviewID: w.reviewID\n\t\t};\n\t\treturn {\n\t\t\t...base,\n\t\t\tstatus: \"new\"\n\t\t};\n\t}\n\t/**\n\t* Returns items that should be pre-hydrated.\n\t* Deterministic: top N items from each queue to ensure coverage.\n\t* Failed queue items will typically already be hydrated (from initial render).\n\t*/\n\t_getItemsToHydrate() {\n\t\tconst items = [];\n\t\tconst SUPPLY_PREFETCH = 3;\n\t\tconst FAILED_PREFETCH = 2;\n\t\tfor (let i = 0; i < Math.min(SUPPLY_PREFETCH, this.supplyQ.length); i++) items.push(this.supplyQ.peek(i));\n\t\tfor (let i = 0; i < Math.min(FAILED_PREFETCH, this.failedQ.length); i++) items.push(this.failedQ.peek(i));\n\t\treturn items;\n\t}\n\t/**\n\t* Selects the next item to present to the user.\n\t*\n\t* The supplyQ is already rank-ordered (the pipeline + mixer did the mixing,\n\t* with `+INF` required cards floated to the front), so the primary path is a\n\t* deterministic front-to-back draw — no second new-vs-review mixer. The only\n\t* remaining decisions are (a) when the session ends and (b) when to interleave\n\t* a remediation card from failedQ. See decision doc §2/§3/§7.\n\t*/\n\t_selectNextItemToHydrate() {\n\t\tif (this.supplyQ.length === 0 && this.failedQ.length === 0) return null;\n\t\tif (this._secondsRemaining < 2 && this.failedQ.length === 0 && this._minCardsGuarantee <= 0) return null;\n\t\tif (this._secondsRemaining <= 0 && this._minCardsGuarantee <= 0) return this.failedQ.length > 0 ? this.failedQ.peek(0) : null;\n\t\tconst supplyTop = this.supplyQ.length > 0 ? this.supplyQ.peek(0) : null;\n\t\tif (this._minCardsGuarantee > 0 && supplyTop) return supplyTop;\n\t\tif (this.failedQ.length > 0 && this._shouldInterleaveFailed(supplyTop !== null)) return this.failedQ.peek(0);\n\t\tif (supplyTop) return supplyTop;\n\t\tif (this.failedQ.length > 0) return this.failedQ.peek(0);\n\t\tthis.log(`No more cards available for the session!`);\n\t\treturn null;\n\t}\n\t/** Supply draws between forced failed-queue interleaves (light steady cadence). */\n\tstatic FAILED_INTERLEAVE_EVERY = 4;\n\t/**\n\t* Slack (seconds) below which the endgame failed-pressure kicks in: when the\n\t* time left after clearing remediation drops under this, bias hard to failed\n\t* so the session doesn't end with un-cleared remediation. Mirrors the old\n\t* `availableTime > 20` ladder thresholds.\n\t*/\n\tstatic FAILED_ENDGAME_SLACK_SECONDS = 20;\n\t/**\n\t* Whether to interleave a failed (remediation) card now instead of drawing\n\t* the supply head. Replaces the old `newBound`/`reviewBound` probability\n\t* ladder's failed path (decision doc §7).\n\t*\n\t* @param supplyAvailable - whether supplyQ has a card to draw instead.\n\t*/\n\t_shouldInterleaveFailed(supplyAvailable) {\n\t\tif (this.failedQ.length === 0) return false;\n\t\tif (!supplyAvailable) return true;\n\t\tif (this._secondsRemaining - this.estimateCleanupTime() <= SessionController.FAILED_ENDGAME_SLACK_SECONDS) return true;\n\t\treturn this._supplyDrawsSinceFailed >= SessionController.FAILED_INTERLEAVE_EVERY;\n\t}\n\tasync nextCard(action = \"dismiss-success\") {\n\t\tthis.dismissCurrentCard(action);\n\t\tif (this._minCardsGuarantee > 0) {\n\t\t\tthis._minCardsGuarantee--;\n\t\t\tthis.log(`[CardGuarantee] ${this._minCardsGuarantee} guaranteed cards remaining`);\n\t\t}\n\t\tif (this._replanPromise && this.supplyQ.length === 0 && this.failedQ.length === 0) {\n\t\t\tthis.log(\"nextCard: queues empty, awaiting in-flight replan before drawing\");\n\t\t\tawait this._replanPromise;\n\t\t}\n\t\tif (this.supplyQ.length <= SessionController.DEPLETION_PREFETCH_THRESHOLD && this._secondsRemaining > 0 && !this._replanPromise) {\n\t\t\tthis._suppressQualityReplan = false;\n\t\t\tthis.log(`[AutoReplan:depletion] supplyQ has ${this.supplyQ.length} card(s) (${this.failedQ.length} failed pending) with ${this._secondsRemaining}s remaining. Triggering background replan.`);\n\t\t\tthis.requestReplan({\n\t\t\t\tlabel: \"auto:depletion\",\n\t\t\t\tmode: \"merge\"\n\t\t\t});\n\t\t}\n\t\tif (!this._suppressQualityReplan && this._wellIndicatedRemaining <= 3 && this.supplyQ.length > 0 && !this._replanPromise) {\n\t\t\tthis.log(`[AutoReplan:quality] ${this._wellIndicatedRemaining} well-indicated cards remaining (supplyQ: ${this.supplyQ.length}). Triggering background replan.`);\n\t\t\tthis.requestReplan({ label: \"auto:quality\" });\n\t\t}\n\t\tif (this._secondsRemaining <= 0 && this.failedQ.length === 0 && this._minCardsGuarantee <= 0) {\n\t\t\tthis._currentCard = null;\n\t\t\tendSessionTracking();\n\t\t\tthis._terminate();\n\t\t\treturn null;\n\t\t}\n\t\tconst WEDGE_MAX_EMPTY_STREAK = 3;\n\t\tconst WEDGE_BACKOFF_MS = 250;\n\t\tlet wedgeEmptyStreak = 0;\n\t\twhile (this._secondsRemaining > 0 && this.supplyQ.length === 0 && this.failedQ.length === 0) {\n\t\t\tthis.log(`[WedgeBreaker] All queues empty with ${this._secondsRemaining}s remaining. Running pipeline (attempt ${wedgeEmptyStreak + 1}/${WEDGE_MAX_EMPTY_STREAK}).`);\n\t\t\tawait this._replanUncoalesced({ label: \"wedge-breaker\" });\n\t\t\tif (this.supplyQ.length === 0 && this.failedQ.length === 0) {\n\t\t\t\twedgeEmptyStreak++;\n\t\t\t\tif (wedgeEmptyStreak >= WEDGE_MAX_EMPTY_STREAK) {\n\t\t\t\t\tthis.log(`[WedgeBreaker] Pipeline returned no content ${WEDGE_MAX_EMPTY_STREAK} consecutive times. Giving up; session will end.`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, WEDGE_BACKOFF_MS));\n\t\t\t} else wedgeEmptyStreak = 0;\n\t\t}\n\t\tconst MAX_SKIP = 20;\n\t\tfor (let attempt = 0; attempt < MAX_SKIP; attempt++) {\n\t\t\tconst nextItem = this._selectNextItemToHydrate();\n\t\t\tif (!nextItem) {\n\t\t\t\tthis._currentCard = null;\n\t\t\t\tendSessionTracking();\n\t\t\t\tthis._terminate();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tlet card = this.hydrationService.getHydratedCard(nextItem.cardID);\n\t\t\tif (!card) card = await this.hydrationService.waitForCard(nextItem.cardID);\n\t\t\tthis.removeItemFromQueue(nextItem);\n\t\t\tif (card) {\n\t\t\t\tawait this.hydrationService.ensureHydratedCards();\n\t\t\t\tthis._currentCard = card;\n\t\t\t\tconst origin = nextItem.status === \"review\" || nextItem.status === \"failed-review\" ? \"review\" : nextItem.status === \"new\" || nextItem.status === \"failed-new\" ? \"new\" : \"failed\";\n\t\t\t\tconst queueSource = nextItem.status.startsWith(\"failed\") ? \"failedQ\" : \"supplyQ\";\n\t\t\t\trecordCardPresentation(nextItem.cardID, nextItem.courseID, this.courseNameCache.get(nextItem.courseID), origin, queueSource, nextItem.score);\n\t\t\t\tfor (const source of this.sources) source.notePresented?.({\n\t\t\t\t\tcardId: nextItem.cardID,\n\t\t\t\t\tcourseId: nextItem.courseID,\n\t\t\t\t\tstatus: nextItem.status\n\t\t\t\t});\n\t\t\t\tsnapshotQueues(this.supplyQ.length, this.failedQ.length);\n\t\t\t\treturn card;\n\t\t\t}\n\t\t\tthis.log(`Skipping card ${nextItem.cardID}: hydration failed, trying next`);\n\t\t\tif (isReview(nextItem)) this.srsService.removeReview(nextItem.reviewID);\n\t\t}\n\t\tthis.log(`Exhausted ${MAX_SKIP} skip attempts finding a hydratable card`);\n\t\tthis._currentCard = null;\n\t\tendSessionTracking();\n\t\tthis._terminate();\n\t\treturn null;\n\t}\n\t/** Not awaited — the host renders the end screen off `nextCard()`'s null. */\n\t_terminate() {\n\t\tthis.endSession().catch((e) => {\n\t\t\tlogger.warn(`[SessionController] endSession failed: ${e}`);\n\t\t});\n\t}\n\t/**\n\t* Public API for processing user responses to cards.\n\t* @param cardRecord User's response record\n\t* @param cardHistory Promise resolving to the card's history\n\t* @param courseRegistrationDoc User's course registration document\n\t* @param currentCard Current study session record\n\t* @param courseId Course identifier\n\t* @param cardId Card identifier\n\t* @param maxAttemptsPerView Maximum attempts allowed per view\n\t* @param maxSessionViews Maximum session views for this card\n\t* @param sessionViews Current number of session views\n\t* @returns ResponseResult with navigation and UI instructions\n\t*/\n\tasync submitResponse(cardRecord, cardHistory, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews) {\n\t\tconst studySessionItem = { ...currentCard.item };\n\t\tconst result = await this.services.response.processResponse(cardRecord, cardHistory, studySessionItem, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews);\n\t\tawait this._notifyOutcomeObservers(cardRecord, currentCard, result);\n\t\treturn result;\n\t}\n\tdismissCurrentCard(action = \"dismiss-success\") {\n\t\tif (this._currentCard) {\n\t\t\tif (action === \"dismiss-success\") this.hydrationService.removeCard(this._currentCard.item.cardID);\n\t\t\telse if (action === \"marked-failed\") {\n\t\t\t\tlet failedItem;\n\t\t\t\tif (isReview(this._currentCard.item)) failedItem = {\n\t\t\t\t\tcardID: this._currentCard.item.cardID,\n\t\t\t\t\tcourseID: this._currentCard.item.courseID,\n\t\t\t\t\tcontentSourceID: this._currentCard.item.contentSourceID,\n\t\t\t\t\tcontentSourceType: this._currentCard.item.contentSourceType,\n\t\t\t\t\tstatus: \"failed-review\",\n\t\t\t\t\treviewID: this._currentCard.item.reviewID\n\t\t\t\t};\n\t\t\t\telse failedItem = {\n\t\t\t\t\tcardID: this._currentCard.item.cardID,\n\t\t\t\t\tcourseID: this._currentCard.item.courseID,\n\t\t\t\t\tcontentSourceID: this._currentCard.item.contentSourceID,\n\t\t\t\t\tcontentSourceType: this._currentCard.item.contentSourceType,\n\t\t\t\t\tstatus: \"failed-new\"\n\t\t\t\t};\n\t\t\t\tthis.failedQ.add(failedItem, failedItem.cardID);\n\t\t\t\tthis._supplyDrawsSinceFailed = 0;\n\t\t\t} else if (action === \"dismiss-error\") this.hydrationService.removeCard(this._currentCard.item.cardID);\n\t\t\telse if (action === \"dismiss-failed\") this.hydrationService.removeCard(this._currentCard.item.cardID);\n\t\t}\n\t}\n\t/**\n\t* Remove an item from its source queue after consumption by nextCard().\n\t*/\n\tremoveItemFromQueue(item) {\n\t\tthis._clearDurableRequirement(item.cardID);\n\t\tthis._servedCardIds.add(item.cardID);\n\t\tif (this.failedQ.peek(0)?.cardID === item.cardID) {\n\t\t\tthis.failedQ.dequeue((queueItem) => queueItem.cardID);\n\t\t\tthis._supplyDrawsSinceFailed = 0;\n\t\t} else if (this.supplyQ.peek(0)?.cardID === item.cardID) {\n\t\t\tthis.supplyQ.dequeue((queueItem) => queueItem.cardID);\n\t\t\tthis._supplyDrawsSinceFailed++;\n\t\t\tif (this._wellIndicatedRemaining > 0) this._wellIndicatedRemaining--;\n\t\t}\n\t}\n\t/**\n\t* Remove a satisfied card ID from the durable session-hint `requireCards`\n\t* list. Called when a card is consumed (see removeItemFromQueue). No-op if\n\t* the card was not a durable requirement.\n\t*\n\t* Matches literal IDs only: a glob/pattern requirement (which may stand for\n\t* several cards) is NOT considered satisfied by a single draw and is left in\n\t* place — durable patterns are the caller's responsibility, one-shot `hints`\n\t* remain the right tool for them.\n\t*/\n\t_clearDurableRequirement(cardID) {\n\t\tconst req = this._sessionHints?.requireCards;\n\t\tif (!req || req.length === 0) return;\n\t\tconst next = req.filter((id) => id !== cardID);\n\t\tif (next.length === req.length) return;\n\t\tthis._sessionHints = {\n\t\t\t...this._sessionHints,\n\t\t\trequireCards: next.length > 0 ? next : void 0\n\t\t};\n\t\tthis.log(`[Replan] Durable requirement satisfied & cleared on draw: ${cardID}`);\n\t}\n\t/**\n\t* End the session and record learning outcomes.\n\t*\n\t* This method aggregates all responses from the session and records a\n\t* UserOutcomeRecord if evolutionary orchestration is enabled.\n\t*/\n\t/**\n\t* Idempotent. Called from every `nextCard()` path that returns null; hosts\n\t* should also call it with `'abandoned'` when tearing down mid-session.\n\t*/\n\tasync endSession(reason = \"closed\") {\n\t\tif (this._sessionClosed) return;\n\t\tthis._sessionClosed = true;\n\t\tclearInterval(this._intervalHandle);\n\t\tsetDebugSessionId(void 0);\n\t\tawait this._closeSessionDoc(reason);\n\t\tif (!this._sessionRecord || this._sessionRecord.length === 0) return;\n\t\tconst questionRecords = this._sessionRecord.flatMap((r) => r.records).filter((r) => r.userAnswer !== void 0);\n\t\tif (questionRecords.length === 0) return;\n\t\tlet orchestrationContext = null;\n\t\tconst strategies = [];\n\t\tfor (const source of this.sources) if (source.getOrchestrationContext) {\n\t\t\ttry {\n\t\t\t\torchestrationContext = await source.getOrchestrationContext();\n\t\t\t\tif (source.getStrategyIds) strategies.push(...source.getStrategyIds());\n\t\t\t} catch (e) {\n\t\t\t\tlogger.warn(`[SessionController] Failed to get orchestration context: ${e}`);\n\t\t\t}\n\t\t\tif (orchestrationContext) break;\n\t\t}\n\t\tif (!orchestrationContext) {\n\t\t\tlogger.debug(\"[SessionController] No orchestration context available, skipping outcome recording\");\n\t\t\treturn;\n\t\t}\n\t\tconst periodEnd = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst periodStart = new Date(this.startTime).toISOString();\n\t\tawait recordUserOutcome(orchestrationContext, periodStart, periodEnd, questionRecords, strategies);\n\t}\n\tasync _closeSessionDoc(reason) {\n\t\tif (this._openDocPromise) await this._openDocPromise;\n\t\tconst doc = this._sessionDoc;\n\t\tif (!doc) return;\n\t\tconst records = this._sessionRecord.flatMap((r) => r.records);\n\t\tconst questionRecords = records.filter(isQuestionRecord);\n\t\ttry {\n\t\t\tconst closed = {\n\t\t\t\t...doc,\n\t\t\t\tstatus: reason,\n\t\t\t\tendTime: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\ttally: {\n\t\t\t\t\tcardsPresented: this._sessionRecord.length,\n\t\t\t\t\tresponses: records.length,\n\t\t\t\t\tcorrect: questionRecords.filter((r) => r.isCorrect).length,\n\t\t\t\t\tincorrect: questionRecords.filter((r) => !r.isCorrect).length,\n\t\t\t\t\tfailedQRemaining: this.failedQ.length,\n\t\t\t\t\tsecondsRemaining: Math.max(0, this._secondsRemaining)\n\t\t\t\t},\n\t\t\t\truns: [...this._runLog],\n\t\t\t\teloEvents: [...this._eloLog],\n\t\t\t\tfinalHints: this._sessionHints,\n\t\t\t\tstateAtEnd: await this._captureState(\"end\")\n\t\t\t};\n\t\t\tthis._sessionDoc = closed;\n\t\t\tawait this.dataLayer.getUserDB().putStudySession(closed);\n\t\t\tthis.log(`[Session] Session record ${closed._id} -> ${reason} (${closed.tally.cardsPresented} cards, ${closed.tally.responses} responses, ${this._runLog.length} pipeline runs)`);\n\t\t} catch (e) {\n\t\t\tlogger.warn(`[SessionController] Failed to close session record: ${e}`);\n\t\t}\n\t}\n};\n//#endregion\nexport { SessionController };\n\n//# sourceMappingURL=SessionController.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { Status } from \"@vue-skuilder/common\";\n//#region src/core/bulkImport/cardProcessor.ts\n/**\n* Processes multiple cards from bulk text input\n*\n* @param parsedCards - Array of parsed cards to import\n* @param courseDB - Course database interface\n* @param config - Configuration for the card processor\n* @returns Array of import results\n*/\nasync function importParsedCards(parsedCards, courseDB, config) {\n\tconst results = [];\n\tfor (const parsedCard of parsedCards) try {\n\t\tconst result = await processCard(parsedCard, courseDB, config);\n\t\tresults.push(result);\n\t} catch (error) {\n\t\tlogger.error(\"Error processing card:\", error);\n\t\tlet errorOriginalText = parsedCard.markdown;\n\t\tif (parsedCard.tags && parsedCard.tags.length > 0) errorOriginalText += `\\ntags: ${parsedCard.tags.join(\", \")}`;\n\t\tif (parsedCard.elo !== void 0) errorOriginalText += `\\nelo: ${parsedCard.elo}`;\n\t\tresults.push({\n\t\t\toriginalText: errorOriginalText,\n\t\t\tstatus: \"error\",\n\t\t\tmessage: `Error processing card: ${error instanceof Error ? error.message : \"Unknown error\"}`\n\t\t});\n\t}\n\treturn results;\n}\n/**\n* Processes a single parsed card\n*\n* @param parsedCard - Parsed card data\n* @param courseDB - Course database interface\n* @param config - Configuration for the card processor\n* @returns Import result for the card\n*/\nasync function processCard(parsedCard, courseDB, config) {\n\tconst { markdown, tags, elo } = parsedCard;\n\tlet originalText = markdown;\n\tif (tags.length > 0) originalText += `\\ntags: ${tags.join(\", \")}`;\n\tif (elo !== void 0) originalText += `\\nelo: ${elo}`;\n\tconst cardData = {\n\t\tInput: markdown,\n\t\tUploads: []\n\t};\n\tconst tagsElo = {};\n\tfor (const tag of tags) tagsElo[tag] = {\n\t\tscore: elo || 0,\n\t\tcount: 1\n\t};\n\ttry {\n\t\tconst result = await courseDB.addNote(config.courseCode, config.dataShape, cardData, config.userName, tags, void 0, elo ? {\n\t\t\tglobal: {\n\t\t\t\tscore: elo,\n\t\t\t\tcount: 1\n\t\t\t},\n\t\t\ttags: tagsElo,\n\t\t\tmisc: {}\n\t\t} : void 0);\n\t\tif (result.status === Status.ok) return {\n\t\t\toriginalText,\n\t\t\tstatus: \"success\",\n\t\t\tmessage: \"Card added successfully.\",\n\t\t\tcardId: result.id ? result.id : \"(unknown)\"\n\t\t};\n\t\telse return {\n\t\t\toriginalText,\n\t\t\tstatus: \"error\",\n\t\t\tmessage: result.message || \"Failed to add card to database. Unknown error.\"\n\t\t};\n\t} catch (error) {\n\t\tlogger.error(\"Error adding note:\", error);\n\t\treturn {\n\t\t\toriginalText,\n\t\t\tstatus: \"error\",\n\t\t\tmessage: `Error adding card: ${error instanceof Error ? error.message : \"Unknown error\"}`\n\t\t};\n\t}\n}\n/**\n* Validates the configuration for bulk card processing\n*\n* @param config - Configuration to validate\n* @returns Object with validation result and error message if any\n*/\nfunction validateProcessorConfig(config) {\n\tif (!config.dataShape) return {\n\t\tisValid: false,\n\t\terrorMessage: \"No data shape provided for card processing\"\n\t};\n\tif (!config.courseCode) return {\n\t\tisValid: false,\n\t\terrorMessage: \"No course code provided for card processing\"\n\t};\n\tif (!config.userName) return {\n\t\tisValid: false,\n\t\terrorMessage: \"No user name provided for card processing\"\n\t};\n\treturn { isValid: true };\n}\n//#endregion\nexport { importParsedCards, validateProcessorConfig };\n\n//# sourceMappingURL=cardProcessor.mjs.map"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./vue.runtime.esm-bundler--Fxmd6l9.js";import"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import"./dist-BsRvt0gH.js";import"./contentSource-DwznMSMs.js";import{i as e}from"./edit-ui.es-UaQFL_My.js";import"./dist-Dp6eBE2S.js";import"./CourseWare-BTFRjgBR-DBp_fIwH.js";import"./PipelineDebugger-BHaqzqZw.js";import"./eloDistance-BV7vfiK5.js";import"./chess-E2uOAyQS-BZi0vihz.js";import"./math-D_8HiEQR-E4QDLrWp.js";import"./piano-DF1g6yaX-Ck3BH5EK.js";import"./sightsing-BFQ7HRig-DV69ELZf.js";import"./typing-BevtfWlp-CvStu5BY.js";export{e as CourseEditor};
|