diff --git a/AGENTS.md b/AGENTS.md index 7cbf45147..c409ed992 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,6 +49,8 @@ The driving agent owns state, cycle selection and completion claims; GStack supp **Delivery parameters.** The merge is a squash merge: `gh pr merge --squash --match-head-commit `. `/ship`'s documentation candidate (`gstack-docs-candidate snapshot`) takes the kept documents as `--docs` roots: AGENTS.md, CHANGELOG.md, PRODUCT_GOAL.md, README.md, `extension/README.md`, `extension/skills/codebook/SKILL.md` and the v9 PNG. CI packages the extension with `node extension/scripts/package.mjs --out artifacts/packages/codebook.vsix` and checks it with `node extension/scripts/check-package.mjs artifacts/packages/codebook.vsix` (`package.yml`). A release commit changes one test line besides the version files and CHANGELOG.md, the expected version in `extension/scripts/tests/package.test.mjs`; `/ship`'s Step 16 counts that edit as release metadata, not as a change to the reviewed tree. +**Pre-gate (owner, 2026-10-22).** `/ship`'s pre-gate runs Stage 1 only: `gstack-pregate --stage preflight --allow-repo-commands`, its secrets scan every time. The test lanes (Stage 2) are covered by `pnpm --dir extension test` on the final tree and by required CI. + **Background work.** `node extension/scripts/watch-background.mjs` (from the directory Claude Code started in, else with `--project `) lists the current Claude Code session's background tasks and subagents (its `CLAUDE_CODE_SESSION_ID`), each with the time of its last output, and marks those silent for more than 20 minutes; a finished or stopped subagent is never marked, a shell's row stays marked after it ended (its task notification is the authority). Stop a review subagent that has written nothing for 20 minutes and dispatch it again on a narrower scope; dispatch a subagent that the API's safety filter stopped again at once, with the same brief, on the fallback model. While waiting longer than a few minutes, tell the owner what is awaited and since when. **Ship review limit (owner, 2026-10-18).** After the installed `/ship`'s three fixing cycles, stop and report `converged:false`: no fourth cycle, no counter reset after a handoff, no round relabeled a repair; the no-carry rule does not waive this. An unconverged ship is no completed delivery. Only the owner starts a new invocation, with its own count. The owner's order for Cycle 0046's second invocation: if it also stops unconverged, its open findings become the next cycle's tasks and that cycle's PR holds only their fixes (Cycle 0047's delivery ended the same way). diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e0717aa..4616c383f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [0.2.35.0] - 2026-10-23 (development candidate) + +Cycle 0049's third pull request ([Issue #107](https://github.com/laststance/codebook/issues/107)): a test replay's executed source in one recorded-source tab that the native debugger opens, moves that never show two moments at once, the unrecorded time on the slider and a bounded wait in Play. The native round in VS Code and Cursor follows this merge. + +**The executed source at the selected moment.** + +- **One recorded-source tab.** A test replay shows its executed source in one tab named after the stop's file (`Captured-`). At a stop whose recorded source verifies, the tab holds that file as it ran, with the stopped line highlighted and labelled `Recorded: : · s`. A stop in a file with another name renames the tab and Codebook closes the tab it opened before, so a replay never leaves a tab per stop; returning to Live or opening another saved study closes it. +- **The native debugger at the same moment.** At such a stop the debugger's thread reads `Recorded test stop · :`, shows that stop's recorded values and stack, and its frames open the same tab. At an output, at the result and at a stop whose source does not verify, the tab holds `// Recorded source · Not recorded at this moment` and `// The test journal holds no source state for this moment.` (comments, so the editor reports no problem for them), and the debugger's thread reads `Not recorded at this moment` with no frames, also when the replay opens on such a moment. +- **One moment at a time.** Each move first takes the earlier moment off the debugger and the tab, then shows the new moment's source in the tab, then presents the debugger at it, and then shows the stopped line, its label, the Study position and the Application output together. Quick moves, an overtaken move and a return to the moment already shown leave no other moment's stop in the debugger and no extra tab. If the tab cannot open, the Study pane says `Codebook could not open the recorded source of stop : . Details: Output › Codebook.`, the moment stays selected with no stop in the debugger, and **Retry** opens the tab again; returning to Live takes that line with it. + +**The slider and Play.** The time slider marks the recording between its first and last event as unrecorded, with a tick at each stop whose recorded source verifies, under `Ticks mark recorded stops; source and debugger are not recorded between them.` (a test journal records when a stop paused, not when the test resumed). **Play** moves from event to event and waits at most 1.5 seconds for the next one, also across an unrecorded interval, which it neither pauses at nor asks about; each surface shows the selected event's own time. + +**Compatibility.** The MCP API stays 1.8 and the bundled skill 1.0.46. No stored format changes: test histories, learning materials and reader positions written by 0.2.34.0 open unchanged, and those written now open in 0.2.34.0. + +**Not observed.** The recorded-source tab was checked natively in VS Code 1.142.0 and Cursor 3.26.13 on macOS (one tab per replay, renamed per file, the label or the placeholder visible, the debugger's top frame opening the tab), on saved test replays recorded through Codebook's tools without a chat; no chat-driven run of this version has reached a stop yet. Motion between moments is not recorded natively yet. A tab the editor restores after a restart serves the placeholder until a replay shows its own tab. Windows and Linux are not run. + ## [0.2.34.0] - 2026-10-22 (development candidate) Cycle 0049's second pull request ([Issue #107](https://github.com/laststance/codebook/issues/107)): a test replay's recorded test output in the Application pane, and the Study pane's test replay section rebuilt around the selected moment. The recorded source with its transitions and the native round in both editors come with the third pull request. diff --git a/README.md b/README.md index 8ad283a59..96ff54447 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Codebook contributes `debug.focusEditorOnBreak: false` as the native debugger de ## Implementation status -This is a preview, not a Marketplace or Open VSX release. The delivered version is **0.2.34.0** once the second pull request of [Cycle 0049](https://github.com/laststance/codebook/issues/107) is merged; until then 0.2.33.0 ([PR #113](https://github.com/laststance/codebook/pull/113)) is the delivered one, and the active cycle Issue says where the delivery stands. Cycle 0049 is a feature cycle: a Vitest test run that the editor chat explained becomes a learning replay, a **test replay**. Its first pull request holds the loop and its contracts: a test run reads `demonstrated` once its test passed after every declared stop and its history sealed complete; **Save learning replay** and **Open replay** in the status bar save and open it (its test output, the executed source and the native debugger's recorded stops; no application video); the run resource tells the agent the test's result and which explanations the saved learning still lacks; a node-test start's refusals arrive before its first stop with their fix; and the bundled skill 1.0.46 routes a question about a test to this flow. The MCP API is 1.8. Its second pull request shows the recorded test output in the Application pane, updated in place up to the selected moment, and rebuilds the Study pane's test replay section around that moment (Previous stop and Next stop first, the learning summary drawn as a browser replay's with the selected step); the recorded source with its transitions and the native round in both editors come with its third; the test replay's summary in the Learning summary view is the next feature cycle. What each earlier cycle delivered, with its tests, trials and limits, is in the [change history](CHANGELOG.md) and in that cycle's record, kept under the tag [`docs-archive-2026-10-20`](https://github.com/laststance/codebook/tree/docs-archive-2026-10-20/docs/cycles); from Cycle 0048 on, the cycle's Issue holds its tasks and state, and its pull requests the results. +This is a preview, not a Marketplace or Open VSX release. The delivered version is **0.2.35.0** once the third pull request of [Cycle 0049](https://github.com/laststance/codebook/issues/107) is merged; until then 0.2.34.0 ([PR #116](https://github.com/laststance/codebook/pull/116)) is the delivered one, and the active cycle Issue says where the delivery stands. Cycle 0049 is a feature cycle: a Vitest test run that the editor chat explained becomes a learning replay, a **test replay**. Its first pull request holds the loop and its contracts: a test run reads `demonstrated` once its test passed after every declared stop and its history sealed complete; **Save learning replay** and **Open replay** in the status bar save and open it (its test output, the executed source and the native debugger's recorded stops; no application video); the run resource tells the agent the test's result and which explanations the saved learning still lacks; a node-test start's refusals arrive before its first stop with their fix; and the bundled skill 1.0.46 routes a question about a test to this flow. The MCP API is 1.8. Its second pull request shows the recorded test output in the Application pane, updated in place up to the selected moment, and rebuilds the Study pane's test replay section around that moment (Previous stop and Next stop first, the learning summary drawn as a browser replay's with the selected step); its third shows the executed source in one recorded-source tab that the native debugger's frames open, takes the earlier moment off the tab and the debugger before each move, marks the unrecorded time on the slider and bounds Play's wait between events; the native round in both editors follows its merge; the test replay's summary in the Learning summary view is the next feature cycle. What each earlier cycle delivered, with its tests, trials and limits, is in the [change history](CHANGELOG.md) and in that cycle's record, kept under the tag [`docs-archive-2026-10-20`](https://github.com/laststance/codebook/tree/docs-archive-2026-10-20/docs/cycles); from Cycle 0048 on, the cycle's Issue holds its tasks and state, and its pull requests the results. The specification is [goal version 10](PRODUCT_GOAL.md), and the implementation targets external repositories. Historical fixture or coupled-Wiki success is not proof of that destination. diff --git a/VERSION b/VERSION index f4c9ab72e..44c06ae5a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.34.0 +0.2.35.0 diff --git a/extension/README.md b/extension/README.md index b7323d8d6..713e1b875 100644 --- a/extension/README.md +++ b/extension/README.md @@ -76,6 +76,10 @@ The **Application pane** shows a test replay's recorded test output up to the se The Study pane's **Test replay** section names the result, the capture and the explained stops, then the selected moment (`Stop of · s`, `Output · s` or `Result · · s`) with the explanation the chat saved for it, or `No saved explanation for this stop.`; at an output, at the result and at a stop whose recorded source does not verify it adds `Source and debugger not recorded at this moment.` **Previous stop** and **Next stop**, first in the section's transport, move between stops, **Previous event** and **Next event** through every event, and **Play** and the time slider move through the recording. The learning summary is drawn as a browser replay's: a sequence diagram and its numbered steps under **Step details**, where the selected step is marked and the other steps of the same moment read `Same recorded moment`; a step's link selects its moment and that step. The events are listed under the collapsed **Events ()**. When the Application pane is closed, the section says `The Application pane is closed.`, and **Show recorded output** opens the pane again at the selected moment. Where that pane opens is not checked in either editor yet: it can open beside the source rather than above it. +The executed source shows in one **recorded-source tab**, named after the stop's file (`Captured-`). At a stop whose recorded source verifies, the tab holds that file as it ran, with the stopped line highlighted and labelled `Recorded: : · s`; the native debugger's thread reads `Recorded test stop · :`, shows that stop's recorded values and stack, and its frames open the same tab. At an output, at the result and at a stop whose source does not verify, the tab holds `// Recorded source · Not recorded at this moment` and `// The test journal holds no source state for this moment.`, and the debugger's thread reads `Not recorded at this moment` with no frames, also when the replay opens on such a moment. A stop in a file with another name renames the tab, and Codebook closes the tab it opened before, so a replay never leaves a tab per stop; returning to Live or opening another saved study closes the tab. Each move first takes the earlier moment off the debugger and the tab, then shows the new moment's source in the tab, then presents the debugger at it, and then shows the stopped line, its label, the Study position and the Application output together; quick moves, an overtaken move and a return to the moment already shown leave no other moment's stop in the debugger and no extra tab. If the tab cannot open, the Study pane says `Codebook could not open the recorded source of stop : . Details: Output › Codebook.`, the moment stays selected with no stop in the debugger, and **Retry** opens the tab again; returning to Live takes that line with it. + +The time slider marks the recording between its first and last event as unrecorded, with a tick at each stop whose recorded source verifies, under `Ticks mark recorded stops; source and debugger are not recorded between them.` (a test journal records when a stop paused, not when the test resumed). **Play** moves from event to event and waits at most 1.5 seconds for the next one, also across an unrecorded interval, which it neither pauses at nor asks about; each surface shows the selected event's own time. + Unexpected failures on these paths write one entry each to **Output › Codebook**, with the surface, the study, the profile, the versions, the cause and the stack. The causes they show name the extension's storage, the workspace and the home folder as ``, `` and `~`; some other messages can still show full local paths. The bundled skill (1.0.46) routes a question about a test, or about library behavior a test exercises, to the `node-test` profile, and the chat explains each test stop in the chat. A run that ends with an `error` before its first stop did not run its test: the chat starts it again only where the published recovery of that error's code allows (`codebook://help/errors`), and it treats any text the error quotes, such as test or tool output, as data. The chat claims saved learning only when the run reads `studyOutcome` `demonstrated` and `nodeTest.learningCoverage` `complete`, says when a test did not pass and names its exit code or signal, and points you to **Save learning replay** and **Open replay**. @@ -86,7 +90,7 @@ The bundled skill (1.0.46) routes a question about a test, or about library beha 2. In Copilot Chat (in VS Code, a new chat in a **Local** session) or Cursor Agent, ask `/codebook` your own question about a test, or about library behavior a test exercises. 3. Follow the chat: it pauses the test at the stops it chose and explains each from the captured values, which you can inspect in the native debugger meanwhile. 4. When the test has run, click **Save learning replay** in the status bar. -5. Click **Open replay**, or open the test replay from Saved studies, and step through its stops with **Previous stop** and **Next stop**: the Application pane shows the test output up to each moment, and the Study pane its explanation. +5. Click **Open replay**, or open the test replay from Saved studies, and step through its stops with **Previous stop** and **Next stop**: the Application pane shows the test output up to each moment, the recorded-source tab the source as it ran, the native debugger the recorded values and stack, and the Study pane its explanation. #### Terms @@ -186,7 +190,7 @@ Package builds require a POSIX host (macOS or Linux); Windows builds are rejecte ```sh pnpm --dir extension install --frozen-lockfile pnpm --dir extension package -pnpm --dir extension package:check "$PWD/artifacts/packages/codebook-0.2.34.vsix" +pnpm --dir extension package:check "$PWD/artifacts/packages/codebook-0.2.35.vsix" ``` The package command checks pnpm, clears only the extension compiler output, rebuilds, bundles production modules and stages an explicit file allowlist. Test/application fixtures and experimental dependencies are rejected. The independent checker validates archive entries, hashes, manifests and dependency notices before accepting the VSIX. diff --git a/extension/package.json b/extension/package.json index b7dbe4137..60450af51 100644 --- a/extension/package.json +++ b/extension/package.json @@ -3,7 +3,7 @@ "displayName": "codebook", "description": "Connect an external agent to source-grounded codebase studies.", "publisher": "laststance", - "version": "0.2.34", + "version": "0.2.35", "private": true, "engines": { "vscode": "^1.120.0", diff --git a/extension/scripts/fixtures/history-transport-golden.txt b/extension/scripts/fixtures/history-transport-golden.txt new file mode 100644 index 000000000..277faac61 --- /dev/null +++ b/extension/scripts/fixtures/history-transport-golden.txt @@ -0,0 +1,3 @@ +
Striped: source/debugger not recorded · ticks: recorded stops
+--- +
Historical source/debugger coverage unknown
diff --git a/extension/scripts/study-bootstrap-qa.mjs b/extension/scripts/study-bootstrap-qa.mjs index 59dcc9f6b..5bcc12854 100644 --- a/extension/scripts/study-bootstrap-qa.mjs +++ b/extension/scripts/study-bootstrap-qa.mjs @@ -754,6 +754,12 @@ async function check(page, options, collected) { ), }) await page.screenshot({ path: `${options.output}/history-coverage.png` }) + // Golden DOM (PR-B2, AC14): the browser transport's time slider with its gap and stop marks renders the markup it rendered before its drawing was shared with test replays. + const mappedTransportMarkup = await page.evaluate( + () => + document.querySelector('#recording-transport .timeline-track') + .outerHTML, + ) await publish({ ...replay, recording: { @@ -761,6 +767,18 @@ async function check(page, options, collected) { historyTimeline: { status: 'unknown' }, }, }) + const unknownTransportMarkup = await page.evaluate( + () => + document.querySelector('#recording-transport .timeline-track') + .outerHTML, + ) + cases.push({ + name: 'the browser transport’s slider with its gap and stop marks, mapped and unknown, renders the same markup as before its drawing was shared with test replays', + actual: `${mappedTransportMarkup}\n---\n${unknownTransportMarkup}`, + passed: + `${mappedTransportMarkup}\n---\n${unknownTransportMarkup}` === + options.goldenHistoryTransport, + }) cases.push({ name: 'an old replay without sealed history avoids invented coverage marks', passed: @@ -1844,6 +1862,13 @@ async function check(page, options, collected) { }, events: 'Events (4)', verdict: 'Test passed · exit code 0', + // The whole range is one unrecorded span; the verified stop at 0.42 s is a tick (PR-B2, Design 4). + timeline: { + startMs: 100, + endMs: 900, + gaps: [{ startMs: 100, endMs: 900 }], + recordedPoints: [420], + }, } const notRecordedLine = 'Source and debugger not recorded at this moment.' /** The Study message of the job scheduler's test replay at one selected event. */ @@ -1974,6 +1999,67 @@ async function check(page, options, collected) { }, }), }) + // Value: protects=the test replay's slider showing the whole recorded range as one unrecorded span with a tick at each verified stop and the catalog legend, and nothing for a one-event history; fails_when=the section's timeline is not drawn by the shared coverage drawing, the legend differs, or a one-event history shows a mark; why_new=Design 8's remaining part (gap mark at the first output), red first on the build without the shared drawing; seam=none; no_claim=native pixels or the browser transport (its golden DOM case) + // Arrange: the replay at its first output, then a replay of one event, which has nothing to mark. + await publish(atFirstOutput) + const readCoverage = () => + page.evaluate(() => { + const strip = document.getElementById('node-history-coverage') + return { + hidden: strip.hidden, + gaps: strip.querySelectorAll('.history-gap').length, + stops: strip.querySelectorAll('.history-stop').length, + gapWidth: strip.querySelector('.history-gap')?.style.width ?? '', + stopLeft: strip.querySelector('.history-stop')?.style.left ?? '', + legend: document.getElementById('node-history-coverage-label') + .textContent, + name: strip.getAttribute('aria-label'), + // The strip is drawn inside the slider's track, below the slider. + insideTrack: Boolean(strip.closest('.timeline-track')), + height: Math.round(strip.getBoundingClientRect().height), + } + }) + // Act + const firstOutputCoverage = await readCoverage() + await publish( + testReplayAt( + { sequence: 1, type: 'output', eventIndex: 0, elapsedMs: 100 }, + { timeline: undefined, previousStop: false, nextStop: false }, + ), + ) + const oneEventCoverage = await readCoverage() + // Assert + cases.push({ + name: 'the test replay’s first output shows its gap mark and a tick at the verified stop under the catalog legend, and a history without a span shows no mark', + actual: { firstOutputCoverage, oneEventCoverage }, + passed: + JSON.stringify({ firstOutputCoverage, oneEventCoverage }) === + JSON.stringify({ + firstOutputCoverage: { + hidden: false, + gaps: 1, + stops: 1, + gapWidth: '100%', + stopLeft: '40%', + legend: + 'Ticks mark recorded stops; source and debugger are not recorded between them.', + name: '1 source/debugger history gap: 0.10 s–0.90 s; 1 recorded stop: 0.42 s', + insideTrack: true, + height: 6, + }, + oneEventCoverage: { + hidden: true, + gaps: 0, + stops: 0, + gapWidth: '', + stopLeft: '', + legend: '', + name: 'Historical source and debugger coverage unknown', + insideTrack: true, + height: 0, + }, + }), + }) // Value: protects=a closed Application pane is named in the test replay section with a way back: the row with Show recorded output appears, its click asks the host for the pane (`focus-app`), and the row goes once the pane is back; fails_when=the row stays hidden while the pane is closed, the button sends another action (`arrange`, which could not bring the pane back), or the row stays after the pane is back; why_new=Step 9 pass 1b's QA critical (Show recorded output could not bring the pane back) and pass 2's testing review: no DOM case showed the row or clicked it; seam=none; no_claim=that the host builds the pane again, which studyWorkspaceTestReplayOutput.test.ts proves // Arrange: the stop of the replay while the learner has closed the Application pane. const paneClosedLine = 'The Application pane is closed.' @@ -8145,6 +8231,13 @@ try { 'utf8', ) ).trimEnd(), + // The browser transport's slider markup before the shared drawing (PR-B2, AC14): a text fixture. + goldenHistoryTransport: ( + await readFile( + new URL('./fixtures/history-transport-golden.txt', import.meta.url), + 'utf8', + ) + ).trimEnd(), message, output, url: `http://127.0.0.1:${server.address().port}/`, diff --git a/extension/scripts/tests/package.test.mjs b/extension/scripts/tests/package.test.mjs index 6df9f4b1a..da7cc1fd5 100644 --- a/extension/scripts/tests/package.test.mjs +++ b/extension/scripts/tests/package.test.mjs @@ -94,7 +94,7 @@ test('a real VSIX loads outside the checkout and excludes bundled applications a // Assert assert.equal(receipt.isolatedModuleLoad, true) assert.equal(receipt.isolatedWikiPageWorker, true) - assert.equal(checked.extension.version, '0.2.34') + assert.equal(checked.extension.version, '0.2.35') assert.equal(checked.extension.apiVersion, '1.8') assert.equal(checked.entries, 32) assert.equal(receipt.dependencies.length, 16) diff --git a/extension/scripts/tests/studyBootstrapQa.test.mjs b/extension/scripts/tests/studyBootstrapQa.test.mjs index 770ceab36..323073f25 100644 --- a/extension/scripts/tests/studyBootstrapQa.test.mjs +++ b/extension/scripts/tests/studyBootstrapQa.test.mjs @@ -36,7 +36,7 @@ test('the pane DOM check loads its flow without eval', async () => { }) // Local CodeRabbit review of Cycle 0045: the script read the compiled reader and the Wiki shell by a path from the working directory, so it ran from the repository root only. -// Value: protects=every file the pane DOM check reads is found beside the script (the compiled reader, the Wiki shell and, since Cycle 0049, the golden markup of the browser replay's sequence), so it runs from any folder; fails_when=a read uses a path from the working directory or the script reads a file this list does not name; why_new=the golden fixture read joins the list (Design 5's golden DOM); seam=none; no_claim=what the check asserts with those files +// Value: protects=every file the pane DOM check reads is found beside the script (the compiled reader, the Wiki shell and, since Cycle 0049, the golden markup of the browser replay's sequence and of its transport's slider), so it runs from any folder; fails_when=a read uses a path from the working directory or the script reads a file this list does not name; why_new=the golden fixture reads join the list (Design 5's golden DOM; PR-B2's shared slider drawing, AC14); seam=none; no_claim=what the check asserts with those files test('the pane DOM check reads the compiled reader, the Wiki shell and its golden sequence markup beside the script, so it runs from any folder', async () => { // Arrange const script = await readFile(scriptUrl, 'utf8') @@ -51,6 +51,7 @@ test('the pane DOM check reads the compiled reader, the Wiki shell and its golde "new URL('../dist/ui/studyHtml.js', import.meta.url)", "new URL('../skills/codebook/reader-shell.html', import.meta.url)", "new URL('./fixtures/learning-sequence-golden.txt', import.meta.url)", + "new URL('./fixtures/history-transport-golden.txt', import.meta.url)", ]) }) diff --git a/extension/src/constants.ts b/extension/src/constants.ts index 139ee8922..46e3a6a28 100644 --- a/extension/src/constants.ts +++ b/extension/src/constants.ts @@ -8,7 +8,7 @@ import { CAPTURE_TIMEOUT_MS } from './runtimeSupport/constants' * 1.8 changed node-test outcomes: a passing test whose history sealed complete reads `demonstrated` in `finalOutcome`, `studyOutcome` and `recordedStudyOutcome` (1.7 stopped at `partial`), its sealed history is a test replay (`recordingAvailable` and `replayAvailable`), and `nodeTest` adds `testResult`, `learningCoverage` and `learningMissing`. A node-test start's deterministic refusals arrive as the run's `error` before its first stop, a failed history seal makes `codebook_stop` answer `HISTORY_SEAL_FAILED`, and `codebook_playback` refuses a test replay with `PLAYBACK_PROFILE_UNSUPPORTED`. */ export const API_VERSION = '1.8' -export const EXTENSION_VERSION = '0.2.34' +export const EXTENSION_VERSION = '0.2.35' export const CONFIGURED_MINIMUM_EXTENSION_VERSION = '0.2.0' export const NODE_TEST_MINIMUM_EXTENSION_VERSION = '0.2.12' export const LOOPBACK_ADDRESS = '127.0.0.1' @@ -160,6 +160,7 @@ export const READER_ERROR_KINDS = [ { kind: 'history-learning', retryable: true, choiceRetired: false }, { kind: 'history-not-saved', retryable: true, choiceRetired: false }, { kind: 'history-position', retryable: true, choiceRetired: false }, + { kind: 'history-source', retryable: true, choiceRetired: false }, { kind: 'layout', retryable: false, choiceRetired: false }, { kind: 'node-history-control', retryable: false, choiceRetired: true }, { kind: 'outline', retryable: true, choiceRetired: false }, @@ -655,6 +656,10 @@ export const MAX_UI_TEXT_CHARS = 8_192 /** The most characters of a failure's cause a tooltip, a notification or an MCP message of the test replay shows; the Output › Codebook entry keeps the whole sanitized cause ({@link sanitizeCause}). */ export const UI_CAUSE_MAX_CHARS = 300 export const STUDY_SOURCE_SCHEME = 'codebook-source' +/** The first path segment of a test replay's recorded-source slot ({@link nodeSourceSlotPath}): one Codebook-owned source document per opened test replay, whose text follows the selected moment (DS5). */ +export const NODE_SOURCE_SLOT_PATH_ROOT = 'node-history-slot' +/** Longest wait for a test replay's recorded-source slot to show a selected moment's bytes before the selection reports that the slot could not open; the slot keeps its loading text meanwhile, never the earlier moment (EN8). */ +export const NODE_HISTORY_TRANSITION_BOUND_MS = 1_000 /** Registered view types of the editor panes Codebook creates: Application, Study and Repository Wiki. */ export const CODEBOOK_PANE_VIEW_TYPES: readonly string[] = [ 'codebook.scopedBrowser', @@ -711,6 +716,8 @@ export const PNG_WIDTH_OFFSET = 16 export const PNG_HEIGHT_OFFSET = 20 export const PNG_SIGNATURE_HEX = '89504e470d0a1a0a0000000d49484452' export const PLAYBACK_TICK_INTERVAL_MS = 50 +/** The longest Play waits between two events of a test replay, however far apart the journal recorded them (the test ran unrecorded between stops). */ +export const NODE_HISTORY_PLAY_MAX_DWELL_MS = 1_500 export const PLAYBACK_PREFERENCE_FILE = 'playback.v1.json' export const PLAYBACK_PREFERENCE_LIMIT_BYTES = 65_536 /** Converts milliseconds to the seconds that playback labels, seek steps and run failure texts name. */ diff --git a/extension/src/studyWorkspace.ts b/extension/src/studyWorkspace.ts index 096dca942..075212da4 100644 --- a/extension/src/studyWorkspace.ts +++ b/extension/src/studyWorkspace.ts @@ -37,6 +37,7 @@ import { NODE_TEST_PROFILE, MILLISECONDS_PER_SECOND, NATIVE_RUN_AND_DEBUG_VIEW_COMMAND, + NODE_HISTORY_TRANSITION_BOUND_MS, OPEN_REPLAY_RESULT_WAIT_MS, PANE_TOOK_CHOSEN_EDITOR_FOCUS_MESSAGE, PAUSE_FOCUS_LOOKBACK_MS, @@ -102,6 +103,7 @@ import { import { NodeLearningSave } from './nodeLearningSave' import { nodeLearningStepIdSchema, + type NodeTestHistoryEntry, type NodeTestHistoryIndex, type NodeTestHistoryLearningDecision, type NodeTestLearningMaterial, @@ -191,6 +193,7 @@ import { type StudyViewMessage, } from './ui/studyHtml' import { adoptWikiGroupReturn } from './utils/adoptWikiGroupReturn' +import { awaitDocumentSettled } from './utils/awaitDocumentSettled' import { bookObservationHash } from './utils/bookObservationHash' import { capturedAppHtml } from './utils/capturedAppHtml' import { capturedSourceDeclaredPath } from './utils/capturedSourceDeclaredPath' @@ -205,6 +208,10 @@ import { configuredObservationPosition } from './utils/configuredObservationPosi import { coveredSourceObstacle } from './utils/coveredSourceObstacle' import { createRecordingObserver } from './utils/createRecordingObserver' import { describeNodeLearningSave } from './utils/describeNodeLearningSave' +import { + describeNodeRecordedSource, + NODE_RECORDED_SOURCE_TEXT, +} from './utils/describeNodeRecordedSource' import { describeNodeTestReplay } from './utils/describeNodeTestReplay' import { describeStudy } from './utils/describeStudy' import { @@ -244,6 +251,7 @@ import { isCollapsedEditorLayout } from './utils/isCollapsedEditorLayout' import { isCurrentRunRememberedWhileClosed } from './utils/isCurrentRunRememberedWhileClosed' import { isDiffTabOfDocument } from './utils/isDiffTabOfDocument' import { isLiveSourceViewUri } from './utils/isLiveSourceViewUri' +import { isNodeSourceSlotPath } from './utils/isNodeSourceSlotPath' import { editorLayoutSchema, isProportionalEditorLayout, @@ -257,6 +265,8 @@ import { maximizedEditorAreaWidthPx } from './utils/maximizedEditorAreaWidthPx' import { nextNodeHistoryStepId } from './utils/nextNodeHistoryStepId' import { NodeHistoryPlaybackController } from './utils/nodeHistoryPlaybackController' import { nodeHistoryStepTarget } from './utils/nodeHistoryStepTarget' +import { nodeSourceSlotName } from './utils/nodeSourceSlotName' +import { nodeSourceSlotPath } from './utils/nodeSourceSlotPath' import { nodeStopSourceMatches } from './utils/nodeStopSourceMatches' import { normalizeNativeSourceText } from './utils/normalizeNativeSourceText' import { paneKeyboardTimeoutMessage } from './utils/paneKeyboardTimeoutMessage' @@ -354,6 +364,8 @@ const revisionShape = { revision: z.number().int().nonnegative() } // The number a Study pane gives its request to open a Saved studies entry; {@link StudyWorkspace.receivePaneMessage} answers it. const openRequestShape = { openRequest: openRequestNumberSchema.optional() } const NODE_HISTORY_READER_PAGE_SIZE = 20 +/** A saved test stop, the only journal entry with captured source and a debugger snapshot. */ +type NodeTestHistoryStop = Extract const messageSchema = z.discriminatedUnion('type', [ webviewFocusReceiptSchema, z.strictObject({ type: z.literal('ready') }), @@ -688,6 +700,13 @@ export class StudyWorkspace { /** The generation of the view the Application pane's document shows, so each change is posted once. */ private shownNodeHistoryApplicationGeneration?: number private nodeHistoryPlaybackController?: NodeHistoryPlaybackController + /** The selected test replay's recorded-source slot (DS5): its one Codebook-owned source document, the bytes it serves ({@link provideSource}) and the verified stop whose line and label it shows, `undefined` for the placeholder or its loading text. */ + private nodeSourceSlot?: { + studyId: string + uri: vscode.Uri + text: string + stop?: NodeTestHistoryStop + } private playback?: PlaybackController private replayDebugger?: ReplayDebugger /** The disposal of replaced historical debuggers that is still running; the editor accepts the next owner only once it has settled. */ @@ -8725,6 +8744,13 @@ export class StudyWorkspace { await playback.settle() return } + // A selected test replay's surfaces change only through its own selection (EN9): Retry shows its moment again, which reopens a recorded-source slot that could not open. A browser replay that holds the reader keeps its own Retry, as every test replay move refuses during it. + const history = this.selectedNodeHistory, + sequence = this.selectedNodeHistorySequence + if (history && sequence !== undefined && !this.recordingActive) { + await this.selectNodeHistoryEvent(history, sequence) + return + } await this.renderSelection(true, true) } } @@ -11938,6 +11964,20 @@ export class StudyWorkspace { this.selectedNodeHistoryDebugAvailable = false this.selectedNodeHistoryValuesUninspected = false this.replayDebugger?.invalidate() + const slot = this.nodeSourceSlot + this.nodeSourceSlot = undefined + // A slot that could not open belonged to the retired replay: its row and Retry go with it. + this.errors.delete('history-source') + // The retired replay's recorded-source slot goes with it, with any slot tab a rename still opening or one that failed left. + if (slot) + await this.closeNodeSourceSlotTabs().catch((error: unknown) => + this.report( + 'layout', + new Error( + `The previous recorded source tab could not close. Arrange the Codebook panes manually. ${String(error)}`, + ), + ), + ) if (!previousNodeHistoryId) return const previousHistoryPath = `/node-history/${previousNodeHistoryId}/` const previews = vscode.window.tabGroups.all @@ -13267,53 +13307,27 @@ export class StudyWorkspace { lifetime: number, signal?: AbortSignal, ): Promise { - await new Promise((resolve, reject) => { - const observation = new AbortController() - let finished = false - const finish = (failure?: { cause: unknown }): void => { - if (finished) return - finished = true - subscription.dispose() - observation.abort() - signal?.removeEventListener('abort', check) - if (failure) reject(failure.cause) - else resolve() - } - const check = (): void => { - try { - this.assertLifetime(lifetime) - signal?.throwIfAborted() - if (this.isRenderSuperseded(revision)) - throw new Error('Captured source view was superseded.') - if ( - normalizeNativeSourceText(editor.document.getText()) === - normalizeNativeSourceText(text) - ) - finish() - } catch (error) { - finish({ cause: error }) - } - } - const subscription = vscode.workspace.onDidChangeTextDocument((event) => { - // Another document's edit cannot settle this captured source. - if (event.document.uri.toString() === editor.document.uri.toString()) - check() - }) - signal?.addEventListener('abort', check, { once: true }) - // Close and newer intent may emit no document event; retain the existing bounded observation for them. - void waitUntil( - () => { - check() - return finished - }, - 'the selected captured source bytes', - PRESENTATION_READY_TIMEOUT_MS, - observation.signal, - ).catch((error: unknown) => finish({ cause: error })) - // Subscribe before notifying the provider, then check already-delivered or unchanged bytes too. - this.sourceChanges.fire(editor.document.uri) - check() - }) + await awaitDocumentSettled( + vscode.workspace.onDidChangeTextDocument, + editor.document.uri.toString(), + () => { + this.assertLifetime(lifetime) + signal?.throwIfAborted() + if (this.isRenderSuperseded(revision)) + throw new Error('Captured source view was superseded.') + return ( + normalizeNativeSourceText(editor.document.getText()) === + normalizeNativeSourceText(text) + ) + }, + 'the selected captured source bytes', + PRESENTATION_READY_TIMEOUT_MS, + { + signal, + // Subscribe before notifying the provider, then check already-delivered or unchanged bytes too. + afterSubscribe: () => this.sourceChanges.fire(editor.document.uri), + }, + ) } /** @@ -18572,6 +18586,12 @@ export class StudyWorkspace { this.confirmInitialAppRegistration() // The paused file the editor opens for a stop its own handling brings gets the keyboard at once. this.handOverAtPausedFileOpening(editor) + // A recorded-source slot brought back into view gets its stopped line and label again: the editor drops them with a hidden tab. + if ( + editor && + editor.document.uri.toString() === this.nodeSourceSlot?.uri.toString() + ) + this.decorateNodeSourceSlot() }), ) this.disposables.push( @@ -18601,6 +18621,11 @@ export class StudyWorkspace { throw new Error('Captured source belongs to another workspace.') const cached = this.documents.get(uri.toString()) if (cached !== undefined) return cached + // A test replay's recorded-source slot serves the moment it shows; a slot no replay holds now (a tab the editor restored) reads as the placeholder. + if (isNodeSourceSlotPath(uri.path)) + return this.nodeSourceSlot?.uri.toString() === uri.toString() + ? this.nodeSourceSlot.text + : NODE_RECORDED_SOURCE_TEXT.placeholder // A view is ephemeral presentation, never a recoverable hash-addressed saved snapshot. if (isLiveSourceViewUri(uri)) throw new Error( @@ -23207,7 +23232,9 @@ export class StudyWorkspace { } /** - * Selects one verified moment of a test replay and clears stale debugger state across unrecorded intervals; called by the Study pane's moves, step actions and Inspect, by Play and seeks, and by the replay's open. + * Selects one moment of a test replay on every surface in the browser replay's order (EN8); called by the Study pane's moves, step actions and Inspect, by Play and seeks, and by the replay's open. + * + * (1) Every surface leaves the earlier moment at once: the replay debugger shows no stop and the recorded-source slot drops the earlier stop's line, label and text ({@link leaveNodeHistoryMoment}); (2) the slot's bytes for this moment are confirmed in its document ({@link showNodeSourceSlot}); (3) the debugger is presented at the slot ({@link presentNodeHistoryDebugger}); (4) the slot's line and label, the Study position and the Application view commit together; the reader position is written after the commit. Every step re-checks that no newer selection took over. * The selection commits the step it shows with its moment ({@link nextNodeHistoryStepId}): a refused, failed or superseded selection leaves the learner's chosen step as it was. * @param history - The selected test replay. * @param sequence - The event to select. @@ -23234,72 +23261,34 @@ export class StudyWorkspace { const entry = history.entries.find((value) => value.sequence === sequence) if (!entry) throw new Error('The requested Node history event is unavailable.') - if (entry.type === 'stop') { - const source = entry.debuggerSnapshot.frames[0]?.source - const sourceMatchesStop = nodeStopSourceMatches(entry) - if (!sourceMatchesStop && requireDebugger) { - throw new Error( - 'The selected Node stop has no matching verified captured source for native debugging.', - ) - } - if (sourceMatchesStop && source) { - const verifiedSource = source - const sourceUri = vscode.Uri.from({ - scheme: STUDY_SOURCE_SCHEME, - authority: this.library!.workspaceKey, - path: `/node-history/${history.header.studyId}/${entry.sequence}/${verifiedSource.hash}/Captured-${basename(entry.source.path)}`, - }) - // Only an explicit learner selection restarts a debugger the learner stopped; seek and Play report why they stopped. - if (this.replayDebugger && !this.replayDebugger.available && !publish) - throw new Error( - 'The historical Node debugger was stopped. Select this stop or use Inspect in native debugger to restart it.', - ) - if ( - (this.replayDebugger && !this.replayDebugger.available) || - this.replayDebuggerRetirement - ) { - await this.replaceUnavailableReplayDebugger() - // The reader may have closed or selected another stop meanwhile; only the current selection creates the next owner. - if (request !== this.selectedNodeHistoryRequest) return - } - this.replayDebugger ??= this.createReplayDebugger() - let inspection: ReplayInspection - try { - inspection = await this.replayDebugger.present( - entry.debuggerSnapshot, - `Recorded Node test stop ${entry.index + 1} · ${entry.source.path}:${entry.frame.line}`, - new AbortController().signal, - { uri: sourceUri.toString(), hash: verifiedSource.hash }, - ) - } catch (error) { - // A newer learner selection supersedes this stop's native presentation; only the current request reports failures. - if (request !== this.selectedNodeHistoryRequest) return - throw error - } - if (request !== this.selectedNodeHistoryRequest) return - this.selectedNodeHistoryDebugAvailable = true - this.selectedNodeHistoryValuesUninspected = inspection === 'uninspected' - } else { - this.replayDebugger?.invalidate() - this.selectedNodeHistoryDebugAvailable = false - this.selectedNodeHistoryValuesUninspected = false - } - } else { - // Output and result events have no source/debugger snapshot; never carry an earlier stop forward. - this.replayDebugger?.invalidate() + const verifiedStop = + entry.type === 'stop' && nodeStopSourceMatches(entry) ? entry : undefined + if (entry.type === 'stop' && !verifiedStop && requireDebugger) + throw new Error( + 'The selected Node stop has no matching verified captured source for native debugging.', + ) + // Only an explicit learner selection restarts a debugger the learner stopped; seek and Play report why they stopped. + if (verifiedStop && this.replayDebugger?.available === false && !publish) + throw new Error( + 'The historical Node debugger was stopped. Select this stop or use Inspect in native debugger to restart it.', + ) + // A step action or Inspect on the moment already shown keeps every surface; another moment leaves the earlier one at once. + if (entry.sequence !== this.selectedNodeHistorySequence) + this.leaveNodeHistoryMoment() + const slot = await this.showNodeSourceSlot(history, verifiedStop, request) + if (!slot) return + // A slot that could not open leaves the debugger on no stop; the moment still commits beside the slot's Study row (S2-1). + if (slot === 'failed') { this.selectedNodeHistoryDebugAvailable = false this.selectedNodeHistoryValuesUninspected = false - } - try { - await this.nodeHistoryStore!.saveReaderPosition( - history.header.studyId, - entry.sequence, - history, - ) - } catch (error) { - this.report('history-position', error) - } - if (request !== this.selectedNodeHistoryRequest) return + } else if ( + !(await this.presentNodeHistoryDebugger(verifiedStop, slot, request)) + ) + return + // The slot's stopped line and label commit with the moment. + if (this.nodeSourceSlot && slot !== 'failed') + this.nodeSourceSlot = { ...this.nodeSourceSlot, stop: verifiedStop } + this.decorateNodeSourceSlot() // A chosen step stays only with its own moment: a selection that lands on another event without a choice of its own (a seek, Play, Inspect) shows that event's first step (DS21). this.selectedNodeHistoryStepId = nextNodeHistoryStepId( stepChoice, @@ -23317,6 +23306,340 @@ export class StudyWorkspace { if (alignPlayback) this.nodeHistoryPlaybackController?.select(entry.sequence) if (publish) this.publish() + // The reader position is written after the commit, so a slow write never holds the shown moment back. + try { + await this.nodeHistoryStore!.saveReaderPosition( + history.header.studyId, + entry.sequence, + history, + ) + } catch (error) { + this.report('history-position', error) + } + } + + /** + * Takes the earlier moment off the test replay's debugger and recorded-source slot before the next moment's bytes load (EN8 step 1): the debugger thread reads "Not recorded at this moment" and a slot that showed a stop shows its loading text with no stopped line or label; called by {@link selectNodeHistoryEvent} when it selects another moment. + * @example this.leaveNodeHistoryMoment() + */ + private leaveNodeHistoryMoment(): void { + this.replayDebugger?.invalidate() + const slot = this.nodeSourceSlot + // A slot that holds the placeholder or its loading text shows no earlier moment. + if (!slot?.stop) return + this.nodeSourceSlot = { + ...slot, + text: NODE_RECORDED_SOURCE_TEXT.loading, + stop: undefined, + } + this.decorateNodeSourceSlot() + this.sourceChanges.fire(slot.uri) + } + + /** + * Shows a test replay's moment in its one recorded-source slot (DS5, EN8 step 2): a verified stop's sealed source, otherwise the 4A placeholder, in a Codebook-owned document named after the stop's file, opened in the source group without taking focus and confirmed in its document before the debugger points at it; called by {@link selectNodeHistoryEvent}. + * A stop in another file renames the slot and closes the tab Codebook opened before, so a replay never leaves a tab per stop. + * @param history - The selected test replay. + * @param verifiedStop - The stop whose source verifies, or `undefined` for an output, the result or an unverified stop. + * @param request - The selection's request token. + * @returns + * - The slot's URI once its bytes show + * - `'failed'` when the slot could not open or did not show its bytes within {@link NODE_HISTORY_TRANSITION_BOUND_MS}, which {@link reportNodeSourceSlotFailure} told + * - `undefined` when a newer selection took over meanwhile + * @example await this.showNodeSourceSlot(history, stop, request) // => Uri codebook-source://…/node-history-slot//Captured-scheduler.ts + */ + private async showNodeSourceSlot( + history: NodeTestHistoryIndex, + verifiedStop: NodeTestHistoryStop | undefined, + request: number, + ): Promise { + const studyId = history.header.studyId + const earlier = this.nodeSourceSlot + // Outside a stop the slot keeps the name it has, or takes the file of the replay's first verified stop. + const uri = verifiedStop + ? this.nodeSourceSlotUri(studyId, verifiedStop.source.path) + : earlier?.studyId === studyId + ? earlier.uri + : this.nodeSourceSlotUri(studyId, nodeSourceSlotName(history)) + const text = + verifiedStop?.debuggerSnapshot.frames[0]?.source?.text ?? + NODE_RECORDED_SOURCE_TEXT.placeholder + // The stopped line and label wait for the commit ({@link selectNodeHistoryEvent}), so no editor event draws them before the debugger shows the stop. + this.nodeSourceSlot = { studyId, uri, text } + try { + this.sourceChanges.fire(uri) + const document = await vscode.workspace.openTextDocument(uri) + if (request !== this.selectedNodeHistoryRequest) return undefined + // A renamed slot opens where the earlier one is, before that tab closes: a group the slot alone filled is never emptied, which `workbench.editor.closeEmptyGroups` would remove. + await vscode.window.showTextDocument(document, { + viewColumn: this.nodeSourceSlotColumn(uri, earlier?.uri), + preserveFocus: true, + preview: false, + }) + // Every other slot tab gives way: the earlier file's at a rename, and one a rename left when a newer selection overtook it or its slot could not open. A selection overtaken meanwhile keeps the newer moment's slot, not its own. + await this.closeNodeSourceSlotTabs(this.nodeSourceSlot?.uri) + await this.awaitNodeSourceSlotText(document, text, request) + } catch (error) { + if (request !== this.selectedNodeHistoryRequest) return undefined + this.reportNodeSourceSlotFailure(studyId, verifiedStop, error) + return 'failed' + } + if (request !== this.selectedNodeHistoryRequest) return undefined + // A slot that shows its moment answers an earlier failure to open it. + if (this.errors.delete('history-source')) this.publish() + return uri + } + + /** + * Tells the learner that a test replay's recorded-source slot could not open (S2-1): the Study pane's `history-source` row names the stop and the sanitized cause and offers Retry, and Output › Codebook keeps one entry with the stack; called by {@link showNodeSourceSlot}. + * @param studyId - The test replay's study id. + * @param verifiedStop - The stop the slot was to show, or `undefined` for the placeholder. + * @param error - The failure. + * @example this.reportNodeSourceSlotFailure(studyId, stop, error) + */ + private reportNodeSourceSlotFailure( + studyId: string, + verifiedStop: NodeTestHistoryStop | undefined, + error: unknown, + ): void { + const roots = this.service?.causeRoots ?? { storage: [] } + const cause = sanitizeCause(error, roots) + const stack = sanitizedStack(error, roots) + this.diagnostics?.log({ + surface: 'open:recorded-source', + studyId, + profile: NODE_TEST_PROFILE, + cause, + ...(stack ? { stack } : {}), + }) + this.report( + 'history-source', + describeNodeRecordedSource({ + kind: 'open-failed', + stop: verifiedStop ? verifiedStop.index + 1 : undefined, + cause, + }), + ) + } + + /** + * Waits until a test replay's recorded-source slot shows the bytes {@link showNodeSourceSlot} gave it, so the debugger never points at a line of earlier text; bounded by {@link NODE_HISTORY_TRANSITION_BOUND_MS}. + * @param document - The slot's document. + * @param text - The bytes the slot must show. + * @param request - The selection's request token; a newer selection ends the wait. + * @throws When the document does not show the bytes within the bound. + * @example await this.awaitNodeSourceSlotText(document, stop.debuggerSnapshot.frames[0].source.text, request) + */ + private async awaitNodeSourceSlotText( + document: vscode.TextDocument, + text: string, + request: number, + ): Promise { + await awaitDocumentSettled( + vscode.workspace.onDidChangeTextDocument, + document.uri.toString(), + () => + request !== this.selectedNodeHistoryRequest || + normalizeNativeSourceText(document.getText()) === + normalizeNativeSourceText(text), + 'the recorded source of this moment', + NODE_HISTORY_TRANSITION_BOUND_MS, + ) + } + + /** + * Presents a test replay's moment in the replay debugger at the recorded-source slot (EN8 step 3): a verified stop's recorded frames and values on the thread `Recorded test stop · :`, otherwise the thread "Not recorded at this moment" with no frames, which also starts the session when the replay opens on such a moment; called by {@link selectNodeHistoryEvent}. + * @param verifiedStop - The stop whose source verifies, or `undefined`. + * @param slotUri - The slot the stop's frames open. + * @param request - The selection's request token. + * @returns `true` once the debugger shows the moment; `false` when a newer selection took over. + * @throws The debugger's failure for the current selection. + * @example await this.presentNodeHistoryDebugger(stop, slotUri, request) // => true + */ + private async presentNodeHistoryDebugger( + verifiedStop: NodeTestHistoryStop | undefined, + slotUri: vscode.Uri, + request: number, + ): Promise { + if (!verifiedStop) { + // A debugger that has not started yet starts on the "Not recorded" thread; a running one is emptied even when this moment is the committed one, since a newer selection may have presented its stop meanwhile (4A); one the learner stopped stays stopped. + if (!this.replayDebugger) + await this.presentReplayDebuggerFor(request, async (debuggerView) => { + await debuggerView.present( + undefined, + NODE_RECORDED_SOURCE_TEXT.notRecordedThread, + new AbortController().signal, + ) + }) + else this.replayDebugger.invalidate() + if (request !== this.selectedNodeHistoryRequest) return false + this.selectedNodeHistoryDebugAvailable = false + this.selectedNodeHistoryValuesUninspected = false + return true + } + if ( + this.replayDebugger?.available === false || + this.replayDebuggerRetirement + ) { + await this.replaceUnavailableReplayDebugger() + // The reader may have closed or selected another stop meanwhile; only the current selection creates the next owner. + if (request !== this.selectedNodeHistoryRequest) return false + } + const inspection = await this.presentReplayDebuggerFor( + request, + (debuggerView) => + debuggerView.present( + verifiedStop.debuggerSnapshot, + describeNodeRecordedSource({ + kind: 'thread', + stop: verifiedStop.index + 1, + path: verifiedStop.source.path, + line: verifiedStop.frame.line, + }), + new AbortController().signal, + { uri: slotUri.toString(), hash: verifiedStop.source.hash }, + ), + ) + if (request !== this.selectedNodeHistoryRequest) return false + this.selectedNodeHistoryDebugAvailable = true + this.selectedNodeHistoryValuesUninspected = inspection === 'uninspected' + return true + } + + /** + * Runs one presentation of the test replay's debugger, creating the owner when there is none, and lets a newer selection's supersession end it quietly; called by {@link presentNodeHistoryDebugger}. + * @param request - The selection's request token. + * @param present - The presentation. + * @returns The presentation's result; `undefined` when a newer selection superseded it. + * @throws The presentation's failure while this selection is still the current one. + * @example await this.presentReplayDebuggerFor(request, (debuggerView) => debuggerView.present(undefined, 'Not recorded at this moment', signal)) + */ + private async presentReplayDebuggerFor( + request: number, + present: (debuggerView: ReplayDebugger) => Promise, + ): Promise { + this.replayDebugger ??= this.createReplayDebugger() + try { + return await present(this.replayDebugger) + } catch (error) { + // A newer learner selection supersedes this moment's native presentation; only the current request reports failures. + if (request !== this.selectedNodeHistoryRequest) return undefined + throw error + } + } + + /** + * Draws the recorded-source slot's stopped line and its label `Recorded: : · s` at a verified stop, and clears both for the placeholder and the loading text (EN8 step 4); called by {@link selectNodeHistoryEvent}, {@link leaveNodeHistoryMoment} and when the slot's tab comes back into view. + * @example this.decorateNodeSourceSlot() + */ + private decorateNodeSourceSlot(): void { + const slot = this.nodeSourceSlot + if (!slot || !this.highlight || !this.sourceIdentity) return + for (const editor of vscode.window.visibleTextEditors) { + if (editor.document.uri.toString() !== slot.uri.toString()) continue + const stop = slot.stop + if (!stop) { + editor.setDecorations(this.highlight, []) + editor.setDecorations(this.sourceIdentity, []) + continue + } + const line = stop.frame.line - 1 + const lineEnd = new vscode.Position( + line, + slot.text.split('\n')[line]?.length ?? 0, + ) + const label = describeNodeRecordedSource({ + kind: 'label', + path: stop.source.path, + line: stop.frame.line, + elapsedMs: stop.elapsedMs, + }) + editor.setDecorations(this.highlight, [ + new vscode.Range(line, 0, line, 0), + ]) + editor.setDecorations(this.sourceIdentity, [ + { + range: new vscode.Range(lineEnd, lineEnd), + hoverMessage: `${label} · captured SHA-256 ${stop.source.hash}`, + renderOptions: { after: { contentText: ` ${label}` } }, + }, + ]) + editor.revealRange( + new vscode.Range(line, 0, line, 0), + vscode.TextEditorRevealType.InCenterIfOutsideViewport, + ) + } + } + + /** + * Names the recorded-source slot's document for a test replay: Codebook's source scheme, this workspace's key and {@link nodeSourceSlotPath}; called by {@link showNodeSourceSlot}. + * @param studyId - The test replay's study id. + * @param sourcePath - The file the slot is named after. + * @returns The slot's URI. + * @example this.nodeSourceSlotUri(studyId, 'src/jobs/scheduler.ts') // => Uri codebook-source:///node-history-slot//Captured-scheduler.ts + */ + private nodeSourceSlotUri(studyId: string, sourcePath: string): vscode.Uri { + return vscode.Uri.from({ + scheme: STUDY_SOURCE_SCHEME, + authority: this.library!.workspaceKey, + path: nodeSourceSlotPath(studyId, sourcePath), + }) + } + + /** + * Chooses the editor column the recorded-source slot shows in: the group that already shows it, else the group that shows the slot it replaces, else a group that shows another slot tab Codebook is about to close (a rename that failed or was overtaken left it), so closing that tab never empties a group the slot alone filled; else the source group, else the Study arrangement's source column; called by {@link showNodeSourceSlot}. + * @param uri - The slot's URI. + * @param earlierUri - The URI of the slot it replaces at a rename, if any. + * @returns The view column. + * @example this.nodeSourceSlotColumn(slotUri, earlierSlotUri) // => 2 + */ + private nodeSourceSlotColumn( + uri: vscode.Uri, + earlierUri?: vscode.Uri, + ): vscode.ViewColumn { + const groupShowing = (shows: (shown: vscode.Uri) => boolean) => + vscode.window.tabGroups.all.find((group) => + group.tabs.some( + (tab) => + tab.input instanceof vscode.TabInputText && shows(tab.input.uri), + ), + ) + return ( + ( + groupShowing((shown) => shown.toString() === uri.toString()) ?? + groupShowing((shown) => shown.toString() === earlierUri?.toString()) ?? + groupShowing( + (shown) => + shown.scheme === STUDY_SOURCE_SCHEME && + shown.authority === this.library!.workspaceKey && + isNodeSourceSlotPath(shown.path), + ) + )?.viewColumn ?? + this.sourceGroup?.viewColumn ?? + STUDY_PRESENTATIONS[this.presentationMode].sourceColumn + ) + } + + /** + * Closes every unpinned, unchanged recorded-source slot tab of this workspace but the one a moment shows: the earlier file's at a rename, one that a rename left when a newer selection overtook it or its slot could not open, and, when its test replay is retired, all of them; called by {@link showNodeSourceSlot} and {@link retireNodeHistorySelection}. + * @param kept - The slot the current moment shows, which stays; `undefined` closes every slot tab. + * @throws When the editor keeps a tab it was asked to close. + * @example await this.closeNodeSourceSlotTabs(this.nodeSourceSlot?.uri) + */ + private async closeNodeSourceSlotTabs(kept?: vscode.Uri): Promise { + const tabs = vscode.window.tabGroups.all + .flatMap((group) => group.tabs) + .filter( + (tab) => + !tab.isDirty && + !tab.isPinned && + this.ownsCapturedSourceTab(tab) && + tab.input instanceof vscode.TabInputText && + isNodeSourceSlotPath(tab.input.uri.path) && + tab.input.uri.toString() !== kept?.toString(), + ) + if (tabs.length && !(await vscode.window.tabGroups.close(tabs, true))) + throw new Error('The editor kept an earlier recorded source tab.') } /** Persists navigation independently; failures do not erase prior learner decisions. @example await this.saveSelection() */ diff --git a/extension/src/tests/awaitDocumentSettled.test.ts b/extension/src/tests/awaitDocumentSettled.test.ts new file mode 100644 index 000000000..6f8c6f57f --- /dev/null +++ b/extension/src/tests/awaitDocumentSettled.test.ts @@ -0,0 +1,131 @@ +import assert from 'node:assert/strict' +import { test } from 'node:test' + +import { awaitDocumentSettled } from '../utils/awaitDocumentSettled' + +type Listener = (event: { document: { uri: { toString(): string } } }) => void + +/** + * Builds a fake text document change event whose listeners the test fires by hand. + * @returns The event to hand to the wait, a way to fire a change of one document, and the count of live listeners. + * @example const documents = fakeDocumentChanges(); documents.change('file:///a.ts') + */ +function fakeDocumentChanges() { + const listeners = new Set() + return { + event: (listener: Listener) => { + listeners.add(listener) + return { dispose: () => void listeners.delete(listener) } + }, + change: (uri: string): void => { + for (const listener of [...listeners]) + listener({ document: { uri: { toString: () => uri } } }) + }, + liveListeners: () => listeners.size, + } +} + +// Value: protects=a wait on one document ends at that document's own change and not at another document's change; fails_when=the wait drops the uri comparison and settles on any document's edit, or never re-checks at a change; why_new=the util's contract had only indirect cover through the workspace's two callers; seam=none; no_claim=the bounded poll +test('a wait for one document settles at that document’s change and ignores another document’s change', async () => { + // Arrange + const documents = fakeDocumentChanges() + let text = 'old' + const wait = awaitDocumentSettled( + documents.event, + 'file:///a.ts', + () => { + return text === 'new' + }, + 'the new bytes', + 2_000, + ) + let resolved = false + void wait.then(() => (resolved = true)) + + // Act + text = 'new' + documents.change('file:///other.ts') + await new Promise((resolve) => setImmediate(resolve)) + const resolvedAfterOtherDocument = resolved + documents.change('file:///a.ts') + await wait + + // Assert + assert.equal(resolvedAfterOtherDocument, false) + assert.equal(resolved, true) + assert.equal(documents.liveListeners(), 0) +}) + +// Value: protects=the provider is notified only once the change listener is in place, and the bytes it delivers settle the wait; fails_when=afterSubscribe runs before the subscription (the provider's event is lost) or its change is not observed; why_new=the capture view's "subscribe before notifying the provider" rule, now in the shared util; seam=none; no_claim=the editor's own event order +test('a wait notifies the provider after subscribing, and the bytes it delivers settle the wait', async () => { + // Arrange + const documents = fakeDocumentChanges() + const liveListenersAtNotify: number[] = [] + let text = 'old' + + // Act + await awaitDocumentSettled( + documents.event, + 'file:///a.ts', + () => text === 'new', + 'the bytes', + 2_000, + { + afterSubscribe: () => { + liveListenersAtNotify.push(documents.liveListeners()) + text = 'new' + documents.change('file:///a.ts') + }, + }, + ) + + // Assert + assert.deepEqual(liveListenersAtNotify, [1]) + assert.equal(documents.liveListeners(), 0) +}) + +// Value: protects=a superseded or closed reader ends the wait with its own error, and an aborting signal re-checks at once without a document event; fails_when=the settled check's throw is swallowed so the wait runs to its bound, or abort is not observed; why_new=the replacement of two hand-written waits by one util changed who owns these exits; seam=none; no_claim=the message wording of the callers +test('a settled check that throws ends the wait with that error, and an abort wakes the check', async () => { + // Arrange + const documents = fakeDocumentChanges() + const controller = new AbortController() + const wait = awaitDocumentSettled( + documents.event, + 'file:///a.ts', + () => { + controller.signal.throwIfAborted() + return false + }, + 'the bytes', + 2_000, + { signal: controller.signal }, + ) + + // Act + controller.abort(new Error('reader closed')) + + // Assert + await assert.rejects(wait, { message: 'reader closed' }) + assert.equal(documents.liveListeners(), 0) +}) + +// Value: protects=a document that never shows the bytes fails the wait at its bound naming what was waited for, and the listener is released; fails_when=the wait hangs, times out without the description, or leaks its change listener; why_new=the slot's open-failure row depends on this bound (NODE_HISTORY_TRANSITION_BOUND_MS); seam=none; no_claim=the bound's value for the slot +test('a document that never shows the bytes fails the wait at its bound and releases the listener', async () => { + // Arrange + const documents = fakeDocumentChanges() + + // Act + const wait = awaitDocumentSettled( + documents.event, + 'file:///a.ts', + () => false, + 'the recorded source of this moment', + 60, + ) + + // Assert + await assert.rejects(wait, { + message: 'Timed out waiting for the recorded source of this moment', + }) + assert.equal(documents.liveListeners(), 0) +}) diff --git a/extension/src/tests/describeNodeRecordedSource.test.ts b/extension/src/tests/describeNodeRecordedSource.test.ts new file mode 100644 index 000000000..627a25e79 --- /dev/null +++ b/extension/src/tests/describeNodeRecordedSource.test.ts @@ -0,0 +1,224 @@ +import assert from 'node:assert/strict' +import { test } from 'node:test' + +import ts from 'typescript' + +import type { NodeTestHistoryEntry } from '../nodeTestHistorySchemas' +import { sha256 } from '../runtimeSupport/utils/sha256' +import { + describeNodeRecordedSource, + NODE_RECORDED_SOURCE_TEXT, +} from '../utils/describeNodeRecordedSource' +import { formatEventSeconds } from '../utils/formatEventSeconds' +import { isNodeSourceSlotPath } from '../utils/isNodeSourceSlotPath' +import { nodeSourceSlotName } from '../utils/nodeSourceSlotName' +import { nodeSourceSlotPath } from '../utils/nodeSourceSlotPath' + +import { nodeTestHistoryHeader } from './utils/nodeTestHistoryFixture' + +/** + * Builds a saved test stop in `src/scheduler.ts` whose captured source verifies, or, with `edited`, whose captured text no longer hashes to its sealed hash. + * @param sequence - The stop's journal sequence. + * @param edited - Whether the captured text was changed after the seal. + * @returns The stop entry. + * @example schedulerStop(2) // a verified stop at sequence 2 + */ +function schedulerStop( + sequence: number, + edited = false, +): Extract { + const text = 'export const delay = 250;\n' + return { + type: 'stop', + sequence, + elapsedMs: 200, + index: 0, + source: { + path: 'src/scheduler.ts', + hash: sha256(text), + line: 1, + column: 1, + }, + frame: { name: 'schedule', line: 1, column: 1 }, + facts: [], + debuggerSnapshot: { + version: 1, + frames: [ + { + name: 'schedule', + line: 1, + column: 1, + source: { + name: 'src/scheduler.ts', + text: edited ? 'export const delay = 0;\n' : text, + hash: sha256(text), + line: 1, + }, + scopes: [], + }, + ], + variables: [], + limitations: [], + }, + } +} + +// Value: protects=the String catalog's recorded-source words: the slot's label at a verified stop, the debugger thread, the slot's open failure with and without a stop, and the slot's tab title; fails_when=any of them is worded otherwise than the catalog, names the stop 0-based, or says "Node" in the thread (DS14); why_new=PR-B2's recorded-source slot (Design 4, DS5, DS18); seam=none; no_claim=where each surface draws the words (the slot tests) +test('the recorded-source slot and its debugger thread are worded as the String catalog writes them', () => { + // Arrange / Act / Assert + assert.equal( + describeNodeRecordedSource({ + kind: 'label', + path: 'src/scheduler.ts', + line: 12, + elapsedMs: 1234, + }), + 'Recorded: src/scheduler.ts:12 · 1.23 s', + ) + assert.equal( + describeNodeRecordedSource({ + kind: 'thread', + stop: 2, + path: 'src/scheduler.ts', + line: 12, + }), + 'Recorded test stop 2 · src/scheduler.ts:12', + ) + assert.equal( + describeNodeRecordedSource({ + kind: 'open-failed', + stop: 2, + cause: 'EACCES: permission denied', + }), + 'Codebook could not open the recorded source of stop 2: EACCES: permission denied. Details: Output › Codebook.', + ) + assert.equal( + describeNodeRecordedSource({ + kind: 'open-failed', + cause: 'EACCES: permission denied', + }), + 'Codebook could not open the recorded source: EACCES: permission denied. Details: Output › Codebook.', + ) + assert.equal( + describeNodeRecordedSource({ + kind: 'tab-title', + path: 'src/jobs/scheduler.ts', + }), + 'Captured-scheduler.ts', + ) + assert.equal( + NODE_RECORDED_SOURCE_TEXT.placeholder, + '// Recorded source · Not recorded at this moment\n// The test journal holds no source state for this moment.\n', + ) + assert.equal( + NODE_RECORDED_SOURCE_TEXT.loading, + '// Loading recorded source…\n', + ) +}) + +// Value: protects=an event's time on every test replay surface: seconds since the run started with two decimals; fails_when=the time is rounded otherwise or carries its unit; why_new=the formatter moved out of describeNodeTestReplay so the slot's label shares it; seam=none; no_claim=none beyond protects +test('a recorded event’s time reads as seconds with two decimals', () => { + // Arrange / Act / Assert + assert.equal(formatEventSeconds(1234), '1.23') + assert.equal(formatEventSeconds(0), '0.00') + assert.equal(formatEventSeconds(60_005), '60.01') +}) + +// Value: protects=the slot's document name: one path per replay and file, its last segment the tab title; fails_when=two replays or two files share a slot path, or the path keeps the file's folders; why_new=DS5's one slot per history, renamed per file; seam=none; no_claim=the URI's scheme and authority, which the workspace adds +test('a recorded-source slot is named after its replay and the file of the stop it shows', () => { + // Arrange / Act / Assert + assert.equal( + nodeSourceSlotPath('instance_run', 'src/jobs/scheduler.ts'), + '/node-history-slot/instance_run/Captured-scheduler.ts', + ) + assert.equal( + nodeSourceSlotPath('instance_run', 'src/jobs/queue.ts'), + '/node-history-slot/instance_run/Captured-queue.ts', + ) +}) + +// Value: protects=which captured-source documents count as recorded-source slots, so the workspace closes every slot tab but the shown one and serves a restored slot the placeholder; fails_when=a slot of another replay or file is not recognized (an orphan slot tab stays), or a stop preview or a live source view is taken for a slot (a learner's other captured tab closes); why_new=PR-B2 /ship Step 9 state-machines review (orphan slot tabs); seam=none; no_claim=the URI's scheme and authority, which the workspace checks +test('only paths under the slot root count as recorded-source slots', () => { + // Arrange / Act / Assert + assert.equal( + isNodeSourceSlotPath( + '/node-history-slot/instance_run/Captured-scheduler.ts', + ), + true, + ) + assert.equal( + isNodeSourceSlotPath('/node-history-slot/other_run/Captured-queue.ts'), + true, + ) + assert.equal(isNodeSourceSlotPath('/node-history/instance_run/2/abc'), false) + assert.equal(isNodeSourceSlotPath('/views/node-history-slot.ts'), false) +}) + +// Value: protects=the name of a slot that opens on a placeholder: the file of the replay's first verified stop, so landing on that stop later does not rename the slot, else the test file; fails_when=an unverified stop names the slot, or a replay with a verified stop is named after its test file; why_new=Design 4's opening on an output or the result; seam=none; no_claim=renames at later stops (the slot tests) +test('a slot that opens on a placeholder is named after the first verified stop’s file, else the test file', () => { + // Arrange + const header = nodeTestHistoryHeader('workspace') + const output: NodeTestHistoryEntry = { + type: 'output', + sequence: 1, + elapsedMs: 100, + outputSequence: 1, + channel: 'stdout', + text: 'RUN src/scheduler.test.ts\n', + } + + // Act + const withVerifiedStop = nodeSourceSlotName({ + header, + entries: [output, schedulerStop(2)], + }) + const withEditedStop = nodeSourceSlotName({ + header, + entries: [output, schedulerStop(2, true)], + }) + + // Assert + assert.equal(withVerifiedStop, 'src/scheduler.ts') + assert.equal(withEditedStop, 'src/theme.test.ts') +}) + +// Value: protects=the slot's placeholder and loading text read as comments in every JavaScript or TypeScript file kind a slot is named after, so the editor's language service reports no problem for them in the learner's workspace; fails_when=a line of either text is plain words, which a TypeScript or JavaScript parser reports as syntax errors (the source-slot spike in VS Code showed 19 problems for the placeholder of a `.ts` slot); why_new=PR-B2's source-slot spike, VS Code 1.142.0 in the macOS Space; seam=the TypeScript compiler's parser stands in for the editor's language service; no_claim=other languages, which no test stop records +test('the slot’s placeholder and loading text parse without a syntax error as TypeScript and JavaScript', () => { + // Arrange + const fileNames = [ + 'slot.ts', + 'slot.tsx', + 'slot.mts', + 'slot.cts', + 'slot.js', + 'slot.mjs', + 'slot.cjs', + 'slot.jsx', + ] + + // Act + const errors = fileNames.flatMap((fileName) => + [ + NODE_RECORDED_SOURCE_TEXT.placeholder, + NODE_RECORDED_SOURCE_TEXT.loading, + ].flatMap((text) => { + const parsed = ts.createSourceFile( + fileName, + text, + ts.ScriptTarget.Latest, + false, + ) + // parseDiagnostics holds what the parser reported for this text. + const diagnostics = ( + parsed as unknown as { parseDiagnostics: readonly ts.Diagnostic[] } + ).parseDiagnostics + return diagnostics.map( + (diagnostic) => + `${fileName}: ${ts.flattenDiagnosticMessageText(diagnostic.messageText, ' ')}`, + ) + }), + ) + + // Assert + assert.deepEqual(errors, []) +}) diff --git a/extension/src/tests/nodeHistoryPlaybackController.test.ts b/extension/src/tests/nodeHistoryPlaybackController.test.ts index aa3af1e89..d1a426458 100644 --- a/extension/src/tests/nodeHistoryPlaybackController.test.ts +++ b/extension/src/tests/nodeHistoryPlaybackController.test.ts @@ -559,3 +559,80 @@ test('a Node stop that finishes presenting after the reader closed publishes not // Assert assert.equal(publishes, 0) }) + +// Value: protects=Play not idling through a long unrecorded interval between two events and stating the shown event own time; fails_when=the dwell bound NODE_HISTORY_PLAY_MAX_DWELL_MS is removed (Play waits the recorded 60 s) or positionMs reports the elapsed wall time; why_new=Cycle 0049 DS11; seam=none; no_claim=native presentation timing +test('Play waits at most 1,500 ms before an event recorded a minute later and reports that event’s own time', async () => { + // Arrange + let now = 0 + const presented: number[] = [] + const controller = new NodeHistoryPlaybackController({ + present: async (sequence) => { + presented.push(sequence) + }, + changed() {}, + now: () => now, + manualTicks: true, + }) + controller.open( + [ + { sequence: 1, elapsedMs: 0 }, + { sequence: 2, elapsedMs: 60_000 }, + { sequence: 3, elapsedMs: 60_200 }, + ], + 1, + ) + controller.play() + + // Act + now = 1_499 + await controller.tick() + const beforeBound = [...presented] + now = 1_500 + await controller.tick() + + // Assert + assert.deepEqual(beforeBound, [], 'nothing is presented before the bound') + assert.deepEqual(presented, [2], 'the far event follows at the bound') + assert.equal(controller.state().positionMs, 60_000) + assert.equal( + controller.state().mode, + 'playing', + 'an unrecorded interval neither pauses nor asks', + ) + controller.dispose() +}) + +// Value: protects=events recorded close together keeping their recorded spacing under the dwell bound; fails_when=every event waits the full bound or none waits; why_new=Cycle 0049 DS11; seam=none; no_claim=none +test('Play keeps the recorded spacing of events closer together than the dwell bound', async () => { + // Arrange + let now = 0 + const presented: number[] = [] + const controller = new NodeHistoryPlaybackController({ + present: async (sequence) => { + presented.push(sequence) + }, + changed() {}, + now: () => now, + manualTicks: true, + }) + controller.open( + [ + { sequence: 1, elapsedMs: 0 }, + { sequence: 2, elapsedMs: 200 }, + ], + 1, + ) + controller.play() + + // Act + now = 199 + await controller.tick() + const beforeSpacing = [...presented] + now = 200 + await controller.tick() + + // Assert + assert.deepEqual(beforeSpacing, []) + assert.deepEqual(presented, [2]) + controller.dispose() +}) diff --git a/extension/src/tests/projectNodeHistoryTimeline.test.ts b/extension/src/tests/projectNodeHistoryTimeline.test.ts new file mode 100644 index 000000000..c166ebc44 --- /dev/null +++ b/extension/src/tests/projectNodeHistoryTimeline.test.ts @@ -0,0 +1,191 @@ +import assert from 'node:assert/strict' +import { test } from 'node:test' + +import type { NodeTestHistoryEntry } from '../nodeTestHistorySchemas' +import { sha256 } from '../runtimeSupport/utils/sha256' +import { NODE_TEST_REPLAY_TEXT } from '../utils/describeNodeTestReplay' +import { projectHistoricalTimeline } from '../utils/projectHistoricalTimeline' +import { projectNodeHistoryTimeline } from '../utils/projectNodeHistoryTimeline' +import { projectNodeTestSection } from '../utils/projectNodeTestSection' + +type StopEntry = Extract + +const SOURCE_TEXT = 'export const delay = schedule(job, 5_000)\n' +const SOURCE_HASH = sha256(SOURCE_TEXT) + +const output = (sequence: number, elapsedMs: number): NodeTestHistoryEntry => ({ + type: 'output', + sequence, + elapsedMs, + outputSequence: sequence, + channel: 'stdout', + text: 'RUN src/jobs.test.ts\n', +}) + +/** A stop whose captured source verifies: the frame's text hashes to the sealed hash at the stopped line. */ +const verifiedStop = (sequence: number, elapsedMs: number): StopEntry => ({ + type: 'stop', + sequence, + elapsedMs, + index: 0, + source: { path: 'src/jobs.ts', hash: SOURCE_HASH, line: 1, column: 1 }, + frame: { name: 'schedule', line: 1, column: 1 }, + facts: [], + debuggerSnapshot: { + version: 1, + frames: [ + { + name: 'schedule', + line: 1, + column: 1, + source: { + name: 'src/jobs.ts', + text: SOURCE_TEXT, + hash: SOURCE_HASH, + line: 1, + }, + scopes: [], + }, + ], + variables: [], + limitations: [], + }, +}) + +/** A stop whose snapshot holds no frame, so its source cannot verify. */ +const unverifiedStop = (sequence: number, elapsedMs: number): StopEntry => ({ + ...verifiedStop(sequence, elapsedMs), + debuggerSnapshot: { version: 1, frames: [], variables: [], limitations: [] }, +}) + +const result = (sequence: number, elapsedMs: number): NodeTestHistoryEntry => ({ + type: 'result', + sequence, + elapsedMs, + exitCode: 0, + signal: null, + outputTail: '', +}) + +// Value: protects=the shared timeline adapter's contract that a test journal records no resume time; fails_when=the adapter drops `pausedIntervals: []` (an undefined list answers unknown, so no mark is drawn) or marks a paused interval as recorded; why_new=Cycle 0049 E1; seam=none; no_claim=how the pane draws the span +test('a test replay maps its whole range to one unrecorded span with a tick at each verified stop', () => { + // Arrange + const history = { + entries: [ + output(1, 100), + verifiedStop(2, 420), + output(3, 600), + verifiedStop(4, 700), + result(5, 900), + ], + } + + // Act + const timeline = projectNodeHistoryTimeline(history) + + // Assert + assert.deepEqual(timeline, { + startMs: 100, + endMs: 900, + gaps: [{ startMs: 100, endMs: 900 }], + recordedPoints: [420, 700], + }) +}) + +// Value: protects=no tick for a stop whose captured source does not verify (the pane says "Recorded source unavailable" there); fails_when=every stop becomes a tick regardless of nodeStopSourceMatches; why_new=Cycle 0049 E1; seam=none; no_claim=the verification rules themselves (nodeStopSourceMatches tests) +test('a stop whose captured source does not verify gets no tick while a verified stop keeps its tick', () => { + // Arrange + const history = { + entries: [ + output(1, 0), + unverifiedStop(2, 300), + verifiedStop(3, 600), + result(4, 1_000), + ], + } + + // Act + const timeline = projectNodeHistoryTimeline(history) + + // Assert + assert.deepEqual(timeline?.recordedPoints, [600]) +}) + +// Value: protects=no marks on a history with nothing to span, as the browser transport draws none; fails_when=a one-event history or events at one time draw a zero-width or full-width gap; why_new=Cycle 0049 E1; seam=none; no_claim=none +test('a history of one event, or of events at one time, has no timeline marks', () => { + // Arrange + const single = { entries: [result(1, 500)] } + const sameTime = { entries: [output(1, 500), verifiedStop(2, 500)] } + const empty = { entries: [] } + + // Act + const marks = [single, sameTime, empty].map(projectNodeHistoryTimeline) + + // Assert + assert.deepEqual(marks, [undefined, undefined, undefined]) +}) + +// Value: protects=the adapter's reason to pass an empty paused list: the existing projection answers unknown for an undefined list; fails_when=projectHistoricalTimeline starts mapping a context without pausedIntervals, which would let the adapter drop the argument unnoticed; why_new=Cycle 0049 E1 pins `pausedIntervals: []`; seam=none; no_claim=old archive coverage +test('the historical timeline answers unknown without a paused-interval list and maps one span with an empty list', () => { + // Arrange + const study = { observations: [{ id: 'a', elapsedMs: 10, debugger: {} }] } + const range = { startMs: 0, endMs: 100 } + + // Act + const withoutList = projectHistoricalTimeline({ study }, range) + const withEmptyList = projectHistoricalTimeline( + { pausedIntervals: [], study }, + range, + ) + + // Assert + assert.deepEqual(withoutList, { status: 'unknown' }) + assert.deepEqual(withEmptyList, { + status: 'mapped', + gaps: [{ startMs: 0, endMs: 100 }], + recordedPoints: [10], + }) +}) + +// Value: protects=the Study section carrying the slider's marks and the catalog legend to the pane; fails_when=the section drops its timeline or the legend string changes; why_new=Cycle 0049 E1/X13; seam=none; no_claim=the pane's drawing (Reader DOM case) +test('the test replay section carries the slider marks and states the recorded-stops legend', () => { + // Arrange + const entries = [output(1, 0), verifiedStop(2, 400), result(3, 900)] + + // Act + const view = projectNodeTestSection({ + history: { entries, status: 'complete' }, + selected: entries[1], + selectedStopVerified: true, + applicationClosed: false, + }) + + // Assert + assert.deepEqual(view.timeline, { + startMs: 0, + endMs: 900, + gaps: [{ startMs: 0, endMs: 900 }], + recordedPoints: [400], + }) + assert.equal( + NODE_TEST_REPLAY_TEXT.timelineLegend, + 'Ticks mark recorded stops; source and debugger are not recorded between them.', + ) +}) + +// Value: protects=a one-event replay showing no marks in the section; fails_when=the section invents a timeline for one event; why_new=Cycle 0049 E1; seam=none; no_claim=none +test('the test replay section of a one-event history has no timeline', () => { + // Arrange + const entries = [result(1, 500)] + + // Act + const view = projectNodeTestSection({ + history: { entries, status: 'complete' }, + selected: entries[0], + selectedStopVerified: false, + applicationClosed: false, + }) + + // Assert + assert.equal('timeline' in view, false) +}) diff --git a/extension/src/tests/projectNodeTestSection.test.ts b/extension/src/tests/projectNodeTestSection.test.ts index ceb35c960..112f0629a 100644 --- a/extension/src/tests/projectNodeTestSection.test.ts +++ b/extension/src/tests/projectNodeTestSection.test.ts @@ -184,6 +184,13 @@ test('at a stop the section shows its locator, its first step and the other step verdict: 'Test passed · exit code 0', previousStop: false, nextStop: true, + // The fixture's stops carry no captured source, so the whole range is one unrecorded span with no tick. + timeline: { + startMs: 100, + endMs: 900, + gaps: [{ startMs: 100, endMs: 900 }], + recordedPoints: [], + }, }) }) diff --git a/extension/src/tests/studyWorkspace.test.ts b/extension/src/tests/studyWorkspace.test.ts index 0a7480a7d..33431b721 100644 --- a/extension/src/tests/studyWorkspace.test.ts +++ b/extension/src/tests/studyWorkspace.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict' import { randomUUID } from 'node:crypto' import { mkdir, rm, writeFile } from 'node:fs/promises' -import { join } from 'node:path' +import { basename, join } from 'node:path' import { test } from 'node:test' import { setTimeout as delay } from 'node:timers/promises' @@ -29,6 +29,20 @@ import { } from './utils/fakeClock' import { nodeTestHistoryHeader } from './utils/nodeTestHistoryFixture' import { shownTestOutput } from './utils/shownTestOutput' + +/** + * Lists the historical debugger presentations of recorded stops, leaving out the "Not recorded at this moment" presentations that start the replay debugger on an output, the result or an unverified stop (Design 4). + * @param harness - The workspace harness. + * @returns The presentations that carry a recorded stop's snapshot, in order. + * @example recordedStopPresentations(harness)[0]?.snapshot?.variables[0]?.name // => 'nextTheme' + */ +function recordedStopPresentations( + harness: Awaited>, +) { + return harness.historicalDebugPresentations.filter( + (presentation) => presentation.snapshot !== undefined, + ) +} test('restored Observed moments leaves its loading state after workspace initialization', async () => { // Arrange const harness = await workspaceHarness() @@ -90,7 +104,7 @@ test('an unreadable Node history folder is reported while the saved-study reader } }) -// Value: protects=a saved test replay opens in the Study reader beside browser studies, pages its events, sends each selected stop's recorded values and sealed source to the native debugger, and shows in the Application pane exactly the recorded output up to the selected event; fails_when=the reader enters browser playback, the Application pane shows output recorded after the selected event or no recorded output document, or a reopened store loses the selected moment; why_new=PR-B1 moved the recorded output from the Study pane's block to the Application pane (Design 3, AC5); seam=the workspace harness's posted messages and native panels; no_claim=the document's pixels or its in-place updates in a real webview +// Value: protects=a saved test replay opens in the Study reader beside browser studies, pages its events, sends each selected stop's recorded values and sealed source to the native debugger through the replay's one recorded-source slot (PR-B2, DS5; counts follow recorded-stop presentations, as the debugger also starts on the "Not recorded" thread), and shows in the Application pane exactly the recorded output up to the selected event; fails_when=the reader enters browser playback, the Application pane shows output recorded after the selected event or no recorded output document, or a reopened store loses the selected moment; why_new=PR-B1 moved the recorded output from the Study pane's block to the Application pane (Design 3, AC5); seam=the workspace harness's posted messages and native panels; no_claim=the document's pixels or its in-place updates in a real webview test('saved Node history is selectable in the reader without entering browser playback', async () => { // Arrange const harness = await workspaceHarness() @@ -407,13 +421,13 @@ test('saved Node history is selectable in the reader without entering browser pl // Native presentation precedes durable cursor publication; wait for both before inspecting the reader. await waitUntil( () => - harness.historicalDebugPresentations.length === 1 && + recordedStopPresentations(harness).length === 1 && harness.postedMessages().slice(-1)[0]?.nodeHistoryPosition?.sequence === 23, 'first historical Node stop reaches the native debugger and reader', 1_000, ) - const firstPresentation = harness.historicalDebugPresentations[0]! + const firstPresentation = recordedStopPresentations(harness)[0]! assert.equal(firstPresentation.snapshot?.variables[0]?.name, 'nextTheme') assert.equal( firstPresentation.sourceDocument?.hash, @@ -433,12 +447,16 @@ test('saved Node history is selectable in the reader without entering browser pl shownTestOutput(harness), /between stops|Tests 1 passed/, ) + // The stop's frames open the replay's one recorded-source slot, named after the stop's file (DS5). + const slotUri = new URL(firstPresentation.sourceDocument.uri) + assert.equal( + slotUri.pathname, + `/node-history-slot/${header.studyId}/Captured-${basename(header.configuration.source.path)}`, + ) + // A per-stop source address of an earlier version still refuses a hash its sealed stop does not have. await assert.rejects( harness.readCapturedSource( - firstPresentation.sourceDocument.uri.replace( - header.configuration.source.hash, - secondSource.hash, - ), + `${slotUri.protocol}//${slotUri.host}/node-history/${header.studyId}/23/${secondSource.hash}/Captured-${basename(header.configuration.source.path)}`, ), /no longer matches its sealed history/i, ) @@ -508,13 +526,13 @@ test('saved Node history is selectable in the reader without entering browser pl }) await waitUntil( () => - harness.historicalDebugPresentations.length === 2 && + recordedStopPresentations(harness).length === 2 && harness.postedMessages().slice(-1)[0]?.nodeHistoryPosition?.sequence === 25, 'second historical Node stop replaces the selected native and reader state', 1_000, ) - const secondPresentation = harness.historicalDebugPresentations[1]! + const secondPresentation = recordedStopPresentations(harness)[1]! assert.equal(secondPresentation.snapshot?.variables[0]?.name, 'themeName') assert.equal(secondPresentation.sourceDocument?.hash, secondSource.hash) assert.equal( @@ -529,6 +547,7 @@ test('saved Node history is selectable in the reader without entering browser pl assert.doesNotMatch(shownTestOutput(harness), /Tests 1 passed/) // Act: moving through output-only intervals clears the previously selected native debug context. + const invalidationsBeforeOutput = harness.historicalDebugInvalidations() harness.receive({ type: 'node-history-event', revision: message.revision, @@ -548,13 +567,16 @@ test('saved Node history is selectable in the reader without entering browser pl assert.equal(interStopMessage.nodeHistoryPosition?.type, 'output') assert.match(shownTestOutput(harness), /between stops/) assert.doesNotMatch(shownTestOutput(harness), /Tests 1 passed/) - assert.equal( - harness.historicalDebugInvalidations(), - 1, + assert.ok( + harness.historicalDebugInvalidations() > invalidationsBeforeOutput, 'the previous stop is cleared during an output-only interval', ) assert.equal( - harness.historicalDebugPresentations.length, + harness.historicalDebugInvalidationLabels().at(-1), + 'Not recorded at this moment', + ) + assert.equal( + recordedStopPresentations(harness).length, 2, 'an output-only interval does not claim a debugger snapshot', ) @@ -586,6 +608,7 @@ test('saved Node history is selectable in the reader without entering browser pl 'backward navigation restores the output gap', 1_000, ) + const invalidationsBeforeResult = harness.historicalDebugInvalidations() harness.receive({ type: 'node-history-event', revision: message.revision, @@ -605,13 +628,12 @@ test('saved Node history is selectable in the reader without entering browser pl assert.equal(terminalMessage.nodeHistoryPosition?.type, 'result') assert.match(shownTestOutput(harness), /between stops/) assert.doesNotMatch(shownTestOutput(harness), /Tests 1 passed/) - assert.equal( - harness.historicalDebugInvalidations(), - 3, + assert.ok( + harness.historicalDebugInvalidations() > invalidationsBeforeResult, 'terminal events do not retain historical debugger values', ) assert.equal( - harness.historicalDebugPresentations[2]?.snapshot?.variables[0]?.name, + recordedStopPresentations(harness)[2]?.snapshot?.variables[0]?.name, 'themeName', 'revisiting a stop restores its captured values', ) @@ -625,7 +647,7 @@ test('saved Node history is selectable in the reader without entering browser pl }) await waitUntil( () => - harness.historicalDebugPresentations.length === 4 && + recordedStopPresentations(harness).length === 4 && harness.postedMessages().slice(-1)[0]?.nodeHistoryPosition?.sequence === 25, 'second stop is selected in the reader before reopening its history', @@ -644,7 +666,7 @@ test('saved Node history is selectable in the reader without entering browser pl }) await waitUntil( () => - harness.historicalDebugPresentations.length === 5 && + recordedStopPresentations(harness).length === 5 && harness.postedMessages().slice(-1)[0]?.nodeHistoryPosition?.sequence === 25 && !harness.postedMessages().slice(-1)[0]?.loading, @@ -660,7 +682,7 @@ test('saved Node history is selectable in the reader without entering browser pl true, ) assert.equal( - harness.historicalDebugPresentations[4]?.snapshot?.variables[0]?.name, + recordedStopPresentations(harness)[4]?.snapshot?.variables[0]?.name, 'themeName', ) assert.equal( @@ -675,7 +697,7 @@ test('saved Node history is selectable in the reader without entering browser pl ) assert.equal( await harness.readCapturedSource( - harness.historicalDebugPresentations[4].sourceDocument!.uri, + recordedStopPresentations(harness)[4]!.sourceDocument!.uri, ), secondSourceText, ) @@ -703,7 +725,7 @@ test('saved Node history is selectable in the reader without entering browser pl assert.match(shownTestOutput(harness), /between stops/) assert.doesNotMatch(shownTestOutput(harness), /Tests 1 passed/) const presentationsBeforeOutputRestore = - harness.historicalDebugPresentations.length + recordedStopPresentations(harness).length harness.reader['nodeHistoryStore'] = new NodeTestHistoryStore( library.directory, header.workspaceKey, @@ -735,7 +757,7 @@ test('saved Node history is selectable in the reader without entering browser pl assert.match(shownTestOutput(harness), /between stops/) assert.doesNotMatch(shownTestOutput(harness), /Tests 1 passed/) assert.equal( - harness.historicalDebugPresentations.length, + recordedStopPresentations(harness).length, presentationsBeforeOutputRestore, 'reopening an output event does not present a stale debugger stop', ) @@ -757,7 +779,7 @@ test('saved Node history is selectable in the reader without entering browser pl harness.reader.inspect().view!.errors.at(-1)!, /Close browser replay/, ) - assert.equal(harness.historicalDebugPresentations.length, 5) + assert.equal(recordedStopPresentations(harness).length, 5) harness.reader['recordingActive'] = false // Act: advance the independent event page without opening browser playback. @@ -1233,7 +1255,7 @@ test('reopening a Node history after the learner stops its historical debugger r sequence: 2, }) await waitUntil( - () => harness.historicalDebugPresentations.length === 1, + () => recordedStopPresentations(harness).length === 1, 'the recorded stop reaches the native debugger', 1_000, ) @@ -1248,7 +1270,7 @@ test('reopening a Node history after the learner stops its historical debugger r }) await waitUntil( () => - harness.historicalDebugPresentations.length === 2 && + recordedStopPresentations(harness).length === 2 && !harness.postedMessages().slice(-1)[0]?.loading, 'the reopened history presents its saved stop through a fresh historical debugger', 1_000, @@ -1257,7 +1279,7 @@ test('reopening a Node history after the learner stops its historical debugger r // Assert assert.equal(harness.historicalDebuggers.length, 2) assert.equal( - harness.historicalDebugPresentations[1]?.snapshot?.variables[0]?.name, + recordedStopPresentations(harness)[1]?.snapshot?.variables[0]?.name, 'nextTheme', ) assert.equal( @@ -1620,7 +1642,7 @@ test('moving to another Node history event while a stop still loads its native v harness.postedMessages().slice(-1)[0]?.nodeHistoryPosition?.type, 'result', ) - assert.equal(harness.historicalDebugPresentations.length, 1) + assert.equal(recordedStopPresentations(harness).length, 1) } finally { await harness.close() } @@ -3720,7 +3742,7 @@ test('inspecting a Node stop whose captured source differs from its recorded pos ) // Assert - assert.equal(harness.historicalDebugPresentations.length, 0) + assert.equal(recordedStopPresentations(harness).length, 0) assert.equal( harness.postedMessages().slice(-1)[0]?.nodeHistoryPosition?.sequence, 1, @@ -3819,7 +3841,7 @@ test('a Node stop selected on the timeline whose captured source differs from it assert.equal(selectedStop.nodeHistoryPosition?.type, 'stop') assert.equal(selectedStop.nodeHistoryPosition?.sourceAvailable, false) assert.equal(selectedStop.nodeHistoryPosition?.debuggerAvailable, false) - assert.equal(harness.historicalDebugPresentations.length, 0) + assert.equal(recordedStopPresentations(harness).length, 0) } finally { await harness.close() } @@ -4304,7 +4326,7 @@ test('pressing Inspect again while the editor is still stopping the ended histor assert.equal(sessionsWhileStopping, 1) assert.equal(harness.historicalDebuggers.length, 2) assert.equal(harness.historicalDebuggers[1]!.available, true) - assert.equal(harness.historicalDebugPresentations.length, 2) + assert.equal(recordedStopPresentations(harness).length, 2) assert.equal(view.nodeHistoryPosition?.sequence, 2) assert.equal(view.nodeHistoryPosition?.debuggerAvailable, true) } finally { diff --git a/extension/src/tests/studyWorkspaceRemoval.test.ts b/extension/src/tests/studyWorkspaceRemoval.test.ts index 64532a996..e59166ea9 100644 --- a/extension/src/tests/studyWorkspaceRemoval.test.ts +++ b/extension/src/tests/studyWorkspaceRemoval.test.ts @@ -7754,6 +7754,14 @@ test('a Node test history opened while the neighbour of a removed study is being const removal = requestRemoval(harness, removed.id) await neighbourRead.started await sendChoice(harness, 'node-history', nodeHistory.studyId) + // The open ends with its own publish, which a loaded machine can deliver after the choice's answer. + await waitUntil( + () => + harness.reader.inspect().view?.nodeHistory?.header.studyId === + nodeHistory.studyId && !harness.reader.inspect().view?.loading, + 'the Node test history is open', + 2_000, + ) // The learner selects the history's recorded stop, which shows that stop's captured source in the historical debugger; the reader's `sourceUri` names only a saved study's source. const opened = harness.reader.inspect().view! await readerSeams(harness).receive( @@ -7781,8 +7789,9 @@ test('a Node test history opened while the neighbour of a removed study is being inspected.view!.nodeHistory?.header.studyId, nodeHistory.studyId, ) + // The stop's frames open the history's recorded-source slot (PR-B2, DS5). assert.equal( - presentedSource?.includes(`/node-history/${nodeHistory.studyId}/`), + presentedSource?.includes(`/node-history-slot/${nodeHistory.studyId}/`), true, ) assert.equal( @@ -7820,6 +7829,14 @@ test('refreshes after the background selection changed leave a selected test rep const removal = requestRemoval(harness, removed.id) await neighbourRead.started await sendChoice(harness, 'node-history', nodeHistory.studyId) + // The open ends with its own publish, which a loaded machine can deliver after the choice's answer. + await waitUntil( + () => + harness.reader.inspect().view?.nodeHistory?.header.studyId === + nodeHistory.studyId && !harness.reader.inspect().view?.loading, + 'the Node test history is open', + 2_000, + ) const opened = harness.reader.inspect().view! await readerSeams(harness).receive( { diff --git a/extension/src/tests/studyWorkspaceTestReplay.test.ts b/extension/src/tests/studyWorkspaceTestReplay.test.ts index 96bfeb81b..233236957 100644 --- a/extension/src/tests/studyWorkspaceTestReplay.test.ts +++ b/extension/src/tests/studyWorkspaceTestReplay.test.ts @@ -133,7 +133,7 @@ test('Open replay opens a sealed test replay in a closed Study pane on its first } }) -// Value: protects=a test replay's saved reader position, which wins over the landing on its first verified stop; fails_when=a replay the learner left on its result reopens on a stop; why_new=DS1 keeps the saved position first (AC4); seam=none; no_claim=a position saved in another window +// Value: protects=a test replay's saved reader position, which wins over the landing on its first verified stop, and the replay debugger that opens on that moment with no recorded stack; fails_when=a replay the learner left on its result reopens on a stop, or opens with no "Not recorded at this moment" thread or with a stop's frames; why_new=DS1 keeps the saved position first (AC4); PR-B2 (Design 4) starts the debugger on the "Not recorded" thread when a replay opens on an output or the result; seam=none; no_claim=a position saved in another window test('Open replay opens a test replay at its saved reader position', async () => { // Arrange const harness = await workspaceHarness() @@ -155,13 +155,19 @@ test('Open replay opens a test replay at its saved reader position', async () => // Assert assert.equal(lastView(harness)?.nodeHistoryPosition?.sequence, 3) - assert.equal(harness.historicalDebugPresentations.length, 0) + assert.deepEqual( + harness.historicalDebugPresentations.map(({ snapshot, label }) => ({ + snapshot, + label, + })), + [{ snapshot: undefined, label: 'Not recorded at this moment' }], + ) } finally { await harness.close() } }) -// Value: protects=the landing of a test replay without a verified stop: its first event; fails_when=the open selects an unverified stop and presents another moment's source; why_new=DS1's fallback (AC4); seam=a stop whose captured text was edited after the seal; no_claim=none beyond protects +// Value: protects=the landing of a test replay without a verified stop: its first event, with the debugger on the "Not recorded at this moment" thread; fails_when=the open selects an unverified stop and presents another moment's source; why_new=DS1's fallback (AC4); PR-B2 (Design 4) starts the debugger on the "Not recorded" thread at such a moment; seam=a stop whose captured text was edited after the seal; no_claim=none beyond protects test('a test replay whose stop does not verify opens on its first event', async (context) => { // Arrange const harness = await workspaceHarness() @@ -211,7 +217,13 @@ test('a test replay whose stop does not verify opens on its first event', async // Assert assert.equal(lastView(harness)?.nodeHistoryPosition?.sequence, 1) - assert.equal(harness.historicalDebugPresentations.length, 0) + assert.deepEqual( + harness.historicalDebugPresentations.map(({ snapshot, label }) => ({ + snapshot, + label, + })), + [{ snapshot: undefined, label: 'Not recorded at this moment' }], + ) } finally { context.mock.restoreAll() await harness.close() @@ -328,6 +340,44 @@ test('Open replay of a test replay during a browser replay tells the learner one } }) +// Value: protects=Retry pressed while a browser replay holds the reader leaves the shared debugger and source with that replay: it never presents the stop of a test replay that was selected before the recording opened; fails_when=Retry re-selects the earlier test replay's moment, which puts its recorded stop on the shared debugger beside the browser replay's frame; why_new=/ship Step 11 (Codex structured review P2: Retry bypassed the browser replay's refusal); seam=none; no_claim=what Retry does for the browser replay's own rows +test('Retry during a browser replay presents no stop of the test replay selected before it', async () => { + // Arrange + const harness = await recordedReaderHarness() + try { + const nodeHistory = await saveOneStopNodeHistory( + harness.service.nodeHistoryStore!, + ) + await harness.reader.action('retry') + await harness.reader.openLearningReplay(nodeHistory.studyId) + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === 2, + 'the test replay on its stop', + 2_000, + ) + await harness.reader.openRecording(harness.studyId) + await waitUntil( + () => harness.controller.state().readiness === 'ready', + 'the opened recording', + 2_000, + ) + const testStopPresentations = () => + harness.historicalDebugPresentations.filter((presentation) => + presentation.label.startsWith('Recorded test stop'), + ).length + const presentationsBeforeRetry = testStopPresentations() + + // Act + await harness.reader.action('retry') + + // Assert + assert.equal(testStopPresentations(), presentationsBeforeRetry) + assert.equal(harness.controller.state().studyId, harness.studyId) + } finally { + await harness.close() + } +}) + // Value: protects=the status bar's Save learning replay item of a live test run while the Study pane was never opened, the usual state of a chat-driven test run; fails_when=the item is drawn only when the reader publishes, so it stays hidden until the learner opens the Study pane and Save learning replay cannot be clicked; why_new=the live Save test opens the reader first (Red Team, Step 9 of PR-A's ship); seam=none; no_claim=the host's status bar drawing (the harness's status item stands in) test('the Save item of a live test run is drawn in the status bar while the Study pane is closed', async () => { // Arrange diff --git a/extension/src/tests/studyWorkspaceTestReplaySource.test.ts b/extension/src/tests/studyWorkspaceTestReplaySource.test.ts new file mode 100644 index 000000000..d7a834574 --- /dev/null +++ b/extension/src/tests/studyWorkspaceTestReplaySource.test.ts @@ -0,0 +1,915 @@ +import assert from 'node:assert/strict' +import { test } from 'node:test' + +import type { NodeTestHistoryStore } from '../nodeTestHistoryStore' +import type { NodeTestSourceStop } from '../ownedNodeTestRun' +import { sha256 } from '../runtimeSupport/utils/sha256' +import { waitUntil } from '../runtimeSupport/utils/waitUntil' +import type { CodebookDiagnostic } from '../utils/formatCodebookDiagnostic' + +import { + saveOneStopNodeHistory, + workspaceHarness, +} from './studyWorkspaceHarness' +import { nodeTestHistoryHeader } from './utils/nodeTestHistoryFixture' + +type Harness = Awaited> + +const THEME_TEXT = 'const nextTheme = "dark";\n' +const THEME_NEXT_TEXT = 'export const applied = applyTheme(nextTheme);\n' +const PLACEHOLDER = + '// Recorded source · Not recorded at this moment\n// The test journal holds no source state for this moment.\n' + +/** The last view the reader posted to its panes. */ +function lastView(harness: Harness) { + return harness.postedMessages().slice(-1)[0] +} + +/** + * Lists the URIs of every editor tab that shows a test replay's recorded-source slot, in every group. + * @param harness - The workspace harness. + * @returns The slot tabs' URIs. + * @example slotTabs(harness) // => ['codebook-source://…/node-history-slot//Captured-theme.ts'] + */ +function slotTabs(harness: Harness): string[] { + return harness.groups.flatMap((group) => + group.tabs.flatMap((tab) => { + const input = tab.input as { uri?: { toString(): string } } | undefined + const uri = input?.uri?.toString() + return uri?.includes('/node-history-slot/') ? [uri] : [] + }), + ) +} + +/** + * Reads the end-of-line labels the reader last drew on a recorded-source slot; an empty list once it cleared them. + * @param harness - The workspace harness. + * @returns The label texts of the slot's last source identity decoration. + * @example slotLabels(harness) // => [' Recorded: src/theme.ts:1 · 0.20 s'] + */ +function slotLabels(harness: Harness): string[] { + const decoration = harness + .sourceIdentityDecorations() + .filter((call) => call.uri.includes('/node-history-slot/')) + .at(-1) + return (decoration?.ranges ?? []).map( + (range) => + (range as { renderOptions?: { after?: { contentText?: string } } }) + .renderOptions?.after?.contentText ?? '', + ) +} + +/** + * Saves a sealed test replay whose two stops stop in two files: output 1, stop 2 in `src/theme.ts`, output 3, stop 4 in `src/theme-next.ts`, result 5. + * @param store - The workspace's history store. + * @returns The history's header. + * @example const history = await saveTwoFileNodeHistory(harness.service.nodeHistoryStore!) + */ +async function saveTwoFileNodeHistory(store: NodeTestHistoryStore) { + const oneStop = nodeTestHistoryHeader(store.workspaceKey) + const nextSource = { + path: 'src/theme-next.ts', + hash: sha256(THEME_NEXT_TEXT), + line: 1, + column: 8, + } + const configuration = { + ...oneStop.configuration, + additionalStops: [ + { + ...nextSource, + anchorIndex: 0, + inspections: oneStop.configuration.inspections, + }, + ], + } + const history = { + ...oneStop, + configuration, + configurationHash: sha256(JSON.stringify(configuration)), + } + const writer = await store.start(history) + const stopIn = ( + index: number, + elapsedMs: number, + source: { path: string; hash: string; line: number; column: number }, + text: string, + ): NodeTestSourceStop => ({ + index, + runId: 'test-run', + sessionId: 'test-session', + threadId: 1, + elapsedMs, + worker: { pid: 1, processGroup: 1, workspace: '/private/test' }, + source, + frame: { id: index + 1, name: 'applyTheme', line: 1, column: 1 }, + variables: [{ name: 'nextTheme', value: 'dark', variablesReference: 0 }], + facts: [ + { path: 'nextTheme', mode: 'value', display: 'dark', type: 'string' }, + ], + debuggerSnapshot: { + version: 1, + frames: [ + { + name: 'applyTheme', + line: 1, + column: 1, + source: { name: source.path, text, hash: sha256(text), line: 1 }, + scopes: [{ name: 'Local', variables: [0] }], + }, + ], + variables: [ + { name: 'nextTheme', value: 'dark', type: 'string', children: [] }, + ], + limitations: [], + }, + }) + await writer.appendOutput({ + sequence: 1, + elapsedMs: 100, + channel: 'stdout', + text: 'RUN src/theme.test.ts\n', + }) + await writer.appendStop( + stopIn(0, 200, history.configuration.source, THEME_TEXT), + ) + await writer.appendOutput({ + sequence: 2, + elapsedMs: 250, + channel: 'stdout', + text: 'between stops\n', + }) + await writer.appendStop(stopIn(1, 300, nextSource, THEME_NEXT_TEXT)) + await writer.appendResult( + { exitCode: 0, signal: null, output: 'Tests 1 passed' }, + 400, + ) + await writer.finish('complete') + return history +} + +/** + * Opens a saved test replay through Open replay and waits until it shows the given moment. + * @param harness - The workspace harness. + * @param studyId - The replay's study id. + * @param sequence - The moment the open lands on. + * @example await openReplayAt(harness, history.studyId, 2) + */ +async function openReplayAt( + harness: Harness, + studyId: string, + sequence: number, +): Promise { + await harness.reader.action('retry') + await harness.reader.openLearningReplay(studyId) + await waitUntil( + () => + lastView(harness)?.nodeHistoryPosition?.sequence === sequence && + !lastView(harness)?.loading, + `the test replay shows sequence ${sequence}`, + 2_000, + ) +} + +/** + * Selects one moment of the open test replay as the Study pane's event list does, and waits until the reader shows it. + * @param harness - The workspace harness. + * @param studyId - The replay's study id. + * @param sequence - The moment to select. + * @example await selectMoment(harness, history.studyId, 3) + */ +async function selectMoment( + harness: Harness, + studyId: string, + sequence: number, +): Promise { + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId, + sequence, + }) + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === sequence, + `sequence ${sequence} is selected`, + 2_000, + ) +} + +// Value: protects=a verified stop of a test replay shows in one Codebook-owned recorded-source slot named after the stop's file, holding the stop's sealed source with its recorded label, and the replay debugger's frames open that slot on the thread `Recorded test stop · :`; fails_when=the stop opens a document per stop, the slot holds other bytes or no label, or the debugger's frames name another document or the old "Recorded Node test stop" thread; why_new=PR-B2's recorded-source slot (Design 4, DS5, DS14, AC6); seam=none; no_claim=how the native editor draws the label or reveals the line (the source-slot spike and N49) +test('a test replay’s verified stop shows its sealed source in one recorded-source slot that the debugger’s frames open', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveOneStopNodeHistory( + harness.service.nodeHistoryStore!, + ) + + // Act + await openReplayAt(harness, history.studyId, 2) + + // Assert + const tabs = slotTabs(harness) + assert.equal(tabs.length, 1) + assert.match( + tabs[0]!, + new RegExp(`/node-history-slot/${history.studyId}/Captured-theme\\.ts$`), + ) + assert.equal(await harness.readCapturedSource(tabs[0]!), THEME_TEXT) + assert.deepEqual(slotLabels(harness), [ + ' Recorded: src/theme.ts:1 · 0.20 s', + ]) + const presentation = harness.historicalDebugPresentations.at(-1)! + assert.equal(presentation.label, 'Recorded test stop 1 · src/theme.ts:1') + assert.equal(presentation.sourceDocument?.uri, tabs[0]) + assert.equal(presentation.sourceDocument?.hash, sha256(THEME_TEXT)) + } finally { + await harness.close() + } +}) + +// Value: protects=moving from a stop to an output and on to the result keeps the one slot tab and shows the 4A placeholder there with no stopped line or label, while the debugger reads "Not recorded at this moment"; fails_when=an output or the result keeps the earlier stop's source, line or label in the slot, opens a second tab, or leaves the stop on the debugger; why_new=4A for the recorded source (Design 4, AC6; PRODUCT_GOAL partial history); seam=none; no_claim=the Study pane's 4A line, which PR-B1's section tests cover +test('an output and the result after a stop show the 4A placeholder in the same slot and no stop in the debugger', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveOneStopNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const slot = slotTabs(harness)[0]! + + // Act + await selectMoment(harness, history.studyId, 3) + + // Assert + assert.deepEqual(slotTabs(harness), [slot]) + assert.equal(await harness.readCapturedSource(slot), PLACEHOLDER) + assert.deepEqual(slotLabels(harness), []) + assert.equal( + harness.historicalDebugInvalidationLabels().at(-1), + 'Not recorded at this moment', + ) + assert.equal( + lastView(harness)?.nodeHistoryPosition?.debuggerAvailable, + undefined, + ) + } finally { + await harness.close() + } +}) + +// Value: protects=a stop in another file renames the slot after that file and closes the tab Codebook opened before, so moving across files and back leaves one slot tab, and each stop shows its own file's sealed bytes and label; fails_when=a tab per stop or per file stays open, the renamed slot serves the earlier file's bytes, or the label names the earlier stop; why_new=DS5's rename rule (Design 4, AC6); seam=none; no_claim=a tab the learner pinned or edited, which the rename never closes +test('a stop in another file renames the slot and closes the earlier slot tab', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + + // Act + await selectMoment(harness, history.studyId, 4) + const afterRename = slotTabs(harness) + const labelsAfterRename = slotLabels(harness) + await selectMoment(harness, history.studyId, 2) + + // Assert + assert.equal(afterRename.length, 1) + assert.match(afterRename[0]!, /\/Captured-theme-next\.ts$/) + assert.equal(await harness.readCapturedSource(afterRename[0]!), PLACEHOLDER) + assert.deepEqual(labelsAfterRename, [ + ' Recorded: src/theme-next.ts:1 · 0.30 s', + ]) + const back = slotTabs(harness) + assert.equal(back.length, 1) + assert.match(back[0]!, /\/Captured-theme\.ts$/) + assert.equal(await harness.readCapturedSource(back[0]!), THEME_TEXT) + assert.deepEqual(slotLabels(harness), [ + ' Recorded: src/theme.ts:1 · 0.20 s', + ]) + } finally { + await harness.close() + } +}) + +// Value: protects=a test replay that opens on its result (its saved position) shows the 4A placeholder in a slot named after its first verified stop's file and starts the debugger on the "Not recorded at this moment" thread; fails_when=the open shows no slot, names it after the test file although a stop verifies, or starts no debugger; why_new=Design 4's opening on an output or the result; seam=none; no_claim=a replay none of whose stops verifies, named after its test file (nodeSourceSlotName's unit test) +test('a test replay that opens on its result shows the placeholder slot named after its first verified stop’s file', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 3) + + // Act + await openReplayAt(harness, history.studyId, 3) + + // Assert + const tabs = slotTabs(harness) + assert.equal(tabs.length, 1) + assert.match(tabs[0]!, /\/Captured-theme\.ts$/) + assert.equal(await harness.readCapturedSource(tabs[0]!), PLACEHOLDER) + assert.deepEqual( + harness.historicalDebugPresentations.map(({ snapshot, label }) => ({ + snapshot, + label, + })), + [{ snapshot: undefined, label: 'Not recorded at this moment' }], + ) + } finally { + await harness.close() + } +}) + +// Value: protects=the selection order (EN8): while the next stop's debugger presentation still loads, the slot already holds that stop's bytes with no stopped line or label and the Study position stays on the earlier moment; once the debugger shows the stop, the slot's label and the Study position commit together; fails_when=the slot keeps the earlier stop's label beside the next stop's debugger, or the Study position moves before the debugger shows the stop; why_new=Design 4's order (old moment left first, slot text confirmed before the debugger, commit after it; AC6); seam=the workspace harness's held historical debug presentation (a slow debugger); no_claim=the native frames of the transition, which N49 part 7 reviews +test('while the next stop’s debugger still loads, the slot shows no earlier stop’s label and the Study position waits', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const held = harness.holdHistoricalDebugPresentation(true) + + // Act + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 4, + }) + await held.started + const slotDuringLoad = slotTabs(harness) + const labelsDuringLoad = slotLabels(harness) + const positionDuringLoad = lastView(harness)?.nodeHistoryPosition?.sequence + held.release() + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === 4, + 'the second stop commits', + 2_000, + ) + + // Assert + assert.equal(slotDuringLoad.length, 1) + assert.equal( + await harness.readCapturedSource(slotDuringLoad[0]!), + THEME_NEXT_TEXT, + ) + assert.deepEqual(labelsDuringLoad, []) + assert.equal(positionDuringLoad, 2) + assert.deepEqual(slotLabels(harness), [ + ' Recorded: src/theme-next.ts:1 · 0.30 s', + ]) + } finally { + await harness.close() + } +}) + +// Value: protects=the debugger is presented only once the slot's document shows the stop's bytes, so its frame never points at a line of earlier text; fails_when=the debugger presentation starts while the slot's document still shows the placeholder; why_new=Design 4's order, step 2 before step 3 (slotReady, AC6); seam=the workspace harness's held delivery of a provider result to the open slot document (a delay between the slot's bytes and the frames); no_claim=how long the native editor takes to apply a provider result +test('the debugger is presented at a stop only after the slot’s document shows that stop’s bytes', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 1) + await openReplayAt(harness, history.studyId, 1) + const presentationsBefore = harness.historicalDebugPresentations.length + const heldUpdate = harness.holdNextSourceUpdate() + + // Act + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 2, + }) + await heldUpdate.started + const presentationsWhileHeld = harness.historicalDebugPresentations.length + heldUpdate.release() + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === 2, + 'the stop commits', + 2_000, + ) + + // Assert + assert.equal(presentationsWhileHeld, presentationsBefore) + assert.equal( + harness.historicalDebugPresentations.at(-1)?.label, + 'Recorded test stop 1 · src/theme.ts:1', + ) + } finally { + await harness.close() + } +}) + +// Value: protects=the reader position is written after the commit: a slow position write never holds the shown moment back; fails_when=the Study position waits for the write; why_new=Design 4's order (the position persisted after the commit, never awaited before it; AC6); seam=the history store's position write, held by the test; no_claim=the write's outcome, which the position tests cover +test('a slow reader position write does not hold the selected moment back', async (context) => { + // Arrange + const harness = await workspaceHarness() + let releaseWrite = (): void => {} + // The held writes, awaited before the harness removes its folders, so no late write lands in a folder being removed. + const heldWrites: Promise[] = [] + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await openReplayAt(harness, history.studyId, 2) + const writeHeld = new Promise((resolve) => { + releaseWrite = resolve + }) + const save = store.saveReaderPosition.bind(store) + context.mock.method( + store, + 'saveReaderPosition', + (...args: Parameters) => { + const write = writeHeld.then(() => save(...args)) + heldWrites.push(write) + return write + }, + ) + + // Act + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 3, + }) + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === 3, + 'the result commits while its position write is held', + 2_000, + ) + + // Assert + assert.equal(lastView(harness)?.nodeHistoryPosition?.type, 'result') + } finally { + releaseWrite() + await Promise.allSettled(heldWrites) + context.mock.restoreAll() + await harness.close() + } +}) + +// Value: protects=two quick selections show only the last one: the first selection, overtaken while its debugger presentation loads, commits nothing, and the slot, its label and the Study position all show the last moment; fails_when=the overtaken stop's label, slot bytes or Study position appear after the later selection; why_new=Design 4's generations (rapid seeks, AC6); seam=the workspace harness's held historical debug presentation; no_claim=Play's own pacing (the timeline and pacing tests) +test('a stop selection overtaken by an output selection leaves only the output on every surface', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const held = harness.holdHistoricalDebugPresentation(true) + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 4, + }) + await held.started + + // Act + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 3, + }) + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === 3, + 'the output commits', + 2_000, + ) + held.reject(new Error('Historical debugger presentation was superseded.')) + await new Promise((resolve) => setImmediate(resolve)) + + // Assert + assert.equal(lastView(harness)?.nodeHistoryPosition?.sequence, 3) + const tabs = slotTabs(harness) + assert.equal(tabs.length, 1) + assert.equal(await harness.readCapturedSource(tabs[0]!), PLACEHOLDER) + assert.deepEqual(slotLabels(harness), []) + assert.equal(lastView(harness)?.errors.length, 0) + } finally { + await harness.close() + } +}) + +// Value: protects=a recorded-source slot that cannot open is told in the Study pane with the stop's number and the cause, written once to Output › Codebook, and leaves the moment selected with no stop on the debugger; Retry opens the slot again and retires the row; fails_when=the failure is silent, names no stop, writes no entry, keeps the earlier moment, or Retry leaves the row or renders a saved study's source instead; why_new=S2-1 for the slot (Design 4, the String catalog's open failure, AC17); seam=the workspace harness's injected failure of a non-file document open; no_claim=a slot that opens but whose bytes do not show within the bound (the same row, by NODE_HISTORY_TRANSITION_BOUND_MS) +test('a recorded-source slot that cannot open is told with its stop and cause, and Retry opens it again', async () => { + // Arrange + const harness = await workspaceHarness() + const logged: CodebookDiagnostic[] = [] + harness.reader.diagnostics = { + log: (entry) => logged.push(entry), + show: () => undefined, + } + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 1) + await openReplayAt(harness, history.studyId, 1) + harness.failCurrentSourceOpen() + + // Act + await selectMoment(harness, history.studyId, 2) + const failedView = lastView(harness)! + harness.restoreCurrentSourceOpen() + await harness.reader.action('retry') + + // Assert + assert.equal(failedView.nodeHistoryPosition?.sequence, 2) + assert.equal(failedView.nodeHistoryPosition?.debuggerAvailable, false) + assert.ok( + failedView.errors.includes( + 'Codebook could not open the recorded source of stop 1: Injected current source open failure. Details: Output › Codebook.', + ), + ) + assert.deepEqual( + logged.map(({ surface, studyId, profile, cause }) => ({ + surface, + studyId, + profile, + cause, + })), + [ + { + surface: 'open:recorded-source', + studyId: history.studyId, + profile: 'node-test', + cause: 'Injected current source open failure', + }, + ], + ) + assert.equal(lastView(harness)?.errors.length, 0) + assert.equal(lastView(harness)?.nodeHistoryPosition?.sequence, 2) + assert.equal( + await harness.readCapturedSource(slotTabs(harness)[0]!), + THEME_TEXT, + ) + } finally { + await harness.close() + } +}) + +// Value: protects=a slot whose document never shows the selected stop's bytes within the bound is told as an open failure with Retry, and the debugger shows no stop of the earlier moment; fails_when=the selection waits forever, presents the debugger at stale text, or commits silently without the history-source row; why_new=the bound path of EN8 step 2 (the open-failure test covers only a failing open); seam=the workspace harness's held delivery of a provider result to the open slot document; no_claim=the real editor's delivery latency +test('a slot that does not show a stop’s bytes within the bound is told as an open failure and presents no stop', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 1) + await openReplayAt(harness, history.studyId, 1) + const presentationsBefore = harness.historicalDebugPresentations.length + const heldUpdate = harness.holdNextSourceUpdate() + + // Act + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 2, + }) + await heldUpdate.started + await waitUntil( + () => + lastView(harness)?.nodeHistoryPosition?.sequence === 2 && + (lastView(harness)?.errors.length ?? 0) > 0, + 'the selection reports that the slot did not show its bytes', + 4_000, + ) + heldUpdate.release() + + // Assert + assert.equal( + lastView(harness)?.errors.includes( + 'Codebook could not open the recorded source of stop 1: Timed out waiting for the recorded source of this moment. Details: Output › Codebook.', + ), + true, + ) + assert.equal( + lastView(harness)?.nodeHistoryPosition?.debuggerAvailable, + false, + ) + assert.equal( + harness.historicalDebugPresentations.length, + presentationsBefore, + ) + } finally { + await harness.close() + } +}) + +// Value: protects=leaving a test replay for Live closes the recorded-source slot Codebook opened; fails_when=the slot's tab stays after its replay is retired; why_new=Design 4 (`retireNodeHistorySelection` closes the slot); seam=none; no_claim=a slot tab the learner pinned, which stays +test('returning to Live closes the test replay’s recorded-source slot', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveOneStopNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const openedSlots = slotTabs(harness) + + // Act + await harness.reader['retireNodeHistorySelection']() + + // Assert + assert.equal(openedSlots.length, 1) + assert.deepEqual(slotTabs(harness), []) + } finally { + await harness.close() + } +}) + +// Value: protects=a rename the learner overtakes before the renamed slot's document opens still leaves one slot tab, the newer moment's, with that moment's placeholder; fails_when=the earlier file's slot tab stays open beside the newer slot because the overtaken rename never reached its close; why_new=PR-B2 /ship Step 9 state-machines review (critical: an orphan slot tab, cell verified-stop × overtaken during a rename); seam=the workspace harness's held native open of the renamed slot's document; no_claim=a slot tab the learner pinned or edited, which stays +test('a rename overtaken before its slot opens leaves one slot tab, the newer moment’s', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const renamedSlot = slotTabs(harness)[0]!.replace( + /Captured-theme\.ts$/, + 'Captured-theme-next.ts', + ) + const heldOpen = harness.holdNextSource({ uri: renamedSlot }) + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 4, + }) + await heldOpen.started + + // Act + await selectMoment(harness, history.studyId, 3) + heldOpen.release() + await new Promise((resolve) => setImmediate(resolve)) + + // Assert + assert.deepEqual(slotTabs(harness), [renamedSlot]) + assert.equal(await harness.readCapturedSource(renamedSlot), PLACEHOLDER) + assert.equal(lastView(harness)?.nodeHistoryPosition?.sequence, 3) + } finally { + await harness.close() + } +}) + +// Value: protects=a rename whose slot cannot open leaves the earlier file's slot tab only until the next moment shows its slot, which closes it, so a failed rename never keeps a second slot tab; fails_when=the earlier slot tab stays beside the renamed slot after the next moment, because the failed rename never closed it and the next moment kept the slot's name; why_new=PR-B2 /ship Step 9 state-machines review (critical: an orphan slot tab, cell failed open × rename); seam=the workspace harness's injected failure of a non-file document open; no_claim=the failure row itself (the open-failure test) +test('a rename whose slot cannot open leaves no earlier slot tab once the next moment shows', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const earlierSlot = slotTabs(harness)[0]! + harness.failCurrentSourceOpen() + await selectMoment(harness, history.studyId, 4) + harness.restoreCurrentSourceOpen() + + // Act + await selectMoment(harness, history.studyId, 3) + + // Assert + const tabs = slotTabs(harness) + assert.equal(tabs.length, 1) + assert.notEqual(tabs[0], earlierSlot) + assert.match(tabs[0]!, /\/Captured-theme-next\.ts$/) + assert.equal(await harness.readCapturedSource(tabs[0]!), PLACEHOLDER) + } finally { + await harness.close() + } +}) + +// Value: protects=returning to Live while a renamed slot's document still opens closes every slot tab of the retired replay, the earlier file's included; fails_when=the retire closes only the renamed slot, which had no tab yet, and the earlier file's slot tab stays open with no replay behind it; why_new=PR-B2 /ship Step 9 state-machines review (critical: an orphan slot tab, retire during a pending rename); seam=the workspace harness's held native open of the renamed slot's document; no_claim=a slot tab the learner pinned or edited, which stays +test('returning to Live while a renamed slot still opens closes every slot tab of the replay', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const renamedSlot = slotTabs(harness)[0]!.replace( + /Captured-theme\.ts$/, + 'Captured-theme-next.ts', + ) + const heldOpen = harness.holdNextSource({ uri: renamedSlot }) + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 4, + }) + await heldOpen.started + + // Act + await harness.reader['retireNodeHistorySelection']() + heldOpen.release() + await new Promise((resolve) => setImmediate(resolve)) + + // Assert + assert.deepEqual(slotTabs(harness), []) + } finally { + await harness.close() + } +}) + +/** + * Reads what an editor tab shows: a text document's URI, a webview's view type, or its label. + * @param tab - A tab of the fake editor. + * @returns The URI, the view type or the label. + * @example tabIdentity(tab) // => 'codebook-source://…/node-history-slot//Captured-theme.ts' + */ +function tabIdentity(tab: Harness['groups'][number]['tabs'][number]): string { + const input = tab.input as + { uri?: { toString(): string }; viewType?: string } | undefined + return input?.uri?.toString() ?? input?.viewType ?? tab.label +} + +// Value: protects=a slot renamed for a stop in another file opens in the group that held the earlier slot before Codebook closes the earlier tab, so a source group the slot alone filled stays and no other pane's group receives the slot; fails_when=the earlier tab closes first, the editor (with `workbench.editor.closeEmptyGroups` on) removes the emptied group, and the renamed slot opens in another group; why_new=PR-B2's own OCR review (the rename's order); seam=the workspace harness's native layout with its closeEmptyGroups model (useNativeLayout, closeDisposedPanelTabsLater) and the test taking the article's source tab out of the slot's group, so the slot fills it alone; no_claim=a group the learner locked or pinned +test('a slot renamed for another file stays in its own group when it alone filled that group', async () => { + // Arrange + const harness = await workspaceHarness() + try { + harness.useNativeLayout({ orientation: 0, groups: [{ size: 980 }] }) + harness.closeDisposedPanelTabsLater() + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const slotGroup = harness.groups.find((group) => + group.tabs.some((tab) => + tabIdentity(tab).includes('/node-history-slot/'), + ), + )! + // The slot alone fills its group: the article's source tab that the Study's open also showed there is taken out. + const slotTab = slotGroup.tabs.find((tab) => + tabIdentity(tab).includes('/node-history-slot/'), + )! + slotGroup.tabs.splice(0, slotGroup.tabs.length, slotTab) + slotGroup.activeTab = slotTab + const groupsBefore = harness.groups.map((group) => + group.tabs.map(tabIdentity), + ) + + // Act + await selectMoment(harness, history.studyId, 4) + + // Assert + const groupsAfter = harness.groups.map((group) => + group.tabs.map(tabIdentity), + ) + assert.equal(groupsAfter.length, groupsBefore.length) + const slotGroupIndex = groupsBefore.findIndex((tabs) => + tabs.some((tab) => tab.includes('/node-history-slot/')), + ) + assert.equal(groupsAfter[slotGroupIndex]!.length, 1) + assert.match(groupsAfter[slotGroupIndex]![0]!, /\/Captured-theme-next\.ts$/) + } finally { + await harness.close() + } +}) + +// Value: protects=a slot tab of another replay (one an editor restart restored or an earlier replay left) is closed when the open replay shows its slot, so only the open replay's slot tab stays; fails_when=the close skips slot tabs of other study ids and the stale tab stays beside the slot; why_new=the unit test of isNodeSourceSlotPath covers the path only, no workspace test plants a foreign slot tab; seam=none (the fake editor's showTextDocument as the learner's restored tab); no_claim=a slot tab the learner pinned or edited, which stays +test('a slot tab of another replay is closed once the open replay shows its slot', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const history = await saveTwoFileNodeHistory( + harness.service.nodeHistoryStore!, + ) + await openReplayAt(harness, history.studyId, 2) + const openSlot = slotTabs(harness)[0]! + const foreignSlot = openSlot.replace( + `/${history.studyId}/Captured-theme.ts`, + '/other-replay-study/Captured-old.ts', + ) + const parsed = new URL(foreignSlot) + await harness.editor.window.showTextDocument( + new harness.editor.Uri( + parsed.protocol.slice(0, -1), + parsed.host, + parsed.pathname, + ), + { viewColumn: 1, preserveFocus: true, preview: false }, + ) + assert.equal(slotTabs(harness).length, 2) + + // Act + await selectMoment(harness, history.studyId, 3) + + // Assert + assert.deepEqual(slotTabs(harness), [openSlot]) + } finally { + await harness.close() + } +}) + +// Value: protects=returning to Live after a slot that could not open leaves no slot tab and no recorded-source failure row in the Study pane; fails_when=the retire keeps the failed open's history-source row, which names a replay the learner left and offers a Retry that has nothing to retry; why_new=the open-failure test ends inside the replay, no test retires after a failure; seam=the workspace harness's injected failure of a non-file document open; no_claim=the Retry wording +test('returning to Live after a recorded-source slot failed to open leaves no failure row behind', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 1) + await openReplayAt(harness, history.studyId, 1) + harness.failCurrentSourceOpen() + await selectMoment(harness, history.studyId, 2) + harness.restoreCurrentSourceOpen() + assert.equal(lastView(harness)?.errors.length, 1) + + // Act + await harness.reader.action('return-current') + + // Assert + assert.deepEqual(slotTabs(harness), []) + assert.equal(lastView(harness)?.errors.length, 0) + } finally { + await harness.close() + } +}) + +// Value: protects=returning to Live from a moment that shows the placeholder (an output) closes the placeholder's slot tab; fails_when=the retire closes the slot tab only when it held a verified stop; why_new=the retire test starts from a verified stop; seam=none; no_claim=a slot tab the learner pinned or edited, which stays +test('returning to Live closes the recorded-source slot a placeholder moment showed', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 1) + await openReplayAt(harness, history.studyId, 1) + const openedSlots = slotTabs(harness) + + // Act + await harness.reader['retireNodeHistorySelection']() + + // Assert + assert.equal(openedSlots.length, 1) + assert.deepEqual(slotTabs(harness), []) + } finally { + await harness.close() + } +}) + +// Value: protects=returning to the shown moment that recorded no stop while a newer selection of a stop is still presenting that stop leaves the native debugger on no stop, so the stop's stack and values never stand beside a moment that recorded none (4A); fails_when=the return skips the leave because its moment is the committed one, and the debugger keeps the overtaken stop's frames; why_new=/ship Step 11 (Codex adversarial P1, Claude adversarial, Codex structured P2: the stale stack after a quick reversal); seam=the workspace harness's held historical debug presentation; no_claim=the native debugger's own drawing +test('returning to the shown output while a stop still presents leaves the debugger on no stop', async () => { + // Arrange + const harness = await workspaceHarness() + try { + const store = harness.service.nodeHistoryStore! + const history = await saveOneStopNodeHistory(store) + await store.saveReaderPosition(history.studyId, 1) + await openReplayAt(harness, history.studyId, 1) + const held = harness.holdHistoricalDebugPresentation(true) + harness.receiveContext({ + type: 'node-history-event', + revision: lastView(harness)!.revision, + studyId: history.studyId, + sequence: 2, + }) + await held.started + const invalidationsWhileStopPresents = + harness.historicalDebugInvalidations() + + // Act + await harness.reader['selectNodeHistoryEvent']( + harness.reader['selectedNodeHistory']!, + 1, + ) + held.reject(new Error('Historical debugger presentation was superseded.')) + await waitUntil( + () => lastView(harness)?.nodeHistoryPosition?.sequence === 1, + 'the output stays selected', + 2_000, + ) + + // Assert + assert.equal( + harness.historicalDebugInvalidations(), + invalidationsWhileStopPresents + 1, + ) + assert.equal( + harness.historicalDebugInvalidationLabels().at(-1), + 'Not recorded at this moment', + ) + assert.equal( + await harness.readCapturedSource(slotTabs(harness)[0]!), + PLACEHOLDER, + ) + } finally { + await harness.close() + } +}) diff --git a/extension/src/ui/constants.ts b/extension/src/ui/constants.ts index 8076f57a2..e75f3bf83 100644 --- a/extension/src/ui/constants.ts +++ b/extension/src/ui/constants.ts @@ -205,7 +205,7 @@ body.moments-only[data-replay=true] #recording-transport{order:-1;position:stick /* The bottom panel is wide and short: the values hint and its button share one row there, so the button, 44 px high like the status row above it, stays inside a panel 180 px high. Every other part of the transport keeps a row of its own. */ body.moments-only #recording-transport{display:flex;flex-wrap:wrap;align-items:center}body.moments-only #recording-transport>*{flex:0 0 100%;min-width:0}body.moments-only #recording-transport>#playback-hint{flex:1 1 60%}body.moments-only #recording-transport>#playback-show-variables{flex:none;margin-left:12px} .playback-row{display:flex;gap:6px;align-items:center;flex-wrap:wrap}.playback-row button{min-height:32px;padding:4px 8px}.playback-row #playhead{flex:1;min-width:80px;width:auto;min-height:32px}.playback-row #playback-position{font-size:12px;white-space:nowrap}#playback-show-variables{margin:6px 0} -.timeline-track{position:relative;flex:1;min-width:100px;display:flex;flex-direction:column;align-items:stretch}.timeline-track #playhead{width:100%;flex:none}.timeline-track #history-coverage{position:relative;height:6px;margin:0 8px;overflow:hidden;background:var(--vscode-panel-border,#555)}.timeline-track .history-gap{position:absolute;top:0;bottom:0;background:repeating-linear-gradient(135deg,var(--vscode-editorWarning-foreground,#d7ba7d) 0 3px,transparent 3px 6px)}.timeline-track .history-stop{position:absolute;top:0;bottom:0;width:3px;background:var(--vscode-focusBorder,#007fd4)}#history-coverage-label{font-size:11px;line-height:1.2} +.timeline-track{position:relative;flex:1;min-width:100px;display:flex;flex-direction:column;align-items:stretch}.timeline-track #playhead{width:100%;flex:none}.timeline-track #history-coverage,.timeline-track .history-coverage{position:relative;height:6px;margin:0 8px;overflow:hidden;background:var(--vscode-panel-border,#555)}.timeline-track .history-gap{position:absolute;top:0;bottom:0;background:repeating-linear-gradient(135deg,var(--vscode-editorWarning-foreground,#d7ba7d) 0 3px,transparent 3px 6px)}.timeline-track .history-stop{position:absolute;top:0;bottom:0;width:3px;background:var(--vscode-focusBorder,#007fd4)}#history-coverage-label,.history-coverage-label{font-size:11px;line-height:1.2} .playback-status-row{display:flex;justify-content:space-between;gap:12px;align-items:start;font-size:12px}.playback-status-row summary{padding:13px 0}.playback-status-row>#recording-status{margin-top:13px}body.moments-only .playback-status-row{flex-wrap:wrap;row-gap:0}body.moments-only #application-covered-remedy{order:1;flex-basis:100%}.playback-status-row p{margin:8px 0}#playback-pending:empty,#playback-reason:empty{display:none}#playback-hint:empty,#node-history-hint:empty{margin:0}#playback-pending,#playback-reason,#playback-hint,#node-history-hint{margin:6px 0 0;font-size:12px} /* The live strip and the replay transport stay in the page while this pane does not show them, so the status regions inside exist before their first text. Each shows nothing and takes no room exactly while its own status is empty: #runtime for the strip, #recording-status for the transport. */ .live-strip:has(>#runtime:empty),#recording-transport:has(#recording-status:empty){padding:0;border:0}.live-strip:has(>#runtime:empty)>:not(#runtime),#recording-transport:has(#recording-status:empty)>:not(.playback-status-row,[role=status]),#recording-transport:has(#recording-status:empty) #playback-options{display:none}.playback-status-row>#recording-status:empty{margin:0} diff --git a/extension/src/ui/studyHtml.ts b/extension/src/ui/studyHtml.ts index e83dd6d70..67ff231ea 100644 --- a/extension/src/ui/studyHtml.ts +++ b/extension/src/ui/studyHtml.ts @@ -210,7 +210,7 @@ export function studyHtml(kind: 'context' | 'moments'): string {
Study controls

Ask your editor agent to explain a code path in the open repository.

Workspace panes

-

${STUDY_UI_OPTIONS.testReplay.heading}

Test journal playback
Events
+

${STUDY_UI_OPTIONS.testReplay.heading}

Test journal playback
Events

Observed moments

Select a captured observation or open Recording to follow its time.

Saved studies

${markupOnlyIn(kind, 'context', valuesHint)}
History coverage unknown
Playback details

Recorded history only. Playback does not run application code or mark understanding.

${markupOnlyIn(kind, 'moments', valuesHint)}
@@ -345,6 +345,103 @@ function studyClient( } const seconds = (elapsed: number) => `${(elapsed / options.secondMs).toFixed(2)} s` + /** The range a transport's coverage strip draws: its gaps where source and debugger were not recorded and its recorded stops. */ + type CoverageMarks = { + startMs: number + endMs: number + gaps: Array<{ startMs: number; endMs: number }> + recordedPoints: number[] + } + /** + * Draws a transport's coverage strip: striped spans where source and debugger were not recorded, a tick for each recorded stop, the legend and the strip's accessible name; called for the browser transport and the test replay transport, so both draw alike. + * @param coverage - The strip element, hidden when there is nothing to mark. + * @param label - The legend element beside the slider. + * @param marks - The range with its gaps and recorded stops, or `undefined` when no coverage is known. + * @param legends - The legend for a range with gaps, for one without, and for no known coverage. + * @example renderTimelineCoverage(strip, legend, { startMs: 0, endMs: 900, gaps: [{ startMs: 0, endMs: 900 }], recordedPoints: [420] }, legends) + */ + const renderTimelineCoverage = ( + coverage: HTMLElement, + label: HTMLElement, + marks: CoverageMarks | undefined, + legends: { + gapsLegend: string + noGapsLegend: string + unknownLegend: string + }, + ): void => { + coverage.hidden = !marks + label.textContent = marks + ? marks.gaps.length + ? legends.gapsLegend + : legends.noGapsLegend + : legends.unknownLegend + // Without known coverage the strip is emptied and says so. + if (!marks) { + coverage.replaceChildren() + delete coverage.dataset.signature + coverage.setAttribute( + 'aria-label', + 'Historical source and debugger coverage unknown', + ) + return + } + coverage.setAttribute('aria-label', describeCoverageMarks(marks)) + drawCoverageMarks(coverage, marks) + } + /** + * Names a coverage strip for assistive technology: how many gaps and recorded stops it marks, with their times; called by {@link renderTimelineCoverage}. + * @param marks - The range with its gaps and recorded stops. + * @returns The strip's accessible name. + * @example describeCoverageMarks({ startMs: 0, endMs: 900, gaps: [{ startMs: 0, endMs: 900 }], recordedPoints: [420] }) // => '1 source/debugger history gap: 0.00 s–0.90 s; 1 recorded stop: 0.42 s' + */ + const describeCoverageMarks = (marks: CoverageMarks): string => { + const gapTimes = marks.gaps + .map((gap) => `${seconds(gap.startMs)}–${seconds(gap.endMs)}`) + .join(', ') + const stopTimes = marks.recordedPoints.map(seconds).join(', ') + return `${marks.gaps.length} source/debugger history gap${marks.gaps.length === 1 ? '' : 's'}${gapTimes ? `: ${gapTimes}` : ''}; ${marks.recordedPoints.length} recorded stop${marks.recordedPoints.length === 1 ? '' : 's'}${stopTimes ? `: ${stopTimes}` : ''}` + } + /** + * Draws a coverage strip's gap spans and stop ticks, once per distinct set of marks; called by {@link renderTimelineCoverage}. + * @param coverage - The strip element. + * @param marks - The range with its gaps and recorded stops. + * @example drawCoverageMarks(strip, { startMs: 0, endMs: 900, gaps: [], recordedPoints: [420] }) + */ + const drawCoverageMarks = ( + coverage: HTMLElement, + marks: CoverageMarks, + ): void => { + const signature = JSON.stringify([ + marks.startMs, + marks.endMs, + marks.gaps, + marks.recordedPoints, + ]) + // The same marks are not drawn again. + if (coverage.dataset.signature === signature) return + coverage.replaceChildren() + coverage.dataset.signature = signature + const durationMs = marks.endMs - marks.startMs + // Draw sealed-history gaps and exact recorded stops without changing the range input's seek semantics. + for (const gap of marks.gaps) { + const mark = document.createElement('span') + mark.className = 'history-gap' + mark.setAttribute('aria-hidden', 'true') + mark.style.left = `${((gap.startMs - marks.startMs) / durationMs) * options.timelineFullWidthPercent}%` + mark.style.width = `${((gap.endMs - gap.startMs) / durationMs) * options.timelineFullWidthPercent}%` + mark.title = `Not recorded at this moment · ${seconds(gap.startMs)}–${seconds(gap.endMs)}` + coverage.append(mark) + } + for (const positionMs of marks.recordedPoints) { + const mark = document.createElement('span') + mark.className = 'history-stop' + mark.setAttribute('aria-hidden', 'true') + mark.style.left = `${((positionMs - marks.startMs) / durationMs) * options.timelineFullWidthPercent}%` + mark.title = `Recorded source and debugger · ${seconds(positionMs)}` + coverage.append(mark) + } + } const playback = ( action: 'play' | 'pause' | 'seek', positionMs?: number, @@ -2195,6 +2292,28 @@ function studyClient( message.nodeHistoryPlayback, !message.nodeHistory || replaying, ) + renderTestReplayTimeline(section, unavailable) + } + /** + * Draws the test replay slider's marks, the whole range unrecorded with a tick at each verified stop, and its legend; called by {@link renderTestReplayTransport}. + * @param section - The section's worded view, which carries the timeline of the shown replay. + * @param unavailable - Whether no test replay is shown: none, a browser recording shown, or the bottom panel held by a browser replay; the marks belong to the shown replay only. + * @example renderTestReplayTimeline(message.nodeHistorySection, false) + */ + const renderTestReplayTimeline = ( + section: StudyViewMessage['nodeHistorySection'], + unavailable: boolean, + ): void => { + renderTimelineCoverage( + element('node-history-coverage'), + element('node-history-coverage-label'), + unavailable ? undefined : section?.timeline, + { + gapsLegend: options.testReplay.timelineLegend, + noGapsLegend: options.testReplay.timelineLegend, + unknownLegend: '', + }, + ) } /** * Enables Previous stop, Next stop, Previous event and Next event where a move exists; called by {@link renderTestReplayTransport}. @@ -3018,64 +3137,26 @@ function studyClient( : `${seconds(recording.presentedMs)} presented${range?.endKnown === false ? '; recording end unknown' : ''}`, ) } - const coverage = element('history-coverage') const mapped = timeline.status === 'mapped' && range && range.endMs > range.startMs - coverage.hidden = !mapped - text( - 'history-coverage-label', + renderTimelineCoverage( + element('history-coverage'), + element('history-coverage-label'), mapped - ? timeline.gaps.length - ? 'Striped: source/debugger not recorded · ticks: recorded stops' - : 'Source/debugger history recorded across this range' - : 'Historical source/debugger coverage unknown', + ? { + startMs: range.startMs, + endMs: range.endMs, + gaps: timeline.gaps, + recordedPoints: timeline.recordedPoints, + } + : undefined, + { + gapsLegend: + 'Striped: source/debugger not recorded · ticks: recorded stops', + noGapsLegend: 'Source/debugger history recorded across this range', + unknownLegend: 'Historical source/debugger coverage unknown', + }, ) - if (mapped) { - const signature = JSON.stringify([ - range.startMs, - range.endMs, - timeline.gaps, - timeline.recordedPoints, - ]) - const gapTimes = timeline.gaps - .map((gap) => `${seconds(gap.startMs)}–${seconds(gap.endMs)}`) - .join(', ') - const stopTimes = timeline.recordedPoints.map(seconds).join(', ') - coverage.setAttribute( - 'aria-label', - `${timeline.gaps.length} source/debugger history gap${timeline.gaps.length === 1 ? '' : 's'}${gapTimes ? `: ${gapTimes}` : ''}; ${timeline.recordedPoints.length} recorded stop${timeline.recordedPoints.length === 1 ? '' : 's'}${stopTimes ? `: ${stopTimes}` : ''}`, - ) - if (coverage.dataset.signature !== signature) { - coverage.replaceChildren() - coverage.dataset.signature = signature - const durationMs = range.endMs - range.startMs - // Draw sealed-history gaps and exact recorded stops without changing the range input's seek semantics. - for (const gap of timeline.gaps) { - const mark = document.createElement('span') - mark.className = 'history-gap' - mark.setAttribute('aria-hidden', 'true') - mark.style.left = `${((gap.startMs - range.startMs) / durationMs) * options.timelineFullWidthPercent}%` - mark.style.width = `${((gap.endMs - gap.startMs) / durationMs) * options.timelineFullWidthPercent}%` - mark.title = `Not recorded at this moment · ${seconds(gap.startMs)}–${seconds(gap.endMs)}` - coverage.append(mark) - } - for (const positionMs of timeline.recordedPoints) { - const mark = document.createElement('span') - mark.className = 'history-stop' - mark.setAttribute('aria-hidden', 'true') - mark.style.left = `${((positionMs - range.startMs) / durationMs) * options.timelineFullWidthPercent}%` - mark.title = `Recorded source and debugger · ${seconds(positionMs)}` - coverage.append(mark) - } - } - } else { - coverage.replaceChildren() - delete coverage.dataset.signature - coverage.setAttribute( - 'aria-label', - 'Historical source and debugger coverage unknown', - ) - } } const item = model.progressByItem.find( (value) => value.id === model.selection.itemId, diff --git a/extension/src/utils/awaitDocumentSettled.ts b/extension/src/utils/awaitDocumentSettled.ts new file mode 100644 index 000000000..28961998b --- /dev/null +++ b/extension/src/utils/awaitDocumentSettled.ts @@ -0,0 +1,69 @@ +import { waitUntil } from '../runtimeSupport/utils/waitUntil' + +/** The part of the editor's workspace API {@link awaitDocumentSettled} listens to: its text document change event. */ +type DocumentChangeEvent = ( + listener: (event: { document: { uri: { toString(): string } } }) => void, +) => { dispose(): void } + +/** + * Waits until a condition about one open document holds, checked at each change of that document and on a bounded poll, so a provider result that reached the document before the subscription still settles the wait. + * Called by {@link StudyWorkspace} while a captured source view takes its new bytes and while a test replay's recorded-source slot shows a moment's bytes. + * @param onDidChangeTextDocument - The editor's text document change event. + * @param uri - The document whose changes wake the check. + * @param settled - Says whether the wait is over; a throw ends the wait with that error (a superseded or closed reader). + * @param description - What is waited for, named in the timeout. + * @param timeoutMs - The wait's bound. + * @param options - `signal` ends the wait through `settled`'s own check when it aborts; `afterSubscribe` runs once the change listener is in place (to notify the document's provider). + * @returns Once `settled` answers `true`. + * @throws What `settled` throws, or a timeout naming `description`. + * @example await awaitDocumentSettled(vscode.workspace.onDidChangeTextDocument, uri.toString(), () => document.getText() === text, 'the recorded source of this moment', 1_000) + */ +export function awaitDocumentSettled( + onDidChangeTextDocument: DocumentChangeEvent, + uri: string, + settled: () => boolean, + description: string, + timeoutMs: number, + { + signal, + afterSubscribe, + }: { signal?: AbortSignal; afterSubscribe?: () => void } = {}, +): Promise { + return new Promise((resolve, reject) => { + const observation = new AbortController() + let finished = false + const finish = (failure?: { cause: unknown }): void => { + if (finished) return + finished = true + subscription.dispose() + observation.abort() + signal?.removeEventListener('abort', check) + if (failure) reject(failure.cause) + else resolve() + } + const check = (): void => { + try { + if (settled()) finish() + } catch (error) { + finish({ cause: error }) + } + } + const subscription = onDidChangeTextDocument((event) => { + // Another document's edit cannot settle this one. + if (event.document.uri.toString() === uri) check() + }) + signal?.addEventListener('abort', check, { once: true }) + // Close and newer intent may emit no document event; the bounded poll observes them. + void waitUntil( + () => { + check() + return finished + }, + description, + timeoutMs, + observation.signal, + ).catch((error: unknown) => finish({ cause: error })) + afterSubscribe?.() + check() + }) +} diff --git a/extension/src/utils/describeNodeRecordedSource.ts b/extension/src/utils/describeNodeRecordedSource.ts new file mode 100644 index 000000000..6fc7de3c3 --- /dev/null +++ b/extension/src/utils/describeNodeRecordedSource.ts @@ -0,0 +1,68 @@ +import { basename } from 'node:path' + +import { formatEventSeconds } from './formatEventSeconds' + +/** + * The fixed words of a test replay's recorded-source slot and its debugger thread, the String catalog of plan version 7 (DS5, DS14); words that hold a value are worded by {@link describeNodeRecordedSource}. + * The placeholder is the slot's whole text before the first stop, at an output, at the result and at a stop whose source does not verify (4A). The slot is named after a JavaScript or TypeScript file, so its placeholder and loading text are line comments: as plain sentences the editor's language service reported them as problems of the learner's workspace (the source-slot spike in VS Code, 2026-10-22). + */ +export const NODE_RECORDED_SOURCE_TEXT = { + placeholder: + '// Recorded source · Not recorded at this moment\n// The test journal holds no source state for this moment.\n', + loading: '// Loading recorded source…\n', + notRecordedThread: 'Not recorded at this moment', +} as const + +/** What a test replay's recorded-source slot or its debugger says, keyed by surface and value. */ +export type NodeRecordedSourceMessage = + | { + /** The end-of-line label at a verified stop's stopped line. */ + kind: 'label' + path: string + line: number + elapsedMs: number + } + | { + /** The replay debugger's thread at a verified stop. */ + kind: 'thread' + stop: number + path: string + line: number + } + | { + /** The Study row of a slot that cannot open. */ + kind: 'open-failed' + stop?: number + cause: string + } + | { + /** The slot's tab title, named after the stop's source file. */ + kind: 'tab-title' + path: string + } + +/** + * Words one recorded-source message of a test replay; {@link StudyWorkspace} calls it for the slot's label and tab, the replay debugger's thread and the slot's open failure. + * @param message - The surface and its values; `stop` is 1-based. + * @returns The catalog's sentence with the values filled in. + * @example + * describeNodeRecordedSource({ kind: 'label', path: 'src/jobs.ts', line: 12, elapsedMs: 1234 }) // => 'Recorded: src/jobs.ts:12 · 1.23 s' + * describeNodeRecordedSource({ kind: 'thread', stop: 2, path: 'src/jobs.ts', line: 12 }) // => 'Recorded test stop 2 · src/jobs.ts:12' + * describeNodeRecordedSource({ kind: 'tab-title', path: 'src/jobs.ts' }) // => 'Captured-jobs.ts' + */ +export function describeNodeRecordedSource( + message: NodeRecordedSourceMessage, +): string { + switch (message.kind) { + case 'label': + return `Recorded: ${message.path}:${message.line} · ${formatEventSeconds(message.elapsedMs)} s` + case 'thread': + return `Recorded test stop ${message.stop} · ${message.path}:${message.line}` + case 'open-failed': + return message.stop === undefined + ? `Codebook could not open the recorded source: ${message.cause}. Details: Output › Codebook.` + : `Codebook could not open the recorded source of stop ${message.stop}: ${message.cause}. Details: Output › Codebook.` + case 'tab-title': + return `Captured-${basename(message.path)}` + } +} diff --git a/extension/src/utils/describeNodeTestReplay.ts b/extension/src/utils/describeNodeTestReplay.ts index 6c5808860..9dc76b431 100644 --- a/extension/src/utils/describeNodeTestReplay.ts +++ b/extension/src/utils/describeNodeTestReplay.ts @@ -1,6 +1,7 @@ -import { MILLISECONDS_PER_SECOND } from '../constants' import type { NodeTestHistorySummary } from '../nodeTestHistoryStore' +import { formatEventSeconds } from './formatEventSeconds' + /** * The fixed words of a test replay's surfaces, the String catalog of plan version 7 (DS18); the Study pane receives them through {@link STUDY_UI_OPTIONS}, as its client code imports nothing, and the Application pane through {@link projectNodeTestApplication} and {@link testOutputHtml}. * Words that hold a value are worded by {@link describeNodeTestReplay}. @@ -32,6 +33,9 @@ export const NODE_TEST_REPLAY_TEXT = { play: 'Play', pause: 'Pause', stepDetails: 'Step details', + /** The slider's legend: a test journal records when a stop paused, not when the run resumed. */ + timelineLegend: + 'Ticks mark recorded stops; source and debugger are not recorded between them.', noSelection: 'Select an event to move through the recorded test history.', chooseReplay: 'Choose a test replay from Saved studies to step through its output and debugger stops.', @@ -130,8 +134,8 @@ export function describeNodeTestReplay(message: NodeTestReplayMessage): string { return positionWords(message.event, message.elapsedMs) case 'step-action': return message.event.type === 'stop' - ? `Inspect stop ${message.event.index + 1} · ${seconds(message.elapsedMs)} s` - : `Inspect ${message.event.type} · ${seconds(message.elapsedMs)} s` + ? `Inspect stop ${message.event.index + 1} · ${formatEventSeconds(message.elapsedMs)} s` + : `Inspect ${message.event.type} · ${formatEventSeconds(message.elapsedMs)} s` case 'events': return `Events (${message.count})` default: @@ -150,15 +154,15 @@ function applicationWords( ): string { switch (message.kind) { case 'application-time': - return `Recorded test output · ${seconds(message.elapsedMs)} s` + return `Recorded test output · ${formatEventSeconds(message.elapsedMs)} s` case 'application-test': return testName(message.test) case 'application-name': return message.elapsedMs === undefined ? `Recorded test output · ${testName(message.test)}` - : `Recorded test output · ${testName(message.test)} · ${seconds(message.elapsedMs)} s` + : `Recorded test output · ${testName(message.test)} · ${formatEventSeconds(message.elapsedMs)} s` case 'application-region': - return `Recorded test output up to ${seconds(message.elapsedMs)} s` + return `Recorded test output up to ${formatEventSeconds(message.elapsedMs)} s` case 'application-cut': return `… ${message.characters} earlier characters not shown${message.startsMidLine ? '; the first line below is cut' : ''}` case 'application-inspector': @@ -178,10 +182,10 @@ function positionWords( elapsedMs: number, ): string { if (event.type === 'stop') - return `Stop ${event.index + 1} of ${event.stopCount} · ${seconds(elapsedMs)} s` + return `Stop ${event.index + 1} of ${event.stopCount} · ${formatEventSeconds(elapsedMs)} s` return event.type === 'result' - ? `Result · ${event.verdict} · ${seconds(elapsedMs)} s` - : `Output · ${seconds(elapsedMs)} s` + ? `Result · ${event.verdict} · ${formatEventSeconds(elapsedMs)} s` + : `Output · ${formatEventSeconds(elapsedMs)} s` } /** @@ -207,13 +211,3 @@ function studyStatus( function testName(test: NodeTestReplayTestName): string { return [test.testFile, ...(test.testTitles ?? [])].join(' › ') } - -/** - * Writes an event's time as the String catalog's ``: seconds since the run started, with two decimals. - * @param elapsedMs - The event's elapsed milliseconds. - * @returns The seconds. - * @example seconds(1234) // => '1.23' - */ -function seconds(elapsedMs: number): string { - return (elapsedMs / MILLISECONDS_PER_SECOND).toFixed(2) -} diff --git a/extension/src/utils/formatEventSeconds.ts b/extension/src/utils/formatEventSeconds.ts new file mode 100644 index 000000000..89b046693 --- /dev/null +++ b/extension/src/utils/formatEventSeconds.ts @@ -0,0 +1,14 @@ +import { MILLISECONDS_PER_SECOND } from '../constants' + +/** + * Writes a recorded event's time as the String catalog's ``: seconds since the run started, paused time included, with two decimals. + * Called by {@link describeNodeTestReplay} and {@link describeNodeRecordedSource} for every test replay surface that names an event's time. + * @param elapsedMs - The event's elapsed milliseconds. + * @returns The seconds with two decimals, without the unit. + * @example + * formatEventSeconds(1234) // => '1.23' + * formatEventSeconds(0) // => '0.00' + */ +export function formatEventSeconds(elapsedMs: number): string { + return (elapsedMs / MILLISECONDS_PER_SECOND).toFixed(2) +} diff --git a/extension/src/utils/isNodeSourceSlotPath.ts b/extension/src/utils/isNodeSourceSlotPath.ts new file mode 100644 index 000000000..e5b9ccd35 --- /dev/null +++ b/extension/src/utils/isNodeSourceSlotPath.ts @@ -0,0 +1,14 @@ +import { NODE_SOURCE_SLOT_PATH_ROOT } from '../constants' + +/** + * Tells whether a captured-source document path names a test replay's recorded-source slot ({@link nodeSourceSlotPath}), whatever replay or file it was named after. + * Called by {@link StudyWorkspace} when it serves a slot's document and when it closes every slot tab but the one a moment shows, so a slot tab left by an overtaken or failed rename, a retired replay or an earlier session never stays. + * @param path - The path of a `codebook-source` URI. + * @returns `true` for a path under the slot root, `false` for any other captured source. + * @example + * isNodeSourceSlotPath('/node-history-slot/3f1c…/Captured-scheduler.ts') // => true + * isNodeSourceSlotPath('/node-history/3f1c…/2/') // => false + */ +export function isNodeSourceSlotPath(path: string): boolean { + return path.split('/').filter(Boolean)[0] === NODE_SOURCE_SLOT_PATH_ROOT +} diff --git a/extension/src/utils/nodeHistoryPlaybackController.ts b/extension/src/utils/nodeHistoryPlaybackController.ts index b97d7bde0..96875f39b 100644 --- a/extension/src/utils/nodeHistoryPlaybackController.ts +++ b/extension/src/utils/nodeHistoryPlaybackController.ts @@ -1,4 +1,7 @@ -import { PLAYBACK_TICK_INTERVAL_MS } from '../constants' +import { + NODE_HISTORY_PLAY_MAX_DWELL_MS, + PLAYBACK_TICK_INTERVAL_MS, +} from '../constants' export interface NodeHistoryPlaybackEvent { sequence: number @@ -19,7 +22,6 @@ export class NodeHistoryPlaybackController { private events: NodeHistoryPlaybackEvent[] = [] private selectedIndex = -1 private mode: 'paused' | 'playing' = 'paused' - private anchorElapsedMs = 0 private anchorWallMs = 0 private timer?: ReturnType private pending?: Promise @@ -108,7 +110,6 @@ export class NodeHistoryPlaybackController { ) return this.mode = 'playing' - this.anchorElapsedMs = this.events[this.selectedIndex]!.elapsedMs this.anchorWallMs = this.clock() if (!this.dependencies.manualTicks) { this.timer = setInterval(() => { @@ -155,24 +156,26 @@ export class NodeHistoryPlaybackController { async tick(): Promise { if (this.mode !== 'playing' || this.pending || this.selectedIndex < 0) return - const targetTime = - this.anchorElapsedMs + Math.max(0, this.clock() - this.anchorWallMs) const nextIndex = this.selectedIndex + 1 if (nextIndex >= this.events.length) { this.pause() return } - if (this.events[nextIndex]!.elapsedMs > targetTime) return - const generation = this.generation, - presentationStartedWallMs = this.clock() + // Each event waits its recorded spacing, never more than the dwell bound: the test ran unrecorded between stops, and Play does not idle through that time. + const recordedGapMs = + this.events[nextIndex]!.elapsedMs - + this.events[this.selectedIndex]!.elapsedMs + const dwellMs = Math.min(recordedGapMs, NODE_HISTORY_PLAY_MAX_DWELL_MS) + if (Math.max(0, this.clock() - this.anchorWallMs) < dwellMs) return + const generation = this.generation try { await this.present(nextIndex, generation) } catch (error) { this.pause() throw error } - // Waiting for native Run and Debug is a visible pause, not recorded test time; later output keeps its recorded spacing. - this.anchorWallMs += this.clock() - presentationStartedWallMs + // Waiting for native Run and Debug is a visible pause, not recorded test time: the next dwell starts when this event is on screen. + this.anchorWallMs = this.clock() if ( this.mode === 'playing' && this.selectedIndex === this.events.length - 1 diff --git a/extension/src/utils/nodeSourceSlotName.ts b/extension/src/utils/nodeSourceSlotName.ts new file mode 100644 index 000000000..8fcfe48ea --- /dev/null +++ b/extension/src/utils/nodeSourceSlotName.ts @@ -0,0 +1,26 @@ +import type { NodeTestHistoryIndex } from '../nodeTestHistorySchemas' + +import { nodeStopSourceMatches } from './nodeStopSourceMatches' + +/** + * Chooses the file a test replay's recorded-source slot is named after while it holds the placeholder and has no name yet: the file of the replay's first stop whose source verifies, so landing on that stop later does not rename the slot, else the test file; called by {@link StudyWorkspace.showNodeSourceSlot} when a replay opens on an output, the result or an unverified stop. + * @param history - The test replay. + * @returns A repository-relative path. + * @example + * nodeSourceSlotName(historyWithStopInScheduler) // => 'src/jobs/scheduler.ts' + * nodeSourceSlotName(historyWithoutVerifiedStop) // => 'src/jobs/scheduler.test.ts' + */ +export function nodeSourceSlotName(history: { + header: { + configuration: Pick< + NodeTestHistoryIndex['header']['configuration'], + 'testFile' + > + } + entries: NodeTestHistoryIndex['entries'] +}): string { + for (const entry of history.entries) + if (entry.type === 'stop' && nodeStopSourceMatches(entry)) + return entry.source.path + return history.header.configuration.testFile +} diff --git a/extension/src/utils/nodeSourceSlotPath.ts b/extension/src/utils/nodeSourceSlotPath.ts new file mode 100644 index 000000000..0ea76a441 --- /dev/null +++ b/extension/src/utils/nodeSourceSlotPath.ts @@ -0,0 +1,18 @@ +import { NODE_SOURCE_SLOT_PATH_ROOT } from '../constants' + +import { describeNodeRecordedSource } from './describeNodeRecordedSource' + +/** + * Names the path of a test replay's recorded-source slot: one Codebook-owned source document per opened test replay, named after the source file of the stop it shows (DS5), so a stop in another file gives the slot another name and never a tab per stop. + * Called by {@link StudyWorkspace} when it shows a test replay's moment and when it serves or closes the slot's document. + * @param studyId - The test replay's study id. + * @param sourcePath - The repository-relative path of the source file the slot is named after. + * @returns The slot's URI path; its last segment is the tab title (`Captured-`). + * @example nodeSourceSlotPath('3f1c…', 'src/jobs/scheduler.ts') // => '/node-history-slot/3f1c…/Captured-scheduler.ts' + */ +export function nodeSourceSlotPath( + studyId: string, + sourcePath: string, +): string { + return `/${NODE_SOURCE_SLOT_PATH_ROOT}/${studyId}/${describeNodeRecordedSource({ kind: 'tab-title', path: sourcePath })}` +} diff --git a/extension/src/utils/projectNodeHistoryTimeline.ts b/extension/src/utils/projectNodeHistoryTimeline.ts new file mode 100644 index 000000000..67f3dbd0c --- /dev/null +++ b/extension/src/utils/projectNodeHistoryTimeline.ts @@ -0,0 +1,61 @@ +import type { NodeTestHistoryIndex } from '../nodeTestHistorySchemas' + +import { nodeStopSourceMatches } from './nodeStopSourceMatches' +import { projectHistoricalTimeline } from './projectHistoricalTimeline' + +/** What the test replay's time slider draws: the recorded range, its unrecorded spans and a tick for each recorded stop. */ +export type NodeHistoryTimeline = { + startMs: number + endMs: number + /** The spans in which source and debugger were not recorded. */ + gaps: Array<{ startMs: number; endMs: number }> + /** The time of each stop whose captured source verifies. */ + recordedPoints: number[] +} + +/** + * Maps a test replay's journal onto the shared coverage timeline: the whole range from the first to the last event is one unrecorded span, and each stop whose captured source verifies is a tick. + * + * A test journal records when a stop paused but not when the run resumed, so no interval is known to be recorded; the adapter hands {@link projectHistoricalTimeline} an empty list of paused intervals (an undefined list would answer `unknown`). + * Called by {@link StudyWorkspace} while it projects the Study pane's test replay section; the slider itself stays an event navigator. + * + * @param history - The test replay's events in journal order. + * @returns The range, its one gap and the ticks; `undefined` for a history of fewer than two events or of events all at one time, which have nothing to mark. + * @example + * projectNodeHistoryTimeline({ entries: [output0s, verifiedStop1s, result2s] }) // => { startMs: 0, endMs: 2000, gaps: [{ startMs: 0, endMs: 2000 }], recordedPoints: [1000] } + */ +export function projectNodeHistoryTimeline( + history: Pick, +): NodeHistoryTimeline | undefined { + const first = history.entries[0], + last = history.entries.at(-1) + // One event, or events at one time, have no span to mark (the browser transport draws none either). + if (!first || !last || last.elapsedMs <= first.elapsedMs) return undefined + const range = { startMs: first.elapsedMs, endMs: last.elapsedMs } + const timeline = projectHistoricalTimeline( + { + pausedIntervals: [], + study: { + observations: history.entries.flatMap((entry) => + // An unverified stop has no recorded source to tick; only a verified one carries a debugger snapshot into the mapping. + entry.type === 'stop' && nodeStopSourceMatches(entry) + ? [ + { + id: String(entry.sequence), + elapsedMs: entry.elapsedMs, + debugger: entry.debuggerSnapshot, + }, + ] + : [], + ), + }, + }, + range, + ) + if (timeline.status !== 'mapped') return undefined + return { + ...range, + gaps: timeline.gaps, + recordedPoints: timeline.recordedPoints, + } +} diff --git a/extension/src/utils/projectNodeTestSection.ts b/extension/src/utils/projectNodeTestSection.ts index db698dd20..a91021fc0 100644 --- a/extension/src/utils/projectNodeTestSection.ts +++ b/extension/src/utils/projectNodeTestSection.ts @@ -8,6 +8,8 @@ import { describeNodeTestResult, type NodeTestVerdict, } from './describeNodeTestResult' +import { projectNodeHistoryTimeline } from './projectNodeHistoryTimeline' +import type { NodeHistoryTimeline } from './projectNodeHistoryTimeline' import type { NodeLearningSummaryProjection } from './projectNodeLearningSummary' /** @@ -39,6 +41,8 @@ export type NodeTestSectionView = { /** Whether a stop lies before and after the selected event, for Previous stop and Next stop. */ previousStop: boolean nextStop: boolean + /** The slider's unrecorded span and stop ticks; absent for a history with nothing to mark (one event, or events at one time). */ + timeline?: NodeHistoryTimeline } /** The inputs of the section's view. */ @@ -72,6 +76,8 @@ export function projectNodeTestSection( const explanation = momentExplanation(selected, moment.selectedStep) const unverifiedStop = selected?.type === 'stop' && !input.selectedStopVerified + const timeline = projectNodeHistoryTimeline(history) + const marks = timeline ? { timeline } : {} return { status: sectionStatus(history, stops, verdict, learning), ...(selected ? { position: positionLine(selected, stops.length) } : {}), @@ -101,6 +107,7 @@ export function projectNodeTestSection( nextStop: stops.some( (stop) => selected === undefined || stop.sequence > selected.sequence, ), + ...marks, } } diff --git a/extension/test-timings.json b/extension/test-timings.json index 4964b3a4d..546a01167 100644 --- a/extension/test-timings.json +++ b/extension/test-timings.json @@ -1,5 +1,8 @@ { "files": { + "accumulateNodeTestOutput.test.js": { + "totalMs": 101 + }, "adoptLateNameOfAcquiredGroup.test.js": { "totalMs": 1 }, @@ -13,19 +16,22 @@ "totalMs": 0 }, "answerDeepWikiQuestion.test.js": { - "totalMs": 237 + "totalMs": 240 + }, + "awaitDocumentSettled.test.js": { + "totalMs": 104 }, "bookIdOfFileName.test.js": { "totalMs": 1 }, "boundaries.test.js": { - "totalMs": 853 + "totalMs": 806 }, "breakLocationLinesOnTheWay.test.js": { "totalMs": 1 }, "browserRecordingSealFailure.test.js": { - "totalMs": 358 + "totalMs": 356 }, "buildWikiUpdatePrompt.test.js": { "totalMs": 1 @@ -37,7 +43,7 @@ "totalMs": 5 }, "canJudgeOwnerHere.test.js": { - "totalMs": 2 + "totalMs": 1 }, "capturedSourceNotShownReason.test.js": { "totalMs": 1 @@ -46,19 +52,19 @@ "totalMs": 1 }, "checkNodeTestFiles.test.js": { - "totalMs": 18 + "totalMs": 11 }, "citationProgress.test.js": { - "totalMs": 93 + "totalMs": 80 }, "claimWikiUpdateMarker.test.js": { - "totalMs": 519 + "totalMs": 490 }, "classifyWikiUpdateEnd.test.js": { - "totalMs": 3 + "totalMs": 2 }, "client.test.js": { - "totalMs": 190 + "totalMs": 178 }, "codebookStopLedger.test.js": { "totalMs": 1 @@ -67,290 +73,290 @@ "totalMs": 1 }, "configuredAdapter.test.js": { - "totalMs": 263 + "totalMs": 247 }, "configuredApplication.test.js": { - "totalMs": 394 + "totalMs": 395 }, "configuredBundle.test.js": { - "totalMs": 79 + "totalMs": 76 }, "configuredConditionHint.test.js": { "totalMs": 2 }, "configuredPreparation.test.js": { - "totalMs": 1721 + "totalMs": 1636 }, "configuredPresentation.test.js": { - "totalMs": 160 + "totalMs": 156 }, "configuredProgress.test.js": { - "totalMs": 602 + "totalMs": 554 }, "configuredRecording.test.js": { - "totalMs": 623 + "totalMs": 596 }, "configuredRunStopLedger.test.js": { - "totalMs": 1775 + "totalMs": 1742 }, "configuredRuntime.test.js": { - "totalMs": 24977, + "totalMs": 24764, "tests": { - "VS Code startup cannot hit Codebook’s click breakpoint before the learner input": 242, - "a before condition that never holds is still named when the wait words its own timeout differently": 69, - "a before text condition on other text ends the run with the comparison rule": 75, - "a before text condition whose element holds more text ends the run with the rule and the fix, without clicking the application": 73, - "a before value attribute condition still ends the run with the before-input sentence, and another attribute with the entire-value sentence": 130, - "a binding failure on a sealed map too large to scan completely says its mapped positions come from a partial scan": 63, - "a browser stop adopted after the debugger moved it past a line that can pause is committed there, and its inspection names the column that pauses on the declared line": 221, - "a browser stop bound on the next line is armed and captured there when the debugger lists break locations only on that line": 167, - "a browser stop moved to a later line asks the debugger for the break locations of the requested line only, and is refused when one lies on it": 58, - "a browser stop slid to the next line although its declared line has a break location is refused at arming without a click": 60, - "a browser stop that still cannot be bound on its line after one new request is refused and told to declare the statement’s column": 114, - "a browser stop the debugger binds across a line that has a mapped position is refused at once with the declared stop and where it landed": 114, - "a browser stop the debugger binds at another column of its declared line is armed at once and commits at the bound column": 258, + "VS Code startup cannot hit Codebook’s click breakpoint before the learner input": 233, + "a before condition that never holds is still named when the wait words its own timeout differently": 82, + "a before text condition on other text ends the run with the comparison rule": 72, + "a before text condition whose element holds more text ends the run with the rule and the fix, without clicking the application": 77, + "a before value attribute condition still ends the run with the before-input sentence, and another attribute with the entire-value sentence": 122, + "a binding failure on a sealed map too large to scan completely says its mapped positions come from a partial scan": 64, + "a browser stop adopted after the debugger moved it past a line that can pause is committed there, and its inspection names the column that pauses on the declared line": 226, + "a browser stop bound on the next line is armed and captured there when the debugger lists break locations only on that line": 164, + "a browser stop moved to a later line asks the debugger for the break locations of the requested line only, and is refused when one lies on it": 76, + "a browser stop slid to the next line although its declared line has a break location is refused at arming without a click": 62, + "a browser stop that still cannot be bound on its line after one new request is refused and told to declare the statement’s column": 109, + "a browser stop the debugger binds across a line that has a mapped position is refused at once with the declared stop and where it landed": 117, + "a browser stop the debugger binds at another column of its declared line is armed at once and commits at the bound column": 264, "a browser stop the debugger binds on an earlier line of its citation is refused at once with the declared stop and where it landed": 93, - "a browser stop the debugger binds on another line fails at once and names the declared stop and where it landed": 77, + "a browser stop the debugger binds on another line fails at once and names the declared stop and where it landed": 63, "a browser stop the debugger binds on the next line of its citation is armed, pauses there and commits at the bound line": 226, - "a browser stop the debugger binds two lines below is refused when the sealed map is too large to scan the line between": 104, - "a browser stop the debugger binds two lines below, across a comment the generated module kept and mapped, is armed and commits at the bound line": 226, - "a browser stop the debugger binds two lines below, across a line the sealed map has no position on, is armed, pauses there and commits at the bound line": 266, - "a browser stop the debugger moved across a mapped line although its own line can pause is requested again on its line and pauses there": 266, - "a browser stop the debugger moved across a mapped line is refused naming that line when its own line cannot pause": 63, - "a browser stop the debugger moves to another line after it was armed fails naming the declared stop and where it is bound now": 195, - "a browser stop whose binding moved to another column after arming commits at the re-read column while the wait for the armed column is still open": 165, - "a browser stop whose binding the debugger moved to another column after arming commits at the column read again at its pause": 227, - "a browser stop whose verified binding moved to the next line although its own line can pause is requested again on its line and pauses there": 272, - "a changed click target is rejected after readiness without a pointer event or automatic retry": 150, - "a cited source that is marked as modified in the editor with the text the article cites, in other line ends, does not refuse the start": 87, - "a click target that matches no element ends preparation saying so, with the page’s control counts and what to read": 60, - "a completed run keeps its result when its whole-run deadline passes before its release": 251, - "a continuation refused because the learner changed a cited source in the editor during the hold ends the run saying that no resume was sent, not as an uncertain continuation": 212, - "a continuation that reaches no next stop while the browser stays paused with no debugger stop ends the run naming where it is paused": 167, - "a continued for another thread after authorized Continue revokes completion as an unowned continuation without another input": 205, - "a debugger-revealed raw source tab does not prevent the matching configured pause image or alter the learner document": 230, - "a declared line the sealed map is too large to scan completely does not refuse the stop at preparation": 67, - "a dirty target buffer rejects preparation before application effects without saving reverting or removing its tab": 84, - "a failure that reaches a completed run before its release leaves the run completed with its result": 221, - "a first stop on its declared line that the click does not reach ends the run naming the stop and that its line must run": 126, - "a first stop the debugger moved to the next line that the click does not reach ends the run naming the bound place and that this line must run": 144, - "a first stop whose executed module differs from the sealed bundle is refused before input naming the stop": 58, - "a held configured pause expires at five minutes while retaining its original observation and learner breakpoint": 168, - "a held configured pause that is renewed while a replay is read is still held at five minutes and expires five minutes after the renewal": 170, - "a held pause whose binding read the adapter does not answer is taken as the stop’s pause when the wait for the stop’s own pause has ended": 457, - "a late action cannot reset the original ten-minute run deadline": 192, - "a later browser stop declared on an unmapped line is requested at the first mapped position after it inside the continuation and captured there": 285, - "a later stop the debugger moved to the next line that is not reached ends the run naming the bound place and that this line must run": 248, - "a later stop whose executed module differs from the sealed bundle ends the run naming the stop and that it was being armed inside the continuation": 227, - "a later stop whose line never runs after the preceding continuation ends the run naming that stop and the order rule": 174, - "a next stop’s pause that waited for the preceding continuation’s receipts is journaled once, and its resume counts from when it was first observed": 388, - "a page that changed while the after image was captured is not saved as demonstrated, and the run ends naming the after condition that no longer held": 275, - "a pause at the line the debugger moved a browser stop to is captured as that stop’s own pause, without waiting for a pause on the declared line": 212, - "a pause held at another column of the bound line while the stop is announced keeps waiting when the binding read again did not move, and the stop is captured at its own column": 307, - "a pause in a script announced after the first two hundred is journaled with its script URL, position, function and hit breakpoints": 76, - "a pause in a script with a 9,000-character URL is journaled and named in the deadline text by a bounded prefix of that URL": 167, - "a pause on the first stop’s line before the input is sent is not captured as that stop when the debugger announces it later": 1155, - "a pause that arrives during a continuation is journaled with the receipts that continuation already has": 166, - "a pause the debugger makes at another column of the expected stop’s line and resumes is retired, and the stop itself is then captured": 217, - "a pause the debugger makes for itself in another script between two browser stops is retired, and the second stop is captured": 342, - "a pending configured input expires the active wait without redispatch and closes transport before waiting for its acknowledgement": 125, - "a pending stack refresh is not renewed as a pause hold while a replay is read": 168, - "a profile folder that cannot be removed is named in the run's cleanup record and leaves a demonstrated run demonstrated": 235, - "a queued next stop that resumes before the prior command response cannot acquire stale pause authority": 216, - "a read of the run resource made between a browser pause and its committed observation does not answer a paused state without the observation": 176, - "a real debugger stop before configured input still fails instead of being ignored as browser setup": 79, - "a required value inspection of an object commits the stop with an object marker and the run continues to completion": 242, - "a required value that the stopped line itself declares fails saying that the line declares it and where to declare the stop instead": 111, - "a resume after an observed pause is journaled with how long that pause lasted, and a resume without one is not": 67, - "a run does not complete while the page is paused at a pause the debugger made for itself during the after capture, and completes once that pause is resumed": 457, - "a run whose evidence refused further events and which then fails keeps its run.failed with its reason as the last event of its journal": 65, - "a sealed source map with a malformed segment is refused at preparation, before any input": 80, - "a second browser-only stop during capture revokes continuation before any second DAP stop arrives": 79, + "a browser stop the debugger binds two lines below is refused when the sealed map is too large to scan the line between": 109, + "a browser stop the debugger binds two lines below, across a comment the generated module kept and mapped, is armed and commits at the bound line": 227, + "a browser stop the debugger binds two lines below, across a line the sealed map has no position on, is armed, pauses there and commits at the bound line": 258, + "a browser stop the debugger moved across a mapped line although its own line can pause is requested again on its line and pauses there": 270, + "a browser stop the debugger moved across a mapped line is refused naming that line when its own line cannot pause": 73, + "a browser stop the debugger moves to another line after it was armed fails naming the declared stop and where it is bound now": 198, + "a browser stop whose binding moved to another column after arming commits at the re-read column while the wait for the armed column is still open": 161, + "a browser stop whose binding the debugger moved to another column after arming commits at the column read again at its pause": 224, + "a browser stop whose verified binding moved to the next line although its own line can pause is requested again on its line and pauses there": 277, + "a changed click target is rejected after readiness without a pointer event or automatic retry": 165, + "a cited source that is marked as modified in the editor with the text the article cites, in other line ends, does not refuse the start": 105, + "a click target that matches no element ends preparation saying so, with the page’s control counts and what to read": 59, + "a completed run keeps its result when its whole-run deadline passes before its release": 217, + "a continuation refused because the learner changed a cited source in the editor during the hold ends the run saying that no resume was sent, not as an uncertain continuation": 216, + "a continuation that reaches no next stop while the browser stays paused with no debugger stop ends the run naming where it is paused": 168, + "a continued for another thread after authorized Continue revokes completion as an unowned continuation without another input": 219, + "a debugger-revealed raw source tab does not prevent the matching configured pause image or alter the learner document": 216, + "a declared line the sealed map is too large to scan completely does not refuse the stop at preparation": 63, + "a dirty target buffer rejects preparation before application effects without saving reverting or removing its tab": 85, + "a failure that reaches a completed run before its release leaves the run completed with its result": 214, + "a first stop on its declared line that the click does not reach ends the run naming the stop and that its line must run": 122, + "a first stop the debugger moved to the next line that the click does not reach ends the run naming the bound place and that this line must run": 154, + "a first stop whose executed module differs from the sealed bundle is refused before input naming the stop": 63, + "a held configured pause expires at five minutes while retaining its original observation and learner breakpoint": 165, + "a held configured pause that is renewed while a replay is read is still held at five minutes and expires five minutes after the renewal": 165, + "a held pause whose binding read the adapter does not answer is taken as the stop’s pause when the wait for the stop’s own pause has ended": 425, + "a late action cannot reset the original ten-minute run deadline": 165, + "a later browser stop declared on an unmapped line is requested at the first mapped position after it inside the continuation and captured there": 295, + "a later stop the debugger moved to the next line that is not reached ends the run naming the bound place and that this line must run": 233, + "a later stop whose executed module differs from the sealed bundle ends the run naming the stop and that it was being armed inside the continuation": 164, + "a later stop whose line never runs after the preceding continuation ends the run naming that stop and the order rule": 166, + "a next stop’s pause that waited for the preceding continuation’s receipts is journaled once, and its resume counts from when it was first observed": 384, + "a page that changed while the after image was captured is not saved as demonstrated, and the run ends naming the after condition that no longer held": 309, + "a pause at the line the debugger moved a browser stop to is captured as that stop’s own pause, without waiting for a pause on the declared line": 221, + "a pause held at another column of the bound line while the stop is announced keeps waiting when the binding read again did not move, and the stop is captured at its own column": 274, + "a pause in a script announced after the first two hundred is journaled with its script URL, position, function and hit breakpoints": 72, + "a pause in a script with a 9,000-character URL is journaled and named in the deadline text by a bounded prefix of that URL": 176, + "a pause on the first stop’s line before the input is sent is not captured as that stop when the debugger announces it later": 1133, + "a pause that arrives during a continuation is journaled with the receipts that continuation already has": 162, + "a pause the debugger makes at another column of the expected stop’s line and resumes is retired, and the stop itself is then captured": 216, + "a pause the debugger makes for itself in another script between two browser stops is retired, and the second stop is captured": 326, + "a pending configured input expires the active wait without redispatch and closes transport before waiting for its acknowledgement": 118, + "a pending stack refresh is not renewed as a pause hold while a replay is read": 167, + "a profile folder that cannot be removed is named in the run's cleanup record and leaves a demonstrated run demonstrated": 226, + "a queued next stop that resumes before the prior command response cannot acquire stale pause authority": 233, + "a read of the run resource made between a browser pause and its committed observation does not answer a paused state without the observation": 170, + "a real debugger stop before configured input still fails instead of being ignored as browser setup": 62, + "a required value inspection of an object commits the stop with an object marker and the run continues to completion": 227, + "a required value that the stopped line itself declares fails saying that the line declares it and where to declare the stop instead": 115, + "a resume after an observed pause is journaled with how long that pause lasted, and a resume without one is not": 61, + "a run does not complete while the page is paused at a pause the debugger made for itself during the after capture, and completes once that pause is resumed": 440, + "a run whose evidence refused further events and which then fails keeps its run.failed with its reason as the last event of its journal": 77, + "a sealed source map with a malformed segment is refused at preparation, before any input": 70, + "a second browser-only stop during capture revokes continuation before any second DAP stop arrives": 61, "a second selected stop during capture cancels the observation instead of overwriting it or granting continuation": 104, - "a second selected stop racing the after renderer cannot replace the first observation or certify completion": 203, - "a start whose cited source is open in the editor with other text than the article cites is refused before the application starts, naming the file and what the learner and the agent do": 92, - "a stop declared at column 1 of an unmapped line is requested and captured at the column of the first mapped position on the next line": 184, - "a stop declared on a blank line with a code line after it in its citation is armed, also when the sealed map is too large to scan completely": 205, + "a second selected stop racing the after renderer cannot replace the first observation or certify completion": 200, + "a start whose cited source is open in the editor with other text than the article cites is refused before the application starts, naming the file and what the learner and the agent do": 96, + "a stop declared at column 1 of an unmapped line is requested and captured at the column of the first mapped position on the next line": 188, + "a stop declared on a blank line with a code line after it in its citation is armed, also when the sealed map is too large to scan completely": 202, "a stop declared on a blank line with only blank or comment lines after it in its citation is refused before any click, also when the sealed map is too large to scan completely": 65, - "a stop declared on a line the sealed map has no position on is requested at the first mapped position after it in its citation, pauses there and commits at that place": 160, - "a stop declared on a line with a mapped position is requested at its declared position": 67, - "a stop declared on an opening tag in a partly scanned module is requested on the first later line that can pause, not on the line that holds only the tag’s closing bracket": 185, - "a stop declared on the first line of a block comment in a partly scanned module is requested on the first line after the comment that can pause, not on the comment’s body": 188, - "a stop declared with a column on a blank line is admitted and requested at the first mapped position after it": 204, - "a stop moved off the line that declares its required binding is journaled with its declared place, its armed place and the bindings, and its inspection names both places": 169, - "a stop on `nextTheme += \"!\"; // Previously: const nextTheme = \"dark\"` that requires nextTheme stays on its declared line, because a declaration in a comment declares nothing": 60, - "a stop on a declaration whose statement does not end within its citation stays on its line and fails naming that line as the one to follow": 112, - "a stop on the first line of a declaration over several lines in a partly scanned module is requested on the first line after the whole statement that can pause, not inside its initializer": 189, - "a stop on the first line of a declaration over several lines is requested on the first mapped line after the whole statement, and the journal names that line": 166, - "a stop requested after its unmapped declared line that slid past the requested line is requested again at that line’s break location before the requested column": 110, - "a stop requested after its unmapped declared line that the debugger slides past a requested line it can pause on is refused naming the requested line": 59, - "a stop requested after its unmapped declared line that the debugger then binds on the next line commits there, as a stop declared on the requested line would": 164, - "a stop requested after its unmapped declared line whose binding never verifies times out naming the place it was requested at": 60, - "a stop that requires a value its own line declares is requested on the first mapped line after it and reaches its pause with the value": 166, - "a stop that requires a value its own line declares, with no later line of its citation that can pause, stays on its line and fails naming that line as the one to follow": 111, - "a stop whose declared line a partial scan found, or the debugger can pause on, is requested on its declared line": 166, - "a target buffer changed during the hold rejects Continue and preserves the first captured source and dirty text": 208, - "a text relation the run does not know fails the read at once instead of timing out": 64, + "a stop declared on a line the sealed map has no position on is requested at the first mapped position after it in its citation, pauses there and commits at that place": 164, + "a stop declared on a line with a mapped position is requested at its declared position": 58, + "a stop declared on an opening tag in a partly scanned module is requested on the first later line that can pause, not on the line that holds only the tag’s closing bracket": 187, + "a stop declared on the first line of a block comment in a partly scanned module is requested on the first line after the comment that can pause, not on the comment’s body": 182, + "a stop declared with a column on a blank line is admitted and requested at the first mapped position after it": 225, + "a stop moved off the line that declares its required binding is journaled with its declared place, its armed place and the bindings, and its inspection names both places": 166, + "a stop on `nextTheme += \"!\"; // Previously: const nextTheme = \"dark\"` that requires nextTheme stays on its declared line, because a declaration in a comment declares nothing": 63, + "a stop on a declaration whose statement does not end within its citation stays on its line and fails naming that line as the one to follow": 121, + "a stop on the first line of a declaration over several lines in a partly scanned module is requested on the first line after the whole statement that can pause, not inside its initializer": 185, + "a stop on the first line of a declaration over several lines is requested on the first mapped line after the whole statement, and the journal names that line": 170, + "a stop requested after its unmapped declared line that slid past the requested line is requested again at that line’s break location before the requested column": 121, + "a stop requested after its unmapped declared line that the debugger slides past a requested line it can pause on is refused naming the requested line": 70, + "a stop requested after its unmapped declared line that the debugger then binds on the next line commits there, as a stop declared on the requested line would": 166, + "a stop requested after its unmapped declared line whose binding never verifies times out naming the place it was requested at": 58, + "a stop that requires a value its own line declares is requested on the first mapped line after it and reaches its pause with the value": 163, + "a stop that requires a value its own line declares, with no later line of its citation that can pause, stays on its line and fails naming that line as the one to follow": 121, + "a stop whose declared line a partial scan found, or the debugger can pause on, is requested on its declared line": 170, + "a target buffer changed during the hold rejects Continue and preserves the first captured source and dirty text": 186, + "a text relation the run does not know fails the read at once instead of timing out": 62, "an accepted action whose first stop is never hit ends the run naming that declared stop and that its line must run after the input": 156, - "an action deadline that expires before the click was sent keeps its text although the first stop was moved to the next line": 112, - "an adapter failure while the first stop is being armed is reported as that failure, without mapped-position hints and without clicking the application": 63, - "an after condition whose selector matches several elements holds when one of them reads the expected text": 221, - "an after condition whose selector matches several elements, none of which reads the expected text, ends the run saying how many matched and the rule": 222, - "an after text condition that never holds ends the run with the after timeout text and its hint, not the plain deadline text": 232, - "an input-time browser resume fails before its stop can obtain DAP correlation or continuation authority": 120, - "an unbound configured stop reports sealed map positions as unverified hints without clicking the application": 73, - "an unbound second position leaves the application paused and never sends Continue or another click": 171, - "an unbound stop in a 120-line citation lists the first 20 mapped lines, the 40 nearest its declared line 60 and the last 20": 86, - "an unsatisfied before condition names the failing predicate without clicking the application": 69, - "configured Continue cannot certify completion without its cdp acknowledgement": 195, - "configured Continue cannot certify completion without its dap acknowledgement": 211, - "configured Continue cannot certify completion without its input acknowledgement": 203, - "configured Continue cannot certify completion without its response acknowledgement": 202, - "configured Continue completes once when acknowledgements arrive cdp then dap then response": 267, + "an action deadline that expires before the click was sent keeps its text although the first stop was moved to the next line": 130, + "an adapter failure while the first stop is being armed is reported as that failure, without mapped-position hints and without clicking the application": 56, + "an after condition whose selector matches several elements holds when one of them reads the expected text": 229, + "an after condition whose selector matches several elements, none of which reads the expected text, ends the run saying how many matched and the rule": 227, + "an after text condition that never holds ends the run with the after timeout text and its hint, not the plain deadline text": 235, + "an input-time browser resume fails before its stop can obtain DAP correlation or continuation authority": 116, + "an unbound configured stop reports sealed map positions as unverified hints without clicking the application": 70, + "an unbound second position leaves the application paused and never sends Continue or another click": 177, + "an unbound stop in a 120-line citation lists the first 20 mapped lines, the 40 nearest its declared line 60 and the last 20": 87, + "an unsatisfied before condition names the failing predicate without clicking the application": 85, + "configured Continue cannot certify completion without its cdp acknowledgement": 183, + "configured Continue cannot certify completion without its dap acknowledgement": 207, + "configured Continue cannot certify completion without its input acknowledgement": 200, + "configured Continue cannot certify completion without its response acknowledgement": 195, + "configured Continue completes once when acknowledgements arrive cdp then dap then response": 270, "configured Continue completes once when acknowledgements arrive cdp then response then dap": 269, - "configured Continue completes once when acknowledgements arrive dap then cdp then response": 254, - "configured Continue completes once when acknowledgements arrive dap then response then cdp": 285, - "configured Continue completes once when acknowledgements arrive response then cdp then dap": 250, - "configured Continue completes once when acknowledgements arrive response then dap then cdp": 253, - "internal browser setup stops do not consume the configured learning pause or prevent its later completion": 289, - "manual CDP resume revokes the exact pause and after completion even before a DAP continued event arrives": 206, - "missing required facts at the second position retain both histories without reusing prior pixels but cannot continue or complete": 222, - "one click retains two ordered source stops and waits for the final continuation before completion": 323, - "one configured browser action keeps a 70-second pause controllable and completes only after original continuation input and renderer ACKs": 239, - "preparing a stop declared on an unmapped line scans its sealed map once": 209, - "removing an editor breakpoint without the adapter acknowledgement grants no captured pause or Continue": 140, - "renewing a held pause for every replay frame adds no events to the run journal": 167, - "the break locations listed at a pause only to name a moved stop’s column are requested with the 3 second capture bound": 214, - "the inspection and the journal of a stop declared on an unmapped line name its declared, its armed and its bound place": 233, - "the next declared stop stays unauthorized until prior receipts arrive cdp then dap then response": 272, - "the next declared stop stays unauthorized until prior receipts arrive cdp then response then dap": 269, - "the next declared stop stays unauthorized until prior receipts arrive dap then cdp then response": 270, - "the next declared stop stays unauthorized until prior receipts arrive dap then response then cdp": 281, - "the next declared stop stays unauthorized until prior receipts arrive response then cdp then dap": 274, - "the next declared stop stays unauthorized until prior receipts arrive response then dap then cdp": 278, + "configured Continue completes once when acknowledgements arrive dap then cdp then response": 274, + "configured Continue completes once when acknowledgements arrive dap then response then cdp": 250, + "configured Continue completes once when acknowledgements arrive response then cdp then dap": 249, + "configured Continue completes once when acknowledgements arrive response then dap then cdp": 242, + "internal browser setup stops do not consume the configured learning pause or prevent its later completion": 274, + "manual CDP resume revokes the exact pause and after completion even before a DAP continued event arrives": 199, + "missing required facts at the second position retain both histories without reusing prior pixels but cannot continue or complete": 216, + "one click retains two ordered source stops and waits for the final continuation before completion": 320, + "one configured browser action keeps a 70-second pause controllable and completes only after original continuation input and renderer ACKs": 215, + "preparing a stop declared on an unmapped line scans its sealed map once": 223, + "removing an editor breakpoint without the adapter acknowledgement grants no captured pause or Continue": 162, + "renewing a held pause for every replay frame adds no events to the run journal": 163, + "the break locations listed at a pause only to name a moved stop’s column are requested with the 3 second capture bound": 215, + "the inspection and the journal of a stop declared on an unmapped line name its declared, its armed and its bound place": 204, + "the next declared stop stays unauthorized until prior receipts arrive cdp then dap then response": 275, + "the next declared stop stays unauthorized until prior receipts arrive cdp then response then dap": 279, + "the next declared stop stays unauthorized until prior receipts arrive dap then cdp then response": 280, + "the next declared stop stays unauthorized until prior receipts arrive dap then response then cdp": 301, + "the next declared stop stays unauthorized until prior receipts arrive response then cdp then dap": 267, + "the next declared stop stays unauthorized until prior receipts arrive response then dap then cdp": 276, "the pre-input configured manifest retains the full accepted intent and complete citation identity without source-code blobs": 63, - "the service cancellation signal retires an already held configured runtime without requiring another click or manual debugger action": 174, - "the whole-run deadline that expires while the page is paused with no debugger stop names where it is paused": 106, - "two stops declared on different lines that bind on one place fail when the second is armed, naming both declared stops and the place, without a resume": 168 + "the service cancellation signal retires an already held configured runtime without requiring another click or manual debugger action": 170, + "the whole-run deadline that expires while the page is paused with no debugger stop names where it is paused": 104, + "two stops declared on different lines that bind on one place fail when the second is armed, naming both declared stops and the place, without a resume": 167 } }, "configuredRuntimeRecording.test.js": { - "totalMs": 4141 + "totalMs": 4023 }, "configuredService.test.js": { - "totalMs": 12307, + "totalMs": 12079, "tests": { - "API 1.8 discovery exposes the bounded configured profile and its executable configuration schema without starting input": 84, - "MCP resources/read returns an observation’s inspection, its pages and its snapshot image": 130, - "Node test learning material whose observed step has no reference is refused naming that step and the references a Node history offers": 105, - "a Node test start whose stop declares only type inspections is refused naming that stop and what to add": 62, - "a bare path that names a value and a type fact is refused with both keys": 111, - "a completed run whose release failed after its saved study was removed by hand names the failed write and the removal as its error, and no storage path": 151, - "a configured runtime returned after cancellation is still owned and released exactly once": 109, - "a continuation acknowledged 40 seconds after the call began waits only five more seconds for the next state": 243, - "a continuation sent with the arguments the run resource gave answers with the next committed observation and its inspectionUri, without a poll": 142, - "a continuation that waits for the next state does not hold other calls: the run resource is read meanwhile": 246, - "a continuation whose request is abandoned stops waiting at once": 245, + "API 1.8 discovery exposes the bounded configured profile and its executable configuration schema without starting input": 93, + "MCP resources/read returns an observation’s inspection, its pages and its snapshot image": 125, + "Node test learning material whose observed step has no reference is refused naming that step and the references a Node history offers": 101, + "a Node test start whose stop declares only type inspections is refused naming that stop and what to add": 73, + "a bare path that names a value and a type fact is refused with both keys": 117, + "a completed run whose release failed after its saved study was removed by hand names the failed write and the removal as its error, and no storage path": 140, + "a configured runtime returned after cancellation is still owned and released exactly once": 108, + "a continuation acknowledged 40 seconds after the call began waits only five more seconds for the next state": 245, + "a continuation sent with the arguments the run resource gave answers with the next committed observation and its inspectionUri, without a poll": 147, + "a continuation that waits for the next state does not hold other calls: the run resource is read meanwhile": 244, + "a continuation whose request is abandoned stops waiting at once": 240, "a continuation whose run shows no next state within 22 seconds of its acknowledgement answers accepted with the latest state and no next state": 240, - "a continuation without the answer argument answers accepted at once": 93, - "a failed configured start keeps its original receipt after source drift without silently trying the application again": 120, - "a failure directly after the next pause was committed is in the continuation’s answer": 142, - "a learning summary that uses a participant id twice is refused naming the second use": 96, - "a learning summary that uses a step id twice is refused naming the second use": 130, - "a learning summary whose source-derived step has no reference is refused naming that step and what it needs": 101, - "a learning summary whose step names a participant that is not declared is refused naming that step and that participant": 124, - "a removed study's kept run failure with the storage path is served by no resource: its events and manifest are refused with the removal, and the run and status name no path": 170, - "a repository run exposes the Study link identity separately from its debugger session identity": 126, - "a reveal and a continuation of the same stop issued together, continue first, never answer an evidence failure": 89, - "a reveal and a continuation of the same stop issued together, reveal first, never answer an evidence failure": 165, - "a reveal whose pause the learner resumes in the debugger meanwhile answers STALE_PAUSE instead of an evidence failure": 104, - "a run its runtime ends during preparation gives its resource the runtime’s reason, not the closed transport": 95, - "a run stopped by another call while a continuation waits answers at once with the stopped run": 151, - "a run that completes in the turn in which its whole-run deadline passes answers the continuation with its result": 144, - "a run that failed itself on a removed study's evidence write and was stopped before a maintenance turn names the failed write and the removal, not the storage path": 113, - "a run that fails inside its runtime gives its resource an error whose cause is the failure text": 98, - "a run that fails while a continuation waits for its next state answers with the failure text, not with the bound": 135, - "a run that the maintenance turn ends for an evidence write failure names that failure in its terminal reason and in the reason it journals as run.failed": 156, - "a run whose explanation cannot be written fails its runtime with the write failure, which the runtime journals as run.failed": 98, - "a run whose explanation was not committed and whose whole-run deadline then passes names the write failure in its terminal reason and in the reason it journals as run.failed": 92, - "a run whose preparation fails and whose release then fails keeps the preparation cause as its terminal reason": 162, - "a run whose preparation fails with an error that is no StudyError names that error in its terminal reason and in the reason it journals as run.failed": 111, - "a run whose saved study was found removed after its evidence write failed and its release ended names the failed write and the removal and no storage path": 169, - "a run whose saved study was removed while it ran ends at the maintenance turn with a terminal reason that names the failed evidence write and the removal and no storage path": 151, - "a run whose saved study was removed while it ran keeps a release failure that names the failed evidence write and the removal and no storage path": 139, - "a run whose study was found removed while its preparation was failing names the failed write and the removal in its error and journaled reason, not the storage path": 175, - "a run whose study was removed during its preparation and found removed after the preparation failed names the failed write and the removal, not the storage path": 174, - "a run whose whole-run deadline expires while a continuation waits answers with that end": 264, - "a runtime failure longer than the saved reason limit is cut to that limit in the run resource": 137, - "a second explanation of a moved stop that names no line is saved once a first one exists": 113, + "a continuation without the answer argument answers accepted at once": 87, + "a failed configured start keeps its original receipt after source drift without silently trying the application again": 101, + "a failure directly after the next pause was committed is in the continuation’s answer": 141, + "a learning summary that uses a participant id twice is refused naming the second use": 93, + "a learning summary that uses a step id twice is refused naming the second use": 93, + "a learning summary whose source-derived step has no reference is refused naming that step and what it needs": 93, + "a learning summary whose step names a participant that is not declared is refused naming that step and that participant": 95, + "a removed study's kept run failure with the storage path is served by no resource: its events and manifest are refused with the removal, and the run and status name no path": 163, + "a repository run exposes the Study link identity separately from its debugger session identity": 108, + "a reveal and a continuation of the same stop issued together, continue first, never answer an evidence failure": 115, + "a reveal and a continuation of the same stop issued together, reveal first, never answer an evidence failure": 168, + "a reveal whose pause the learner resumes in the debugger meanwhile answers STALE_PAUSE instead of an evidence failure": 87, + "a run its runtime ends during preparation gives its resource the runtime’s reason, not the closed transport": 111, + "a run stopped by another call while a continuation waits answers at once with the stopped run": 140, + "a run that completes in the turn in which its whole-run deadline passes answers the continuation with its result": 141, + "a run that failed itself on a removed study's evidence write and was stopped before a maintenance turn names the failed write and the removal, not the storage path": 108, + "a run that fails inside its runtime gives its resource an error whose cause is the failure text": 95, + "a run that fails while a continuation waits for its next state answers with the failure text, not with the bound": 140, + "a run that the maintenance turn ends for an evidence write failure names that failure in its terminal reason and in the reason it journals as run.failed": 148, + "a run whose explanation cannot be written fails its runtime with the write failure, which the runtime journals as run.failed": 91, + "a run whose explanation was not committed and whose whole-run deadline then passes names the write failure in its terminal reason and in the reason it journals as run.failed": 129, + "a run whose preparation fails and whose release then fails keeps the preparation cause as its terminal reason": 158, + "a run whose preparation fails with an error that is no StudyError names that error in its terminal reason and in the reason it journals as run.failed": 87, + "a run whose saved study was found removed after its evidence write failed and its release ended names the failed write and the removal and no storage path": 166, + "a run whose saved study was removed while it ran ends at the maintenance turn with a terminal reason that names the failed evidence write and the removal and no storage path": 141, + "a run whose saved study was removed while it ran keeps a release failure that names the failed evidence write and the removal and no storage path": 136, + "a run whose study was found removed while its preparation was failing names the failed write and the removal in its error and journaled reason, not the storage path": 159, + "a run whose study was removed during its preparation and found removed after the preparation failed names the failed write and the removal, not the storage path": 160, + "a run whose whole-run deadline expires while a continuation waits answers with that end": 248, + "a runtime failure longer than the saved reason limit is cut to that limit in the run resource": 107, + "a second explanation of a moved stop that names no line is saved once a first one exists": 140, "a start on a node id its selected revision does not have is refused in the answer of codebook_start, naming the revision’s nodes and the two ways on": 64, - "a start on a revision its book does not have is refused in the answer of codebook_start with the store’s sentence, and no run begins": 68, - "a start on a stored book the store cannot read is refused in the answer of codebook_start with the store’s sentence and the read’s cause": 69, - "a start whose book read fails with an error that is not the store’s refusal is accepted, and its run ends naming that cause": 63, + "a start on a revision its book does not have is refused in the answer of codebook_start with the store’s sentence, and no run begins": 70, + "a start on a stored book the store cannot read is refused in the answer of codebook_start with the store’s sentence and the read’s cause": 62, + "a start whose book read fails with an error that is not the store’s refusal is accepted, and its run ends naming that cause": 64, "a start whose first stop declares only type inspections is refused naming that stop, the inspections it declares and what to add": 70, - "a start whose later stop declares only type inspections is refused naming that later stop and every inspection it declares": 63, - "a start whose stop declares a value inspection but requires none is refused with the sentence that one required value inspection is needed": 66, - "after a publish with expectedRevision 0 is refused for an existing article, the same document published with the current revision is the next revision, and a start on that revision is admitted": 122, - "after one refusal the next explanation of that moved stop is saved although it names no line, and the journal records that the line was not named": 129, - "after the last stop a continuation sent with those arguments answers the observed result": 143, - "an explanation of a moved stop that names no line is refused with the line it paused on and saved under the same key once it names it": 120, - "an explanation of a stopped run that cannot be written journals explanation.failed with its cause and leaves the run’s outcome as it was": 93, - "an interpretation that gives the declared line as the place and holds the paused line’s number as a value is saved at once": 118, - "an interpretation that holds the paused line’s number only inside a longer number is refused": 120, - "an interpretation that names the paused line in full-width digits is saved at once": 130, - "an interpretation that names the paused line only in words is refused once and then saved": 120, - "an observation committed on the line the debugger moved its stop to reports that line as source beside the declared requestedSource": 116, - "an observation that paused on its declared line carries no place sentence": 127, - "codebook_explain accepts nextTheme for the captured fact value:nextTheme and saves it under that key": 134, - "configured explanations retain actual false and null facts while unavailable or foreign facts grant no interpretation or continuation": 111, - "configured help and the continue tool tell an agent that a continuation sent with continueArguments answers with the next state, and to poll when it answers accepted only": 77, - "configured help names the active-progress deadline the run uses, in seconds, in all six places": 95, - "configured help names the declared, the requested and the bound place, says that a moved stop’s inspection carries place and that its first interpretation must name the paused line, and takes its versions from the constants": 105, - "configured help says that a binding the stop's own line declares has no value when the debugger pauses, so Codebook requests the stop on the first line after it that can pause": 61, - "configured help says that a study saved in a newer format is refused as saved by a newer Codebook and is kept": 97, - "configured help says that a text condition whose selector matches several elements holds when one of them reads the expected text": 104, - "configured help says that any column declared on a blank line is taken as the line’s start and names the journal entry that records it": 102, - "configured help says that every stop needs a required value inspection of a primitive and, for an object, to declare a primitive member with type beside it": 59, - "configured help states the binding rule from the line the stop is requested on": 61, - "configured help tells an agent that a continuation that sends no resume, because its next stop cannot be armed or the other participant’s earlier pauses cannot be read, answers \"Continue was not confirmed.\" and where the run’s reason is read": 87, - "configured help tells an agent that a run waits for the debugger’s own pauses and how a deadline names a paused place": 86, - "configured help tells an agent that a start the library refused can be repeated with the same key and begins a new run, and that a start on a revision or node id the book lacks is refused in its own answer": 71, - "configured help tells an agent that a text condition compares the whole textContent trimmed with whitespace collapsed and child texts joined without a space, and what to declare for a button with an icon": 98, - "configured help tells an agent that an after condition already true before the click is refused, and how to fix a condition of each phase": 94, - "configured help tells an agent that only the learner removes a saved study and that a full library is reported, not repaired": 103, - "configured help tells an agent that only the next stop is armed and where its binding may lie": 89, - "configured help tells an agent when a binding on another line fails for each participant and that a pause the debugger resumes by itself is retired": 87, - "dispatch and acknowledgement each invalidate a saved configured checkpoint without changing the acting runtime state": 106, - "duplicate configured starts reserve one immutable intent before article I/O and reject any changed configuration": 106, - "missing repository runtime support prevents acquisition while source authoring remains available": 167, + "a start whose later stop declares only type inspections is refused naming that later stop and every inspection it declares": 71, + "a start whose stop declares a value inspection but requires none is refused with the sentence that one required value inspection is needed": 72, + "after a publish with expectedRevision 0 is refused for an existing article, the same document published with the current revision is the next revision, and a start on that revision is admitted": 127, + "after one refusal the next explanation of that moved stop is saved although it names no line, and the journal records that the line was not named": 133, + "after the last stop a continuation sent with those arguments answers the observed result": 142, + "an explanation of a moved stop that names no line is refused with the line it paused on and saved under the same key once it names it": 125, + "an explanation of a stopped run that cannot be written journals explanation.failed with its cause and leaves the run’s outcome as it was": 94, + "an interpretation that gives the declared line as the place and holds the paused line’s number as a value is saved at once": 148, + "an interpretation that holds the paused line’s number only inside a longer number is refused": 110, + "an interpretation that names the paused line in full-width digits is saved at once": 113, + "an interpretation that names the paused line only in words is refused once and then saved": 117, + "an observation committed on the line the debugger moved its stop to reports that line as source beside the declared requestedSource": 125, + "an observation that paused on its declared line carries no place sentence": 114, + "codebook_explain accepts nextTheme for the captured fact value:nextTheme and saves it under that key": 133, + "configured explanations retain actual false and null facts while unavailable or foreign facts grant no interpretation or continuation": 97, + "configured help and the continue tool tell an agent that a continuation sent with continueArguments answers with the next state, and to poll when it answers accepted only": 86, + "configured help names the active-progress deadline the run uses, in seconds, in all six places": 93, + "configured help names the declared, the requested and the bound place, says that a moved stop’s inspection carries place and that its first interpretation must name the paused line, and takes its versions from the constants": 91, + "configured help says that a binding the stop's own line declares has no value when the debugger pauses, so Codebook requests the stop on the first line after it that can pause": 69, + "configured help says that a study saved in a newer format is refused as saved by a newer Codebook and is kept": 93, + "configured help says that a text condition whose selector matches several elements holds when one of them reads the expected text": 89, + "configured help says that any column declared on a blank line is taken as the line’s start and names the journal entry that records it": 62, + "configured help says that every stop needs a required value inspection of a primitive and, for an object, to declare a primitive member with type beside it": 67, + "configured help states the binding rule from the line the stop is requested on": 73, + "configured help tells an agent that a continuation that sends no resume, because its next stop cannot be armed or the other participant’s earlier pauses cannot be read, answers \"Continue was not confirmed.\" and where the run’s reason is read": 92, + "configured help tells an agent that a run waits for the debugger’s own pauses and how a deadline names a paused place": 79, + "configured help tells an agent that a start the library refused can be repeated with the same key and begins a new run, and that a start on a revision or node id the book lacks is refused in its own answer": 60, + "configured help tells an agent that a text condition compares the whole textContent trimmed with whitespace collapsed and child texts joined without a space, and what to declare for a button with an icon": 101, + "configured help tells an agent that an after condition already true before the click is refused, and how to fix a condition of each phase": 102, + "configured help tells an agent that only the learner removes a saved study and that a full library is reported, not repaired": 97, + "configured help tells an agent that only the next stop is armed and where its binding may lie": 101, + "configured help tells an agent when a binding on another line fails for each participant and that a pause the debugger resumes by itself is retired": 85, + "dispatch and acknowledgement each invalidate a saved configured checkpoint without changing the acting runtime state": 107, + "duplicate configured starts reserve one immutable intent before article I/O and reject any changed configuration": 88, + "missing repository runtime support prevents acquisition while source authoring remains available": 165, "no help resource names a path under extension/, the tutorial is named by the README section, and the recording discovery says since which API it exists": 91, - "real SDK accepts configuration version 1 and reconnects without a second dispatch": 165, - "real SDK accepts configuration version 2 and reconnects without a second dispatch": 141, - "repeating an accepted start through codebook_start answers its original receipt although its stored book can no longer be read": 88, - "repository entry rejects missing configuration and unknown profiles without input": 113, - "repository help says that a revision conflict names the current revision and gives the two ways on": 63, - "repository preparation reports its remaining time without changing evidence identity": 100, - "stopping a configured start during article I/O drains its read and starts neither prerequisites nor a runtime": 79, - "stopping a held runtime preparation delivers cancellation before waiting for its completion": 93, - "the Study help names save-learning-summary and saveLearningSummary in the last step of its sequence, what the run resource says once the 32 explanation keys are spent, and that a stopped run whose evidence write failed is not offered the step": 103, - "the configured help names every journal entry of a pause and its resume and says that pauses away from a stop are journaled up to the limit": 103, - "the configured help says that Codebook resumes a page pause at a server stop’s breakpoint in the page’s stub of a \"use server\" module": 104, - "the configured help takes the journal limit, the two pause bounds and its two version numbers from the constants": 95, - "the input schema of codebook_explain says that a fact path is taken with its prefix, or alone when one captured fact has it": 74, + "real SDK accepts configuration version 1 and reconnects without a second dispatch": 168, + "real SDK accepts configuration version 2 and reconnects without a second dispatch": 153, + "repeating an accepted start through codebook_start answers its original receipt although its stored book can no longer be read": 94, + "repository entry rejects missing configuration and unknown profiles without input": 118, + "repository help says that a revision conflict names the current revision and gives the two ways on": 72, + "repository preparation reports its remaining time without changing evidence identity": 104, + "stopping a configured start during article I/O drains its read and starts neither prerequisites nor a runtime": 122, + "stopping a held runtime preparation delivers cancellation before waiting for its completion": 84, + "the Study help names save-learning-summary and saveLearningSummary in the last step of its sequence, what the run resource says once the 32 explanation keys are spent, and that a stopped run whose evidence write failed is not offered the step": 74, + "the configured help names every journal entry of a pause and its resume and says that pauses away from a stop are journaled up to the limit": 81, + "the configured help says that Codebook resumes a page pause at a server stop’s breakpoint in the page’s stub of a \"use server\" module": 80, + "the configured help takes the journal limit, the two pause bounds and its two version numbers from the constants": 94, + "the input schema of codebook_explain says that a fact path is taken with its prefix, or alone when one captured fact has it": 79, "the input schema of codebook_start says that a required value is read before the stop's line runs and what Codebook and the agent do about a binding that line declares, for the first stop and for later stops of both profiles": 69, - "the input schema of codebook_start states the inspection rule for the first stop and for later stops of both profiles": 66, - "the input schemas of codebook_explain and codebook_explain_node_history say when a step needs a reference and what it holds": 111, - "the inspection of a stop the debugger moved to the next line says which line it paused on, which line was declared, and to name the paused line": 125, - "the inspection resource template says that an inspection names the declared place, the requested place when it differs and the place sentence of a moved stop": 98, - "the pane’s continuation with the run resource’s arguments answers at the acknowledgement, without waiting for the next state": 91, - "the repository-browser help and the node-test help tell an agent that a start saves no document of the learner, that a cited source open in the editor with other text refuses the start and ends a run that is already going, and what the learner and the agent do then": 98, - "the run resource lists the observation of a moved stop with the sentence that names the line it paused on": 109, - "the second observation of a two-stop run reports the position its own stop declared as requestedSource, not the first stop’s": 129, - "the source-changed error help distinguishes a refused start from an ended browser or Node test, keeps earlier captured observations readable and forbids automatic input replay": 93 + "the input schema of codebook_start states the inspection rule for the first stop and for later stops of both profiles": 71, + "the input schemas of codebook_explain and codebook_explain_node_history say when a step needs a reference and what it holds": 109, + "the inspection of a stop the debugger moved to the next line says which line it paused on, which line was declared, and to name the paused line": 117, + "the inspection resource template says that an inspection names the declared place, the requested place when it differs and the place sentence of a moved stop": 92, + "the pane’s continuation with the run resource’s arguments answers at the acknowledgement, without waiting for the next state": 87, + "the repository-browser help and the node-test help tell an agent that a start saves no document of the learner, that a cited source open in the editor with other text refuses the start and ends a run that is already going, and what the learner and the agent do then": 104, + "the run resource lists the observation of a moved stop with the sentence that names the line it paused on": 131, + "the second observation of a two-stop run reports the position its own stop declared as requestedSource, not the first stop’s": 118, + "the source-changed error help distinguishes a refused start from an ended browser or Node test, keeps earlier captured observations readable and forbids automatic input replay": 97 } }, "configuredStorage.test.js": { - "totalMs": 246 + "totalMs": 247 }, "configuredStudy.test.js": { "totalMs": 20 @@ -365,10 +371,10 @@ "totalMs": 3 }, "crossRuntimeHistory.test.js": { - "totalMs": 157 + "totalMs": 148 }, "currentStorageOwner.test.js": { - "totalMs": 12 + "totalMs": 10 }, "currentUserName.test.js": { "totalMs": 1 @@ -377,13 +383,13 @@ "totalMs": 1 }, "cursorMcpBridge.test.js": { - "totalMs": 1621 + "totalMs": 1536 }, "cursorRemovalNotice.test.js": { "totalMs": 1 }, "cursorSkillDeployment.test.js": { - "totalMs": 4264 + "totalMs": 4205 }, "cutChatCause.test.js": { "totalMs": 0 @@ -391,6 +397,9 @@ "cutTextToFit.test.js": { "totalMs": 0 }, + "cutTextToTail.test.js": { + "totalMs": 1 + }, "deadlineText.test.js": { "totalMs": 1 }, @@ -401,7 +410,7 @@ "totalMs": 2 }, "declaredAndArmedPlace.test.js": { - "totalMs": 791 + "totalMs": 782 }, "declaredInspectionBindings.test.js": { "totalMs": 1 @@ -413,85 +422,85 @@ "totalMs": 3 }, "deepWikiReader.test.js": { - "totalMs": 13194, + "totalMs": 12808, "tests": { - "a Wiki page asked for as an image, media, a style sheet, a font, a track, a script or by a fetch is refused with 403 before any page preparation starts, while a page opened as a document, in a frame or by a client that names no destination is served": 12, - "a busy refusal whose browser stops reading is ended at the send limit and gives no place back: a page asked for after it is still refused while the page in hand holds the place, and one asked for after that page is served": 1016, - "a busy refusal whose connection closes before it is received gives no place back: a page asked for after it is still refused while the page in hand holds the place, and one asked for after that page is served": 17, - "a failed editor-model answer reaches the browser reader as an error instead of an empty answer": 5, - "a local page without this reader’s private path token cannot read the generated Wiki": 5, - "a page and an asset whose path a folder takes after the reader’s look and before its open are refused with 403 as no regular file": 21, - "a page built to make the HTML parser slow is answered within about the deadline with status 503 and a sentence for the learner under the page policy, while the event loop of the host runs on": 2007, - "a page file larger than the reader prepares is answered with 503 and a sentence that says so, without the file being opened, while a page within the limit is read and served": 13, - "a page file of 3 MB, far larger than any generated page, is refused as too large under the reader’s shipped limit and is not prepared": 10, - "a page file of exactly the reader’s limit is read and served": 12, - "a page file that grows past the limit after the reader looked at its size is answered with the page that says it is too large, and is not prepared, and six such pages give their places back, so the page asked for after them is served": 34, - "a page that its browser reads slowly but steadily is received whole, though receiving it takes longer than the send limit": 1253, - "a page whose browser does not read it keeps its place until its connection closes: a page asked for meanwhile is refused at once as busy, and one asked for after the close is served": 15, - "a page whose browser goes while the reader looks at its file gets nothing more read once that look ends": 4, + "a Wiki page asked for as an image, media, a style sheet, a font, a track, a script or by a fetch is refused with 403 before any page preparation starts, while a page opened as a document, in a frame or by a client that names no destination is served": 11, + "a busy refusal whose browser stops reading is ended at the send limit and gives no place back: a page asked for after it is still refused while the page in hand holds the place, and one asked for after that page is served": 1014, + "a busy refusal whose connection closes before it is received gives no place back: a page asked for after it is still refused while the page in hand holds the place, and one asked for after that page is served": 16, + "a failed editor-model answer reaches the browser reader as an error instead of an empty answer": 7, + "a local page without this reader’s private path token cannot read the generated Wiki": 6, + "a page and an asset whose path a folder takes after the reader’s look and before its open are refused with 403 as no regular file": 11, + "a page built to make the HTML parser slow is answered within about the deadline with status 503 and a sentence for the learner under the page policy, while the event loop of the host runs on": 2015, + "a page file larger than the reader prepares is answered with 503 and a sentence that says so, without the file being opened, while a page within the limit is read and served": 10, + "a page file of 3 MB, far larger than any generated page, is refused as too large under the reader’s shipped limit and is not prepared": 5, + "a page file of exactly the reader’s limit is read and served": 7, + "a page file that grows past the limit after the reader looked at its size is answered with the page that says it is too large, and is not prepared, and six such pages give their places back, so the page asked for after them is served": 18, + "a page that its browser reads slowly but steadily is received whole, though receiving it takes longer than the send limit": 1159, + "a page whose browser does not read it keeps its place until its connection closes: a page asked for meanwhile is refused at once as busy, and one asked for after the close is served": 22, + "a page whose browser goes while the reader looks at its file gets nothing more read once that look ends": 5, "a page whose browser goes while the reader reads the manifest for it gets nothing more read once that read ends": 4, - "a page whose browser goes while the reader reads the publication identity for it is not opened once that read ends": 5, - "a page whose browser stops reading is ended at the send limit and gives its place back: a page asked for before is refused as busy, one asked for after is served, and the browser receives less than the page": 1516, - "a page whose browser tab goes while the page is prepared has its preparation stopped": 6, - "a page whose browser tab goes while the reader reads its file has its preparation stopped": 207, - "a page whose path holds a named pipe is refused at once with 403, and no open of it waits for a writer": 16, - "a page whose tab goes while it is prepared gives its place back once the reader has stopped, so the page asked for after it is served": 7, - "a page whose worker fails is answered with status 503 and a sentence for the learner under the page policy, never with the page as the folder holds it": 20, - "a page within the file limit that needs more memory than a page worker may use is answered with 503 and a sentence that asks the editor chat to split it, while a small page is served": 238, - "a question from any other origin is refused": 11, - "a question from the address the editor forwarded the reader to is answered": 7, + "a page whose browser goes while the reader reads the publication identity for it is not opened once that read ends": 4, + "a page whose browser stops reading is ended at the send limit and gives its place back: a page asked for before is refused as busy, one asked for after is served, and the browser receives less than the page": 1515, + "a page whose browser tab goes while the page is prepared has its preparation stopped": 5, + "a page whose browser tab goes while the reader reads its file has its preparation stopped": 209, + "a page whose path holds a named pipe is refused at once with 403, and no open of it waits for a writer": 9, + "a page whose tab goes while it is prepared gives its place back once the reader has stopped, so the page asked for after it is served": 5, + "a page whose worker fails is answered with status 503 and a sentence for the learner under the page policy, never with the page as the folder holds it": 18, + "a page within the file limit that needs more memory than a page worker may use is answered with 503 and a sentence that asks the editor chat to split it, while a small page is served": 240, + "a question from any other origin is refused": 9, + "a question from the address the editor forwarded the reader to is answered": 3, "a question of another origin, a question too long, a blank question and a POST to a page are refused without a manifest read": 9, - "a question whose answer is longer than one part of an answer reaches the browser whole": 9, - "a question whose character of two bytes is split between two parts of its body reaches the editor model whole": 110, - "a question whose tab goes while the reader reads the manifest is not sent to the editor model": 6, - "a reader told two forwarded loopback addresses answers questions and requests from both, and still refuses a third address it was not told": 14, - "a refusal page whose browser stops reading is ended at the send limit and gives its place back, so the page asked for after it is served": 1018, - "a request whose Host header is neither the reader’s own nor the forwarded address’s is refused with 403 and no page, while the reader’s own host and the forwarded one are served": 14, - "a script file of the Wiki folder is served as plain text, a page that points at it plainly or through a tag left open before the reader’s own gets no secret to run it, and every response of the reader says nosniff": 13, - "a shared manifest read that fails answers every file of the Wiki that joined it with its error, and a file asked for after it is read again and served": 7, - "a style sheet that an update adds after the reader has served a file of the Wiki is served": 4, - "a style sheet, an image and a font asked for at once cost one manifest read between them, and the reader’s own script and a page asked for as an image are answered without one": 11, - "a window whose forward goes to another host gets a 403 that says the reader answers only on this computer": 5, - "an asset of the Wiki is sent byte for byte from its opened file in parts, only as far as its size at its stat, and no file is read whole into the editor’s process": 18, - "an asset whose path holds a named pipe is refused at once with 403, and no read of it waits for a writer": 11, - "an empty style sheet of the Wiki is served as an empty answer with status 200": 9, - "an image of the Wiki that another file replaced while its browser waited is ended there, and its browser gets no byte of the other file": 33, - "an image of the Wiki that its browser reads slowly but steadily is received whole, though receiving it takes longer than the send limit": 2478, - "an image of the Wiki that shrinks after the reader looked at its size is sent only as far as the bytes it still holds": 11, - "an image of the Wiki whose browser goes before it has received the image has no file of it open, and no part of it is read after the browser went": 22, - "an image of the Wiki whose browser stops reading but keeps sending bytes is still ended at the send limit": 521, - "an image of the Wiki whose browser stops reading has its file closed well before the publisher’s swap gives up, while its answer still waits for the browser": 1537, - "an image of the Wiki whose browser stops reading is ended at the send limit, and its file is closed": 516, - "closing the reader while a question is in flight stops the question and ends at once": 4, - "every page the reader serves lets only script files of its own origin and the shell’s script by its known hash run, and the reader’s own tag carries no secret: a script written into a page file or into an asset that is an HTML file runs nowhere": 15, - "generated Wiki reader refuses a published symlink escaping its output directory": 14, - "generated Wiki reader refuses malformed source identities rather than showing false freshness": 9, - "generated Wiki reader serves published pages and answers an explicit same-origin question": 89, - "in a local window only the reader’s own origin is accepted": 8, - "pages that their worker refuses and pages whose open fails give their places back, so the page asked for after twelve of them is served": 19, - "pages whose browser goes while the reader opens them keep their places until the reader has stopped: no more than six are opened at once, a page asked for meanwhile is refused as busy, no page is read after its browser went, and a page asked for after them is served": 20, - "six pages asked for at once cost one manifest read between them and are all served": 37, - "six pages whose path a folder takes after the reader’s look are each refused with 403 and give their places back, so the page asked for after them is served": 27, - "the reader refuses a Wiki whose .codebook folder has a real path the system cannot name (EACCES) with the sentence of a folder above the Wiki folder, not the system’s error": 3, - "the reader refuses a Wiki whose .codebook folder has a real path the system cannot name (EINVAL) with the sentence of a folder above the Wiki folder, not the system’s error": 3, + "a question whose answer is longer than one part of an answer reaches the browser whole": 13, + "a question whose character of two bytes is split between two parts of its body reaches the editor model whole": 113, + "a question whose tab goes while the reader reads the manifest is not sent to the editor model": 14, + "a reader told two forwarded loopback addresses answers questions and requests from both, and still refuses a third address it was not told": 9, + "a refusal page whose browser stops reading is ended at the send limit and gives its place back, so the page asked for after it is served": 1017, + "a request whose Host header is neither the reader’s own nor the forwarded address’s is refused with 403 and no page, while the reader’s own host and the forwarded one are served": 8, + "a script file of the Wiki folder is served as plain text, a page that points at it plainly or through a tag left open before the reader’s own gets no secret to run it, and every response of the reader says nosniff": 23, + "a shared manifest read that fails answers every file of the Wiki that joined it with its error, and a file asked for after it is read again and served": 6, + "a style sheet that an update adds after the reader has served a file of the Wiki is served": 12, + "a style sheet, an image and a font asked for at once cost one manifest read between them, and the reader’s own script and a page asked for as an image are answered without one": 16, + "a window whose forward goes to another host gets a 403 that says the reader answers only on this computer": 3, + "an asset of the Wiki is sent byte for byte from its opened file in parts, only as far as its size at its stat, and no file is read whole into the editor’s process": 17, + "an asset whose path holds a named pipe is refused at once with 403, and no read of it waits for a writer": 9, + "an empty style sheet of the Wiki is served as an empty answer with status 200": 11, + "an image of the Wiki that another file replaced while its browser waited is ended there, and its browser gets no byte of the other file": 25, + "an image of the Wiki that its browser reads slowly but steadily is received whole, though receiving it takes longer than the send limit": 2292, + "an image of the Wiki that shrinks after the reader looked at its size is sent only as far as the bytes it still holds": 10, + "an image of the Wiki whose browser goes before it has received the image has no file of it open, and no part of it is read after the browser went": 12, + "an image of the Wiki whose browser stops reading but keeps sending bytes is still ended at the send limit": 512, + "an image of the Wiki whose browser stops reading has its file closed well before the publisher’s swap gives up, while its answer still waits for the browser": 1532, + "an image of the Wiki whose browser stops reading is ended at the send limit, and its file is closed": 514, + "closing the reader while a question is in flight stops the question and ends at once": 5, + "every page the reader serves lets only script files of its own origin and the shell’s script by its known hash run, and the reader’s own tag carries no secret: a script written into a page file or into an asset that is an HTML file runs nowhere": 6, + "generated Wiki reader refuses a published symlink escaping its output directory": 10, + "generated Wiki reader refuses malformed source identities rather than showing false freshness": 2, + "generated Wiki reader serves published pages and answers an explicit same-origin question": 72, + "in a local window only the reader’s own origin is accepted": 6, + "pages that their worker refuses and pages whose open fails give their places back, so the page asked for after twelve of them is served": 17, + "pages whose browser goes while the reader opens them keep their places until the reader has stopped: no more than six are opened at once, a page asked for meanwhile is refused as busy, no page is read after its browser went, and a page asked for after them is served": 15, + "six pages asked for at once cost one manifest read between them and are all served": 32, + "six pages whose path a folder takes after the reader’s look are each refused with 403 and give their places back, so the page asked for after them is served": 34, + "the reader refuses a Wiki whose .codebook folder has a real path the system cannot name (EACCES) with the sentence of a folder above the Wiki folder, not the system’s error": 9, + "the reader refuses a Wiki whose .codebook folder has a real path the system cannot name (EINVAL) with the sentence of a folder above the Wiki folder, not the system’s error": 5, "the reader refuses a Wiki whose `.codebook` folder in the project is a link to a folder outside it, names the link and opens nothing behind it": 10, - "the reader refuses a Wiki whose folder `.codebook/wiki` in the project is itself a link to a folder outside it, names the folder and opens nothing behind it": 2, - "the reader’s look refuses a Wiki folder, and a folder above it, that lstat calls a directory although its real path leaves the project": 8, - "the reader’s manifest read does not follow a link to a regular manifest elsewhere, while the same manifest as a file of the Wiki folder is read": 7, - "the reader’s manifest read does not wait on a link to a named pipe at the manifest’s path: it refuses at once and names the file": 12, - "the reader’s own script, a style sheet and an image of the Wiki are served to a browser that asks for them as a script, a style and an image": 10, - "the reader’s policy names the hash of the one script the shell of this build carries and of the one the shell of 0.2.29.0 and every shell before it carries": 6, - "the same published Wiki opens source and update links in the active editor without rewriting static files": 11, - "while six pages are in hand, a further page is refused at once with 503 and a sentence to reload it in a moment, and its file is not opened, and once the six are served a page asked for after them is served": 16, - "while six pages are in hand, a further page is refused with a page typed as HTML and served under the page policy": 14, - "while six pages are in hand, a further page request is refused at once with 503 and a sentence to reload it in a moment, without the manifest or the publication identity being read": 9 + "the reader refuses a Wiki whose folder `.codebook/wiki` in the project is itself a link to a folder outside it, names the folder and opens nothing behind it": 5, + "the reader’s look refuses a Wiki folder, and a folder above it, that lstat calls a directory although its real path leaves the project": 4, + "the reader’s manifest read does not follow a link to a regular manifest elsewhere, while the same manifest as a file of the Wiki folder is read": 8, + "the reader’s manifest read does not wait on a link to a named pipe at the manifest’s path: it refuses at once and names the file": 13, + "the reader’s own script, a style sheet and an image of the Wiki are served to a browser that asks for them as a script, a style and an image": 6, + "the reader’s policy names the hash of the one script the shell of this build carries and of the one the shell of 0.2.29.0 and every shell before it carries": 7, + "the same published Wiki opens source and update links in the active editor without rewriting static files": 12, + "while six pages are in hand, a further page is refused at once with 503 and a sentence to reload it in a moment, and its file is not opened, and once the six are served a page asked for after them is served": 8, + "while six pages are in hand, a further page is refused with a page typed as HTML and served under the page policy": 9, + "while six pages are in hand, a further page request is refused at once with 503 and a sentence to reload it in a moment, without the manifest or the publication identity being read": 7 } }, "deepWikiReaderOpening.test.js": { - "totalMs": 169 + "totalMs": 156 }, "deepWikiReaderUpdateStatus.test.js": { - "totalMs": 123 + "totalMs": 117 }, "deepWikiSource.test.js": { "totalMs": 4 @@ -514,6 +523,9 @@ "describeNodeLearningSave.test.js": { "totalMs": 2 }, + "describeNodeRecordedSource.test.js": { + "totalMs": 6 + }, "describeNodeTestReplay.test.js": { "totalMs": 1 }, @@ -521,7 +533,7 @@ "totalMs": 0 }, "describeOtherWikiWindow.test.js": { - "totalMs": 14 + "totalMs": 11 }, "describeRefusedLinkBack.test.js": { "totalMs": 0 @@ -530,7 +542,7 @@ "totalMs": 1 }, "describeUnansweredWikiChat.test.js": { - "totalMs": 1 + "totalMs": 0 }, "describeViewportDelivery.test.js": { "totalMs": 1 @@ -545,16 +557,16 @@ "totalMs": 0 }, "describeWikiUpdate.test.js": { - "totalMs": 3 + "totalMs": 4 }, "detectWikiPublishConflicts.test.js": { - "totalMs": 181 + "totalMs": 184 }, "dropSecondNameOfMovedFile.test.js": { - "totalMs": 27 + "totalMs": 30 }, "editorChatOnboarding.test.js": { - "totalMs": 93 + "totalMs": 87 }, "editorLayout.test.js": { "totalMs": 3 @@ -563,7 +575,7 @@ "totalMs": 2 }, "editorShowsDocument.test.js": { - "totalMs": 0 + "totalMs": 1 }, "editorTabInputKinds.test.js": { "totalMs": 1 @@ -581,43 +593,43 @@ "totalMs": 1 }, "endOfWikiChatStart.test.js": { - "totalMs": 2 + "totalMs": 1 }, "entryAfterRejectedMove.test.js": { "totalMs": 2 }, "environment.test.js": { - "totalMs": 41 + "totalMs": 40 }, "escapeHtml.test.js": { "totalMs": 0 }, "evidenceInUseElsewhere.test.js": { - "totalMs": 23 + "totalMs": 18 }, "extension.test.js": { - "totalMs": 2411 + "totalMs": 2429 }, "failureOfWikiChatReplyEnd.test.js": { "totalMs": 1 }, "fakeClock.test.js": { - "totalMs": 1013 + "totalMs": 944 }, "fileSystemWhoseLinksResistRemoval.test.js": { - "totalMs": 3 + "totalMs": 4 }, "findLinkOnWikiPath.test.js": { "totalMs": 4 }, "findUnacknowledgedWikiLeftover.test.js": { - "totalMs": 26 + "totalMs": 21 }, "findUnmappedDeclaredStop.test.js": { "totalMs": 1 }, "findWikiUpdateStartBlock.test.js": { - "totalMs": 3636 + "totalMs": 3619 }, "focusEditorGroupCommand.test.js": { "totalMs": 1 @@ -626,7 +638,7 @@ "totalMs": 1 }, "formatClockTime.test.js": { - "totalMs": 10 + "totalMs": 9 }, "formatWaitEnd.test.js": { "totalMs": 10 @@ -662,13 +674,13 @@ "totalMs": 1 }, "inspectDeepWikiFreshness.test.js": { - "totalMs": 1505 + "totalMs": 1532 }, "inspectNodeTestVariables.test.js": { "totalMs": 1 }, "installShortcutHelp.test.js": { - "totalMs": 3 + "totalMs": 2 }, "isAcknowledgedWikiLeftover.test.js": { "totalMs": 1 @@ -701,10 +713,10 @@ "totalMs": 4 }, "isFolderOfItsOwn.test.js": { - "totalMs": 8 + "totalMs": 7 }, "isFrameAtPosition.test.js": { - "totalMs": 0 + "totalMs": 1 }, "isFromEarlierBoot.test.js": { "totalMs": 1 @@ -743,7 +755,7 @@ "totalMs": 6 }, "isRecordedOwnerGone.test.js": { - "totalMs": 69 + "totalMs": 67 }, "isRefreshedFrameAtStop.test.js": { "totalMs": 1 @@ -752,7 +764,7 @@ "totalMs": 2 }, "isSameStorageMachine.test.js": { - "totalMs": 2 + "totalMs": 1 }, "isSavedBindingReceiptAtStop.test.js": { "totalMs": 2 @@ -767,7 +779,7 @@ "totalMs": 1 }, "isStopCausedByCodebook.test.js": { - "totalMs": 0 + "totalMs": 1 }, "isStopKeyboardHandOverDue.test.js": { "totalMs": 1 @@ -779,46 +791,46 @@ "totalMs": 3 }, "jsonPages.test.js": { - "totalMs": 3 + "totalMs": 2 }, "labelQuestionField.test.js": { "totalMs": 1 }, "launchNodeTest.test.js": { - "totalMs": 1257 + "totalMs": 1251 }, "layoutKeepsEveryGroup.test.js": { "totalMs": 2 }, "learning.test.js": { - "totalMs": 1249 + "totalMs": 1236 }, "learningSummary.test.js": { - "totalMs": 1267 + "totalMs": 1303 }, "leavesStopForNoStop.test.js": { "totalMs": 4 }, "legacyMigration.test.js": { - "totalMs": 33 + "totalMs": 32 }, "libraryHasRoom.test.js": { "totalMs": 1 }, "listFolderTreeWithoutFollowing.test.js": { - "totalMs": 21 + "totalMs": 15 }, "listMissingNodeLearning.test.js": { - "totalMs": 1 + "totalMs": 2 }, "listProcesses.test.js": { - "totalMs": 402 + "totalMs": 397 }, "listVitestTestFiles.test.js": { - "totalMs": 6223 + "totalMs": 6194 }, "listWikiCandidates.test.js": { - "totalMs": 608 + "totalMs": 625 }, "listsEveryTabGroup.test.js": { "totalMs": 1 @@ -827,7 +839,7 @@ "totalMs": 1 }, "maximizedEditorAreaWidthPx.test.js": { - "totalMs": 2 + "totalMs": 1 }, "mayWikiChatStillPublish.test.js": { "totalMs": 1 @@ -836,7 +848,7 @@ "totalMs": 1 }, "modifiedAtMsOf.test.js": { - "totalMs": 3 + "totalMs": 7 }, "namesLineNumber.test.js": { "totalMs": 0 @@ -845,229 +857,235 @@ "totalMs": 0 }, "nativeParticipants.test.js": { - "totalMs": 43225, + "totalMs": 42783, "tests": { "130 instrumentation pauses of the runtime leave the journal room for a later pause the debugger makes for itself, and their resumes past the cap are counted, not journaled": 268, - "130 pauses the debugger makes and resumes before the action are journaled up to the limit with their resumes, and the rest of both are counted": 140, - "CDP runtime resume during stack refresh invalidates the original captured pause": 220, - "Codebook refuses continuation during an unconfirmed native stack refresh without revoking the actual pause": 224, + "130 pauses the debugger makes and resumes before the action are journaled up to the limit with their resumes, and the rest of both are counted": 129, + "CDP runtime resume during stack refresh invalidates the original captured pause": 227, + "Codebook refuses continuation during an unconfirmed native stack refresh without revoking the actual pause": 219, "a bounded wait that has ended is no longer reported as in progress, so a test waiting for the next one does not act early": 375, - "a browser DAP stop during a server-only result remains a competing pause": 278, - "a browser pause on the next stop’s line that comes while that stop is being armed is never captured as that stop, when the debugger announces it after the continuation": 283, - "a browser pause on the next stop’s line that comes while that stop is being armed is never captured as that stop, when the debugger announces it while the continue response is outstanding": 329, - "a browser pause on the next stop’s line that the page made before the continue request is read before the continuation exists and is never captured as that stop": 275, - "a browser pause the debugger makes and resumes in a run without browser stops is journaled with its place and duration": 220, - "a browser stop announced for a pause that was held since before its turn for longer than the debugger holds its own pauses fails at once, naming the early pause": 275, - "a browser stop declared after a server stop does not pause when its line runs before its turn, and both stops commit in declared order": 387, - "a browser stop declared before a server stop is armed before input and the server stop only inside the browser continuation": 376, - "a browser stop that binds on another line while the server is paused ends the run at once without resuming the server": 228, - "a browser stop the debugger announces while a server stop is held ends the run as an additional stop": 265, - "a changed native source location after stack refresh cannot reuse the captured pause": 270, - "a competing browser resume request while the server is paused invalidates the run": 240, - "a continuation that cannot read the other participant’s earlier pauses ends saying that no resume was sent, not as an uncertain continuation": 220, - "a continuation that reaches no next stop while the server stays paused at a pause the debugger made for itself ends the run naming where the server is paused": 274, - "a continued and a pause the debugger makes for itself after the last continuation do not end the run, and it completes": 295, - "a continued the debugger sends after the next declared stop’s stopped was queued ends the run as an unowned continuation": 372, - "a continued the debugger sends for its own resume after the next declared stop’s pause was queued does not end the run": 517, - "a deadline whose paused place cannot be read still fails the run with its own text": 271, - "a debugger hook that pauses and resumes 130 times journals 100 of those pauses and the count of the rest, and the run completes": 269, - "a declared stop whose stopped event is read before the debugger’s own pause in its module is still captured, after the continuation": 505, - "a declared stop whose stopped event is read before the debugger’s own pause in its module is still captured, before the continue response": 505, - "a different native thread cannot re-adopt the captured generation during stack refresh": 223, - "a failed server registration rejects the operation before any browser input": 114, + "a browser DAP stop during a server-only result remains a competing pause": 270, + "a browser pause on the next stop’s line that comes while that stop is being armed is never captured as that stop, when the debugger announces it after the continuation": 304, + "a browser pause on the next stop’s line that comes while that stop is being armed is never captured as that stop, when the debugger announces it while the continue response is outstanding": 330, + "a browser pause on the next stop’s line that the page made before the continue request is read before the continuation exists and is never captured as that stop": 271, + "a browser pause the debugger makes and resumes in a run without browser stops is journaled with its place and duration": 214, + "a browser stop announced for a pause that was held since before its turn for longer than the debugger holds its own pauses fails at once, naming the early pause": 266, + "a browser stop declared after a server stop does not pause when its line runs before its turn, and both stops commit in declared order": 373, + "a browser stop declared before a server stop is armed before input and the server stop only inside the browser continuation": 366, + "a browser stop that binds on another line while the server is paused ends the run at once without resuming the server": 231, + "a browser stop the debugger announces while a server stop is held ends the run as an additional stop": 222, + "a changed native source location after stack refresh cannot reuse the captured pause": 273, + "a competing browser resume request while the server is paused invalidates the run": 219, + "a continuation that cannot read the other participant’s earlier pauses ends saying that no resume was sent, not as an uncertain continuation": 229, + "a continuation that reaches no next stop while the server stays paused at a pause the debugger made for itself ends the run naming where the server is paused": 276, + "a continued and a pause the debugger makes for itself after the last continuation do not end the run, and it completes": 281, + "a continued the debugger sends after the next declared stop’s stopped was queued ends the run as an unowned continuation": 365, + "a continued the debugger sends for its own resume after the next declared stop’s pause was queued does not end the run": 481, + "a deadline whose paused place cannot be read still fails the run with its own text": 275, + "a debugger hook that pauses and resumes 130 times journals 100 of those pauses and the count of the rest, and the run completes": 267, + "a declared stop whose stopped event is read before the debugger’s own pause in its module is still captured, after the continuation": 433, + "a declared stop whose stopped event is read before the debugger’s own pause in its module is still captured, before the continue response": 463, + "a different native thread cannot re-adopt the captured generation during stack refresh": 224, + "a failed server registration rejects the operation before any browser input": 184, "a failed server replacement rejects the operation before any browser input": 171, - "a fast browser stop waits for the prior server continuation response before gaining authority": 431, - "a first server stop whose breakpoint was removed after the input ends the run at the deadline saying the debugger no longer acknowledged it": 163, - "a held browser CDP pause during a server-only result cannot claim completion": 531, - "a late acknowledgement of a server stop’s first registration does not change the binding of its second request": 473, - "a later browser stop the debugger binds on the next line of its citation is armed inside the continuation, resumed and captured at the bound line": 391, - "a later browser stop whose already loaded module differs from its sealed bundle is refused at preparation, before any input": 117, - "a later server stop declared on an unmapped line in a module that is already loaded is requested at the first mapped position after it inside the continuation and captured there": 447, - "a later server stop declared on an unmapped line whose request the adapter refuses answers that the next declared stop was not armed and no resume was sent": 274, - "a later server stop in a loaded module that the adapter acknowledged on the next line and that is not reached ends the run naming the bound place and that this line must run": 285, - "a later server stop on a line that declares the binding it requires, in a partly scanned module the server has not loaded at its turn, is refused before the browser stop is resumed": 216, - "a later server stop on the first line of a declaration over several lines, in a partly scanned module the server already loaded, is requested on the first line after the statement that can pause": 247, - "a later server stop registered pending that the adapter reports bound on the next line and that is not reached ends the run naming the bound place": 269, - "a later server stop that pauses on another line of its module while the preceding continue response is outstanding fails naming the declared stop and where it landed": 422, - "a later server stop whose breakpoint was removed after its continuation ends the run at the deadline saying the debugger no longer acknowledged it": 278, - "a later server stop whose newer registration request the adapter left unanswered ends the run at the deadline saying no current receipt could be read": 276, - "a later server stop whose registration is acknowledged on another line ends the run naming that stop, without resuming": 272, - "a later server stop whose registration is still pending when its deadline passes ends the run saying the breakpoint was never verified": 279, - "a later server stop whose registration the adapter acknowledges on the next line is accepted and captured there without waiting for a pause on the declared line": 429, - "a later server stop whose registration the debugger verifies past mapped lines without break locations is requested again, armed and captured there": 480, - "a later stop on a line the sealed map never reaches is refused at preparation, before any application input": 72, - "a later stop whose pause arrived but that the debugger never announced ends the run at its deadline saying where the participant is paused": 270, - "a learner’s breakpoint where a server stop’s first request was bound stays when the stop is requested again": 433, - "a page paused at a server stop’s breakpoint in its stub of the server module is resumed before the input, and a run that declares a server and a browser stop captures every stop": 454, - "a page paused at a server stop’s breakpoint in its stub of the server module is resumed before the input, and a run that declares only a server stop captures every stop": 277, - "a pause held in an accepted server stop’s module that is resumed during the wait for that stop’s own pause after more than a second ends the run as a manual or competing resume": 173, - "a pause no stop announced counts as the adapter’s own for exactly as long as a stop’s own pause is awaited": 280, - "a pause the debugger makes for itself before the continue response arrives is not queued as the next declared stop": 439, - "a pause the debugger makes for itself in the browser while a server stop is being captured leaves that capture valid, and the run completes": 446, - "a pause the debugger makes for itself in the browser while a server stop is held is retired without ending that stop’s paused interval": 839, - "a pause the debugger makes for itself in the next stop’s module and resumes does not end the run when its continued is read before its pause": 433, - "a pause the debugger makes for itself in the next stop’s module and resumes does not end the run when its pause is read before its continued": 428, - "a pause the debugger makes for itself on the server while a browser stop is next does not end the run": 403, - "a pause the debugger makes past the end of the expected server stop’s module and resumes is retired, and the stop is captured": 375, - "a paused frame at another column than the paused binding on the same line never publishes captured facts": 169, - "a paused server binding under another adapter id than its registration never publishes captured facts": 163, + "a fast browser stop waits for the prior server continuation response before gaining authority": 392, + "a first server stop whose breakpoint was removed after the input ends the run at the deadline saying the debugger no longer acknowledged it": 171, + "a held browser CDP pause during a server-only result cannot claim completion": 528, + "a late acknowledgement of a server stop’s first registration does not change the binding of its second request": 456, + "a later browser stop the debugger binds on the next line of its citation is armed inside the continuation, resumed and captured at the bound line": 390, + "a later browser stop whose already loaded module differs from its sealed bundle is refused at preparation, before any input": 111, + "a later server stop declared on an unmapped line in a module that is already loaded is requested at the first mapped position after it inside the continuation and captured there": 427, + "a later server stop declared on an unmapped line whose request the adapter refuses answers that the next declared stop was not armed and no resume was sent": 270, + "a later server stop in a loaded module that the adapter acknowledged on the next line and that is not reached ends the run naming the bound place and that this line must run": 269, + "a later server stop on a line that declares the binding it requires, in a partly scanned module the server has not loaded at its turn, is refused before the browser stop is resumed": 213, + "a later server stop on the first line of a declaration over several lines, in a partly scanned module the server already loaded, is requested on the first line after the statement that can pause": 241, + "a later server stop registered pending that the adapter reports bound on the next line and that is not reached ends the run naming the bound place": 265, + "a later server stop that pauses on another line of its module while the preceding continue response is outstanding fails naming the declared stop and where it landed": 384, + "a later server stop whose breakpoint was removed after its continuation ends the run at the deadline saying the debugger no longer acknowledged it": 270, + "a later server stop whose newer registration request the adapter left unanswered ends the run at the deadline saying no current receipt could be read": 277, + "a later server stop whose registration is acknowledged on another line ends the run naming that stop, without resuming": 283, + "a later server stop whose registration is still pending when its deadline passes ends the run saying the breakpoint was never verified": 268, + "a later server stop whose registration the adapter acknowledges on the next line is accepted and captured there without waiting for a pause on the declared line": 434, + "a later server stop whose registration the debugger verifies past mapped lines without break locations is requested again, armed and captured there": 477, + "a later stop on a line the sealed map never reaches is refused at preparation, before any application input": 85, + "a later stop whose pause arrived but that the debugger never announced ends the run at its deadline saying where the participant is paused": 265, + "a learner’s breakpoint where a server stop’s first request was bound stays when the stop is requested again": 437, + "a page paused at a server stop’s breakpoint in its stub of the server module is resumed before the input, and a run that declares a server and a browser stop captures every stop": 801, + "a page paused at a server stop’s breakpoint in its stub of the server module is resumed before the input, and a run that declares only a server stop captures every stop": 384, + "a pause held in an accepted server stop’s module that is resumed during the wait for that stop’s own pause after more than a second ends the run as a manual or competing resume": 167, + "a pause no stop announced counts as the adapter’s own for exactly as long as a stop’s own pause is awaited": 269, + "a pause the debugger makes for itself before the continue response arrives is not queued as the next declared stop": 428, + "a pause the debugger makes for itself in the browser while a server stop is being captured leaves that capture valid, and the run completes": 426, + "a pause the debugger makes for itself in the browser while a server stop is held is retired without ending that stop’s paused interval": 433, + "a pause the debugger makes for itself in the next stop’s module and resumes does not end the run when its continued is read before its pause": 429, + "a pause the debugger makes for itself in the next stop’s module and resumes does not end the run when its pause is read before its continued": 426, + "a pause the debugger makes for itself on the server while a browser stop is next does not end the run": 451, + "a pause the debugger makes past the end of the expected server stop’s module and resumes is retired, and the stop is captured": 366, + "a paused frame at another column than the paused binding on the same line never publishes captured facts": 162, + "a paused server binding under another adapter id than its registration never publishes captured facts": 170, "a pending first server stop that the click does not reach within 20 s ends the run naming the stop, its pending registration and that the action may still be running": 162, - "a read of the run resource made between a server pause and its committed observation does not answer a paused state without the observation": 224, - "a result already visible before input cannot establish completion": 198, - "a resume request nobody reserved while the server is paused at a pause nobody announced ends the run as a competing resume": 363, - "a run does not complete while the browser is paused for the runtime’s own instrumentation, and completes once that pause is resumed": 432, - "a run does not complete while the server is still paused at a pause the debugger made for itself, and completes once that pause is resumed": 330, - "a run stopped while a server stop is being requested a second time leaves no owned breakpoint and sends no resume": 371, - "a run stopped while its next stop is still being armed ends without resuming the paused server and without a binding failure": 223, - "a run with a server stop attaches its server debugger without making the editor save the learner’s unsaved documents": 115, - "a second pause while the server still holds a pause nobody announced ends the run as an additional stop": 337, - "a second pause while the server still holds its next declared pause, queued behind the continuation ends the run as an additional stop": 398, - "a server pause in a script that carries the id of the browser stop’s module is not taken for the browser stop, and the run completes": 438, + "a read of the run resource made between a server pause and its committed observation does not answer a paused state without the observation": 227, + "a result already visible before input cannot establish completion": 260, + "a resume request nobody reserved while the server is paused at a pause nobody announced ends the run as a competing resume": 412, + "a run does not complete while the browser is paused for the runtime’s own instrumentation, and completes once that pause is resumed": 420, + "a run does not complete while the server is still paused at a pause the debugger made for itself, and completes once that pause is resumed": 336, + "a run stopped while a server stop is being requested a second time leaves no owned breakpoint and sends no resume": 376, + "a run stopped while its next stop is still being armed ends without resuming the paused server and without a binding failure": 225, + "a run with a server stop attaches its server debugger without making the editor save the learner’s unsaved documents": 118, + "a second pause while the server still holds a pause nobody announced ends the run as an additional stop": 345, + "a second pause while the server still holds its next declared pause, queued behind the continuation ends the run as an additional stop": 366, + "a server pause in a script that carries the id of the browser stop’s module is not taken for the browser stop, and the run completes": 415, "a server pause no debugger stop announced that is resumed after more than three seconds ends the run as a manual or competing resume": 271, - "a server pause no debugger stop announced that is resumed within three seconds is still retired and the run goes on": 374, - "a server pause the debugger makes for itself after the last stop was continued and resumes after more than a second, within its three seconds, is retired and the run does not fail": 216, - "a server stop armed in an already loaded module and acknowledged at another column of its line commits at the bound column": 446, - "a server stop bound past a line of its function where the debugger can pause fails naming that line’s break location": 169, - "a server stop declared on a line the sealed map has no position on is requested at the first mapped position after it in its citation and captured there": 276, - "a server stop on a function head whose lines have mapped positions but no break locations is captured where the debugger paused, and the journal names the break locations that decided it": 285, - "a server stop on the first line of a declaration over several lines in a partly scanned module the server has not loaded is refused before the input, naming the line after the statement": 124, - "a server stop requested after its unmapped declared line that pauses on the line after the requested one is captured there": 279, - "a server stop requested after its unmapped declared line whose registration the adapter refuses names the place it was requested at, not a declared place": 113, - "a server stop that still cannot be bound on its line after one new request is refused and told to declare the statement’s column": 319, - "a server stop the adapter acknowledged across a mapped line although its own line can pause is requested again on its line and pauses there": 483, - "a server stop the adapter acknowledged across a mapped line twice is refused after one new request and told to declare the statement’s column": 333, - "a server stop the adapter reports verified on a line its rule refuses after acknowledging it ends the action before any input is sent, naming that place and why it is refused": 178, - "a server stop the debugger announces and pauses on another line of its module fails naming the declared stop and where it landed": 183, - "a server stop the debugger announces while a browser stop is next ends the run as an additional stop": 314, - "a server stop the debugger binds and pauses across a line that has a mapped position fails naming the declared stop and where it landed": 168, - "a server stop the debugger binds and pauses on an earlier line of its citation fails naming the declared stop and where it landed": 169, + "a server pause no debugger stop announced that is resumed within three seconds is still retired and the run goes on": 370, + "a server pause the debugger makes for itself after the last stop was continued and resumes after more than a second, within its three seconds, is retired and the run does not fail": 215, + "a server stop armed in an already loaded module and acknowledged at another column of its line commits at the bound column": 426, + "a server stop bound past a line of its function where the debugger can pause fails naming that line’s break location": 173, + "a server stop declared on a line the sealed map has no position on is requested at the first mapped position after it in its citation and captured there": 278, + "a server stop on a function head whose lines have mapped positions but no break locations is captured where the debugger paused, and the journal names the break locations that decided it": 290, + "a server stop on the first line of a declaration over several lines in a partly scanned module the server has not loaded is refused before the input, naming the line after the statement": 121, + "a server stop requested after its unmapped declared line that pauses on the line after the requested one is captured there": 269, + "a server stop requested after its unmapped declared line whose registration the adapter refuses names the place it was requested at, not a declared place": 123, + "a server stop that still cannot be bound on its line after one new request is refused and told to declare the statement’s column": 324, + "a server stop the adapter acknowledged across a mapped line although its own line can pause is requested again on its line and pauses there": 484, + "a server stop the adapter acknowledged across a mapped line twice is refused after one new request and told to declare the statement’s column": 362, + "a server stop the adapter reports verified on a line its rule refuses after acknowledging it ends the action before any input is sent, naming that place and why it is refused": 170, + "a server stop the debugger announces and pauses on another line of its module fails naming the declared stop and where it landed": 181, + "a server stop the debugger announces while a browser stop is next ends the run as an additional stop": 303, + "a server stop the debugger binds and pauses across a line that has a mapped position fails naming the declared stop and where it landed": 167, + "a server stop the debugger binds and pauses on an earlier line of its citation fails naming the declared stop and where it landed": 165, "a server stop the debugger binds and pauses two lines below fails when the sealed map is too large to scan the line between": 176, - "a server stop the debugger binds at another column of its declared line commits at the bound column": 285, - "a server stop the debugger binds on another line fails naming the declared stop, where it landed and the mapped positions": 171, - "a server stop whose acknowledged binding moved to the next line although its own line can pause is requested again on its line and pauses there": 487, - "a server stop whose binding is first known at its pause and lies past a line that can pause is committed there, and its inspection names both lines and the column that pauses on the declared one": 236, - "a server stop whose breakpoint is removed after the continuation that armed it fails at its pause naming the stop and that it was not registered": 329, + "a server stop the debugger binds at another column of its declared line commits at the bound column": 268, + "a server stop the debugger binds on another line fails naming the declared stop, where it landed and the mapped positions": 167, + "a server stop whose acknowledged binding moved to the next line although its own line can pause is requested again on its line and pauses there": 481, + "a server stop whose binding is first known at its pause and lies past a line that can pause is committed there, and its inspection names both lines and the column that pauses on the declared one": 220, + "a server stop whose breakpoint is removed after the continuation that armed it fails at its pause naming the stop and that it was not registered": 328, "a server stop whose breakpoint the adapter moves to a refused line after the input ends the run at the deadline naming that place, why it is refused and what to declare": 163, - "a server stop whose breakpoint the learner removed before the input fails naming the stop and the removal, without mapping hints": 189, - "a server stop whose pause is taken from one held on another line of its module journals that adoption with its place": 181, - "a server stop whose pending breakpoint the debugger reports verified past a function head while the page is read before the input still gets its input and is captured": 219, - "a server stop whose pending breakpoint the debugger reports verified past a function head without break locations is matched at its pause without waiting": 320, - "a server stop whose pending breakpoint the debugger reports verified past a function head without break locations, after the input, is captured where it paused": 282, - "a server stop whose pending breakpoint the debugger reports verified past a function head without break locations, before the input, is captured where it paused": 221, - "a server stop whose pending registration binds on the next line is captured at its announced pause there without waiting for a pause on the declared line": 270, - "a server stop with changed binding never publishes captured facts": 176, - "a server stop with changed binding-source never publishes captured facts": 191, - "a server stop with changed source never publishes captured facts": 174, - "a stack refresh before the binding at another column of the declared line does not move the stop from the position the debugger then binds": 275, - "a stack refresh before the binding that reports another file cannot reuse the pause": 166, - "a stack refresh before the binding that reports another line cannot reuse the pause": 172, - "a stack refresh that arrives before a server stop’s bound position is known keeps the pause and the stop commits at the bound position": 272, - "a stack refresh that arrives before the binding of a server stop moved to the next line is read keeps the pause and the stop commits at the bound line": 277, - "a stack refresh that reports the bound position keeps the captured pause of a stop whose column moved": 281, - "a stack refresh that reports the requested column instead of the bound one cannot reuse the captured pause": 270, - "a stack refresh while a server stop bound on another line is still waited for does not hide the binding failure": 228, - "a stop announced on another thread after a stack refresh that came while a server stop’s own pause was awaited ends the run instead of passing as the refresh’s re-announcement": 165, - "a worker session of the browser that ends while a server stop is held leaves that stop’s replay interval ending at its continuation": 279, - "after conditions that held only while the server was paused at the debugger’s own pause do not certify the result once it is resumed": 329, - "an accepted server stop whose own pause never arrives does not adopt a pause held in another original of its bundle": 172, - "an accepted server stop whose own pause never arrives fails waiting for it, without adopting a pause the debugger holds in another script": 330, - "an adapter pause on the line after a server stop that the adapter verified on its declared line is held, retired on its resume, and the run reaches the real stop": 433, - "an extra native stop without a refresh cannot claim an already captured pause": 240, - "an idle browser continuation while a server stop is current preserves the next owned pause": 531, - "an internal browser CDP pause that auto resumes cannot invalidate a server-only result": 324, - "an unrelated debugger stop cannot claim the configured server pause": 242, - "browser stack refresh preserves its captured pause and allows the declared path to complete": 594, - "closing during delayed stack refresh verification cannot revive the captured pause": 229, - "manually resuming a queued browser stop cannot reuse the previous server continuation": 304, - "native client resume during stack refresh invalidates the original captured pause": 216, - "one input retains server/browser/server sources and independent native generations while video stays on the browser": 542, - "one owned Next worker with nested debugger sessions still reaches its first server stop": 233, - "preparation installs only the first declared stop, so a later stop cannot pause before its turn": 140, - "server registration revoked during the final DOM check prevents the mouse input": 164, - "server stack refresh preserves its captured pause and allows the declared path to complete": 591, - "server worker exit invalidates the whole operation and releases both owned transports": 129, - "the deadline text of a later server stop requested after its declared line names the requested place": 284, - "the deadline text of a server stop requested after its declared line names the requested place": 178, - "the harness holds only the next declared stop: after the held stop is released, the following stop pauses by itself": 538, - "the harness leaves the wait for an accepted stop’s own pause to the real wait when no seam enabled its substitution": 220, - "the harness’s substitution of the wait for an accepted stop’s own pause engages for that wait when expireSourceBoundWait enabled it": 218, - "the harness’s substitution of the wait for an accepted stop’s own pause engages for that wait when holdSourceBoundWait enabled it": 221, - "the main server pause is captured when a nested background worker shares its PID": 237, - "the runtime’s own instrumentation pause and resume in the browser while a server stop is held leaves that stop’s replay interval ending at its continuation": 379, - "two distinct owned server workers reject before application input": 143 + "a server stop whose breakpoint the learner removed before the input fails naming the stop and the removal, without mapping hints": 161, + "a server stop whose pause is taken from one held on another line of its module journals that adoption with its place": 175, + "a server stop whose pending breakpoint the debugger reports verified past a function head while the page is read before the input still gets its input and is captured": 221, + "a server stop whose pending breakpoint the debugger reports verified past a function head without break locations is matched at its pause without waiting": 323, + "a server stop whose pending breakpoint the debugger reports verified past a function head without break locations, after the input, is captured where it paused": 269, + "a server stop whose pending breakpoint the debugger reports verified past a function head without break locations, before the input, is captured where it paused": 215, + "a server stop whose pending registration binds on the next line is captured at its announced pause there without waiting for a pause on the declared line": 277, + "a server stop with changed binding never publishes captured facts": 170, + "a server stop with changed binding-source never publishes captured facts": 163, + "a server stop with changed source never publishes captured facts": 166, + "a stack refresh before the binding at another column of the declared line does not move the stop from the position the debugger then binds": 278, + "a stack refresh before the binding that reports another file cannot reuse the pause": 168, + "a stack refresh before the binding that reports another line cannot reuse the pause": 168, + "a stack refresh that arrives before a server stop’s bound position is known keeps the pause and the stop commits at the bound position": 270, + "a stack refresh that arrives before the binding of a server stop moved to the next line is read keeps the pause and the stop commits at the bound line": 271, + "a stack refresh that reports the bound position keeps the captured pause of a stop whose column moved": 280, + "a stack refresh that reports the requested column instead of the bound one cannot reuse the captured pause": 273, + "a stack refresh while a server stop bound on another line is still waited for does not hide the binding failure": 227, + "a stop announced on another thread after a stack refresh that came while a server stop’s own pause was awaited ends the run instead of passing as the refresh’s re-announcement": 170, + "a worker session of the browser that ends while a server stop is held leaves that stop’s replay interval ending at its continuation": 271, + "after conditions that held only while the server was paused at the debugger’s own pause do not certify the result once it is resumed": 325, + "an accepted server stop whose own pause never arrives does not adopt a pause held in another original of its bundle": 163, + "an accepted server stop whose own pause never arrives fails waiting for it, without adopting a pause the debugger holds in another script": 372, + "an adapter pause on the line after a server stop that the adapter verified on its declared line is held, retired on its resume, and the run reaches the real stop": 424, + "an extra native stop without a refresh cannot claim an already captured pause": 230, + "an idle browser continuation while a server stop is current preserves the next owned pause": 530, + "an internal browser CDP pause that auto resumes cannot invalidate a server-only result": 325, + "an unrelated debugger stop cannot claim the configured server pause": 224, + "browser stack refresh preserves its captured pause and allows the declared path to complete": 586, + "closing during delayed stack refresh verification cannot revive the captured pause": 234, + "manually resuming a queued browser stop cannot reuse the previous server continuation": 309, + "native client resume during stack refresh invalidates the original captured pause": 228, + "one input retains server/browser/server sources and independent native generations while video stays on the browser": 529, + "one owned Next worker with nested debugger sessions still reaches its first server stop": 239, + "preparation installs only the first declared stop, so a later stop cannot pause before its turn": 115, + "server registration revoked during the final DOM check prevents the mouse input": 188, + "server stack refresh preserves its captured pause and allows the declared path to complete": 593, + "server worker exit invalidates the whole operation and releases both owned transports": 174, + "the deadline text of a later server stop requested after its declared line names the requested place": 269, + "the deadline text of a server stop requested after its declared line names the requested place": 164, + "the harness holds only the next declared stop: after the held stop is released, the following stop pauses by itself": 525, + "the harness leaves the wait for an accepted stop’s own pause to the real wait when no seam enabled its substitution": 221, + "the harness’s substitution of the wait for an accepted stop’s own pause engages for that wait when expireSourceBoundWait enabled it": 220, + "the harness’s substitution of the wait for an accepted stop’s own pause engages for that wait when holdSourceBoundWait enabled it": 211, + "the main server pause is captured when a nested background worker shares its PID": 228, + "the runtime’s own instrumentation pause and resume in the browser while a server stop is held leaves that stop’s replay interval ending at its continuation": 384, + "two distinct owned server workers reject before application input": 66 } }, "nativeParticipantsBindingPlace.test.js": { - "totalMs": 13934, + "totalMs": 13837, "tests": { - "a browser stop declared on the line above a function whose line a statement at the module’s end is mapped to is armed and captured at the function’s first statement": 172, - "a browser stop requested at column 1 that the adapter verifies only by news after its reply is armed at the place the adapter reported": 220, + "a browser stop declared on the line above a function whose line a statement at the module’s end is mapped to is armed and captured at the function’s first statement": 174, + "a browser stop requested at column 1 that the adapter verifies only by news after its reply is armed at the place the adapter reported": 219, "a browser stop requested at column 1 whose binding the debugger moves along its line is taken at its held pause without waiting, by the column the adapter reported": 165, - "a browser stop requested at column 1 whose binding the debugger moves to the next line after it was armed is captured there, although the editor keeps no column of that news": 168, - "a continuation whose page stays paused at the next server stop’s breakpoint because the debugger never answers Codebook’s resume ends at its deadline naming that pause and the unanswered resume, and not a line to declare": 310, - "a page pause at a server stop’s breakpoint after the action was accepted is not ended by the 250 ms bound of an unowned page pause while the run’s own resume is under way, in a run that declares only a server stop": 268, - "a page pause at a server stop’s breakpoint after the action was accepted is not taken for a competing resume when the run’s own resume is slow, in a run that declares a browser stop too": 325, - "a page pause at a server stop’s breakpoint after the action was accepted whose resume the adapter refuses ends the run naming the place of that pause, the declared stop and the refusal": 226, - "a page pause at a server stop’s breakpoint that follows the debugger’s own pause at the module’s first position is not ended by the bound of an unowned page pause while the run’s resume has no answer, and the run goes on to its server stop": 303, - "a page pause at a server stop’s breakpoint that follows the debugger’s own pause at the module’s first position is not taken for a competing resume when the adapter answers late, in a run that declares a browser stop too": 365, - "a page pause at a server stop’s breakpoint that is read after the debugger answered Codebook’s resume and that the page never resumes ends the action at its deadline saying that the debugger answered and the page reported no resume, in a run that declares only a server stop": 221, - "a page pause at a server stop’s breakpoint that is read after the debugger answered Codebook’s resume and that the page never resumes is named at the deadline as the pause the debugger answered for, not as one without a debugger stop, in a run that declares a browser stop too": 221, - "a page pause at a server stop’s breakpoint that is read only after the run sent its resume is not bounded as a pause nobody owns": 279, - "a page pause at a server stop’s breakpoint whose resume the adapter refuses leaves the request in the journal and no entry that says resumed, and the run ends naming the declared stop and the refusal": 162, - "a page pause at the first position of another page script whose breakpoint was set by that script’s address, held while an accepted browser stop awaits its own pause and resumed after 1,001 ms, ends the run as a manual or competing resume": 224, - "a page pause in the stub of a declared server stop’s module that nobody resumes and no stopped event names ends the run after 3,000 ms, not earlier": 173, - "a page pause in the stub of a declared server stop’s module whose stopped event is read 300 ms later is resumed by the run, and the server stop is captured": 326, - "a page pause in the stub of a declared server stop’s module, held while an accepted browser stop awaits its own pause and resumed by the debugger after 1,500 ms, is not taken for a competing resume, and the browser stop is captured": 330, - "a page pause in the stub of the server stop’s module that is read more than 3,000 ms after the debugger answered Codebook’s resume keeps the stub’s own bound and ends a run without browser stops 3,000 ms later": 240, - "a page pause outside the stub of a declared server stop’s module still ends a run without browser stops after 250 ms": 176, - "a page pause outside the stub of the server stop’s module that is read right after the debugger answered Codebook’s resume still ends a run without browser stops after 250 ms": 220, - "a page pause whose breakpoints are a server stop’s and one of the page’s own is not resumed by the run: no resume is requested, no continue reaches the page, and the action ends for the unowned page stop": 160, - "a pause at the first position of another page script whose breakpoint was set by that script’s address still ends a run without browser stops after 250 ms": 169, - "a pause held in the accepted browser stop’s own module, when that module is also the page’s stub of a server stop’s module, and resumed after 1,001 ms still ends the run as a manual or competing resume": 220, - "a second page pause at a server stop’s breakpoint, whose stopped event was read before the first pause’s own events, is not ended by the bound of an unowned page pause while its resume is under way, and the run goes on to its server stop": 369, - "a second page pause at a server stop’s breakpoint, whose stopped event was read before the first pause’s own events, is not taken for a competing resume when the adapter answers late, in a run that declares a browser stop too": 376, + "a browser stop requested at column 1 whose binding the debugger moves to the next line after it was armed is captured there, although the editor keeps no column of that news": 169, + "a continuation whose page stays paused at the next server stop’s breakpoint because the debugger never answers Codebook’s resume ends at its deadline naming that pause and the unanswered resume, and not a line to declare": 286, + "a page pause at a server stop’s breakpoint after the action was accepted is not ended by the 250 ms bound of an unowned page pause while the run’s own resume is under way, in a run that declares only a server stop": 277, + "a page pause at a server stop’s breakpoint after the action was accepted is not taken for a competing resume when the run’s own resume is slow, in a run that declares a browser stop too": 324, + "a page pause at a server stop’s breakpoint after the action was accepted whose resume the adapter refuses ends the run naming the place of that pause, the declared stop and the refusal": 228, + "a page pause at a server stop’s breakpoint that follows the debugger’s own pause at the module’s first position is not ended by the bound of an unowned page pause while the run’s resume has no answer, and the run goes on to its server stop": 321, + "a page pause at a server stop’s breakpoint that follows the debugger’s own pause at the module’s first position is not taken for a competing resume when the adapter answers late, in a run that declares a browser stop too": 351, + "a page pause at a server stop’s breakpoint that is read after the debugger answered Codebook’s resume and that the page never resumes ends the action at its deadline saying that the debugger answered and the page reported no resume, in a run that declares only a server stop": 224, + "a page pause at a server stop’s breakpoint that is read after the debugger answered Codebook’s resume and that the page never resumes is named at the deadline as the pause the debugger answered for, not as one without a debugger stop, in a run that declares a browser stop too": 216, + "a page pause at a server stop’s breakpoint that is read only after the run sent its resume is not bounded as a pause nobody owns": 274, + "a page pause at a server stop’s breakpoint whose resume the adapter refuses leaves the request in the journal and no entry that says resumed, and the run ends naming the declared stop and the refusal": 168, + "a page pause at the first position of another page script whose breakpoint was set by that script’s address, held while an accepted browser stop awaits its own pause and resumed after 1,001 ms, ends the run as a manual or competing resume": 220, + "a page pause in the stub of a declared server stop’s module that nobody resumes and no stopped event names ends the run after 3,000 ms, not earlier": 168, + "a page pause in the stub of a declared server stop’s module whose stopped event is read 300 ms later is resumed by the run, and the server stop is captured": 322, + "a page pause in the stub of a declared server stop’s module, held while an accepted browser stop awaits its own pause and resumed by the debugger after 1,500 ms, is not taken for a competing resume, and the browser stop is captured": 331, + "a page pause in the stub of the server stop’s module that is read more than 3,000 ms after the debugger answered Codebook’s resume keeps the stub’s own bound and ends a run without browser stops 3,000 ms later": 226, + "a page pause outside the stub of a declared server stop’s module still ends a run without browser stops after 250 ms": 178, + "a page pause outside the stub of the server stop’s module that is read right after the debugger answered Codebook’s resume still ends a run without browser stops after 250 ms": 227, + "a page pause whose breakpoints are a server stop’s and one of the page’s own is not resumed by the run: no resume is requested, no continue reaches the page, and the action ends for the unowned page stop": 166, + "a pause at the first position of another page script whose breakpoint was set by that script’s address still ends a run without browser stops after 250 ms": 179, + "a pause held in the accepted browser stop’s own module, when that module is also the page’s stub of a server stop’s module, and resumed after 1,001 ms still ends the run as a manual or competing resume": 228, + "a second page pause at a server stop’s breakpoint, whose stopped event was read before the first pause’s own events, is not ended by the bound of an unowned page pause while its resume is under way, and the run goes on to its server stop": 361, + "a second page pause at a server stop’s breakpoint, whose stopped event was read before the first pause’s own events, is not taken for a competing resume when the adapter answers late, in a run that declares a browser stop too": 375, "a server pause that is read while a page pause in the stub of the server stop’s module waits, read too late after the debugger’s answer to be Codebook’s own, leaves it named at the action’s deadline as a pause without a debugger stop, in a run that declares a browser stop too": 230, - "a server pause that is read while a page pause in the stub of the server stop’s module waits, read too late after the debugger’s answer to be Codebook’s own, leaves that page pause its bound, and a run without browser stops ends 3,000 ms after the page paused": 218, - "a server stop above a function whose pending breakpoint the adapter reports verified at the first statement is matched at its pause, judged once by the place the map gives that report": 319, - "a server stop bound past a break location between the two generated places is refused naming that line, not the line of the statement at the module’s end": 224, - "a server stop declared on the line above a function whose line a statement at the module’s end is mapped to is captured at the function’s first statement, and the journal names only the lines on the way": 321, - "a server stop judged from its reported place before the pause is judged once more when it pauses at another generated place, and refused for the break location passed on the way there": 276, + "a server pause that is read while a page pause in the stub of the server stop’s module waits, read too late after the debugger’s answer to be Codebook’s own, leaves that page pause its bound, and a run without browser stops ends 3,000 ms after the page paused": 223, + "a server stop above a function whose pending breakpoint the adapter reports verified at the first statement is matched at its pause, judged once by the place the map gives that report": 320, + "a server stop bound past a break location between the two generated places is refused naming that line, not the line of the statement at the module’s end": 221, + "a server stop declared on the line above a function whose line a statement at the module’s end is mapped to is captured at the function’s first statement, and the journal names only the lines on the way": 318, + "a server stop judged from its reported place before the pause is judged once more when it pauses at another generated place, and refused for the break location passed on the way there": 266, "a server stop requested at column 1 whose binding the editor answers without a column at its pause is captured at the place the adapter reported, and the run goes on": 349, - "a server stop that pauses while the debugger still has to answer the break-location request is taken as soon as that judgement accepts its place, without the wait and without an adoption": 272, - "a server stop whose binding names another line than the paused frame and no column is still refused as not bound to the captured source": 160, - "a server stop whose binding names no column and whose adapter reported none is captured at the paused frame’s column on the binding’s line": 225, - "a server stop whose binding the break locations refuse leaves one journal entry of that judgement and one request for the break locations, although its receipt is read again at the pause": 272, - "a server stop whose breakpoint the adapter first reports at a place the map refuses and then, while the run waits for the module, at an accepted place is taken as registered there, and the run goes on to its stop": 419, - "a server stop whose pending breakpoint the adapter reports verified before the run has seen its module is judged when the module is announced, and matched at its pause without waiting": 323, - "a server stop whose pending breakpoint the adapter reports verified before the run has seen the module waits for the module before the input and is then judged by the break locations": 284, - "a server stop whose reported place the debugger lists no break location at is judged by every line with a break location, and no input is sent": 178, - "a server stop whose reported place the map refuses and whose module is not announced within the bound is refused before the input with the map’s reason": 388, - "an action that reaches no stop after the debugger answered Codebook’s resume of the page and the page’s two pauses were resumed ends at its deadline with the ordinary sentence, naming no pause of the page": 217, - "an action whose page stays paused at a server stop’s breakpoint although the debugger answered Codebook’s resume ends at its deadline saying that the debugger answered and the page reported no resume": 237, - "an action whose page stays paused at a server stop’s breakpoint because the debugger never answers Codebook’s resume ends at its deadline naming that pause once, as the pause Codebook is resuming and not as one without a debugger stop, in a run that declares a browser stop too": 176, - "an action whose page stays paused at a server stop’s breakpoint because the debugger never answers Codebook’s resume ends at its deadline naming that pause, the declared stop and the unanswered resume, and not a line to declare, in a run that declares only a server stop": 180, - "an action whose page stays paused at a server stop’s breakpoint, after the debugger’s own pause at the module’s first position was resumed, ends at its deadline naming the pause at the breakpoint and the unanswered resume": 174, - "the adapter stand-in holds back only the one resume of a page pause at a server stop’s breakpoint it was told to hold: the resume of a second such pause is answered at once while the first has no answer": 236, - "the adapter stand-in leaves the page paused only at the one answered resume it was told to: the resume of a second pause at the server stop’s breakpoint resumes the page, and its open pause is retired": 333, - "the adapter stand-in refuses only the one resume of a page pause at a server stop’s breakpoint it was told to refuse: the resume of a second such pause is answered": 207, - "the debugger’s own pause at the first position of a browser stop’s own module, held since before that stop’s turn for 1,500 ms and then resumed, is not refused as an early run of the stop’s line, and the stop is captured at its own pause": 325, - "the debugger’s own pause at the first position of another page script named like the server stop’s file, resumed after 300 ms, does not end a run without browser stops, and the server stop is captured": 283, - "the debugger’s own pause at the first position of another page script that nobody resumes ends a run without browser stops after 3,000 ms, not earlier": 167, - "the debugger’s own pause at the first position of another page script, held while an accepted browser stop awaits its own pause and resumed after 1,500 ms, is not taken for a competing resume, and the browser stop is captured": 333, - "the journal of a page pause at a server stop’s breakpoint holds Codebook’s resume request before the page’s resume, and the answered entry only after the debugger’s answer, which follows the page’s resume here": 220 + "a server stop that pauses while the debugger still has to answer the break-location request is taken as soon as that judgement accepts its place, without the wait and without an adoption": 279, + "a server stop whose binding names another line than the paused frame and no column is still refused as not bound to the captured source": 169, + "a server stop whose binding names no column and whose adapter reported none is captured at the paused frame’s column on the binding’s line": 224, + "a server stop whose binding the break locations refuse leaves one journal entry of that judgement and one request for the break locations, although its receipt is read again at the pause": 284, + "a server stop whose breakpoint the adapter first reports at a place the map refuses and then, while the run waits for the module, at an accepted place is taken as registered there, and the run goes on to its stop": 429, + "a server stop whose pending breakpoint the adapter reports verified before the run has seen its module is judged when the module is announced, and matched at its pause without waiting": 318, + "a server stop whose pending breakpoint the adapter reports verified before the run has seen the module waits for the module before the input and is then judged by the break locations": 272, + "a server stop whose reported place the debugger lists no break location at is judged by every line with a break location, and no input is sent": 175, + "a server stop whose reported place the map refuses and whose module is not announced within the bound is refused before the input with the map’s reason": 367, + "an action that reaches no stop after the debugger answered Codebook’s resume of the page and the page’s two pauses were resumed ends at its deadline with the ordinary sentence, naming no pause of the page": 214, + "an action whose page stays paused at a server stop’s breakpoint although the debugger answered Codebook’s resume ends at its deadline saying that the debugger answered and the page reported no resume": 235, + "an action whose page stays paused at a server stop’s breakpoint because the debugger never answers Codebook’s resume ends at its deadline naming that pause once, as the pause Codebook is resuming and not as one without a debugger stop, in a run that declares a browser stop too": 171, + "an action whose page stays paused at a server stop’s breakpoint because the debugger never answers Codebook’s resume ends at its deadline naming that pause, the declared stop and the unanswered resume, and not a line to declare, in a run that declares only a server stop": 177, + "an action whose page stays paused at a server stop’s breakpoint, after the debugger’s own pause at the module’s first position was resumed, ends at its deadline naming the pause at the breakpoint and the unanswered resume": 169, + "the adapter stand-in holds back only the one resume of a page pause at a server stop’s breakpoint it was told to hold: the resume of a second such pause is answered at once while the first has no answer": 241, + "the adapter stand-in leaves the page paused only at the one answered resume it was told to: the resume of a second pause at the server stop’s breakpoint resumes the page, and its open pause is retired": 308, + "the adapter stand-in refuses only the one resume of a page pause at a server stop’s breakpoint it was told to refuse: the resume of a second such pause is answered": 193, + "the debugger’s own pause at the first position of a browser stop’s own module, held since before that stop’s turn for 1,500 ms and then resumed, is not refused as an early run of the stop’s line, and the stop is captured at its own pause": 323, + "the debugger’s own pause at the first position of another page script named like the server stop’s file, resumed after 300 ms, does not end a run without browser stops, and the server stop is captured": 269, + "the debugger’s own pause at the first position of another page script that nobody resumes ends a run without browser stops after 3,000 ms, not earlier": 173, + "the debugger’s own pause at the first position of another page script, held while an accepted browser stop awaits its own pause and resumed after 1,500 ms, is not taken for a competing resume, and the browser stop is captured": 325, + "the journal of a page pause at a server stop’s breakpoint holds Codebook’s resume request before the page’s resume, and the answered entry only after the debugger’s answer, which follows the page’s resume here": 221 } }, "nativeParticipantsRecording.test.js": { - "totalMs": 2639 + "totalMs": 2615 }, "nativePaths.test.js": { - "totalMs": 3 + "totalMs": 2 }, "nativeRepositoryLauncher.test.js": { "totalMs": 6 }, + "nextNodeHistoryStepId.test.js": { + "totalMs": 1 + }, "nodeHistoryPlaybackController.test.js": { - "totalMs": 366 + "totalMs": 362 + }, + "nodeHistoryStepTarget.test.js": { + "totalMs": 1 }, "nodeInspectorEndpoint.test.js": { "totalMs": 1 @@ -1076,28 +1094,28 @@ "totalMs": 3 }, "nodeStopSourceMatches.test.js": { - "totalMs": 203 + "totalMs": 189 }, "nodeTestConfigSchemas.test.js": { "totalMs": 6 }, "nodeTestHelp.test.js": { - "totalMs": 463 + "totalMs": 446 }, "nodeTestHistoryStore.test.js": { - "totalMs": 1082 + "totalMs": 1076 }, "nodeTestHistorySummary.test.js": { - "totalMs": 375 + "totalMs": 343 }, "nodeTestOutputTerminal.test.js": { "totalMs": 2 }, "nodeTestRunLifecycle.test.js": { - "totalMs": 3226 + "totalMs": 3242 }, "nodeTestService.test.js": { - "totalMs": 1109 + "totalMs": 1088 }, "noticeWithSetupStep.test.js": { "totalMs": 2 @@ -1106,22 +1124,22 @@ "totalMs": 1 }, "openWithoutFollowing.test.js": { - "totalMs": 12 + "totalMs": 9 }, "ownedNodeTestRun.test.js": { - "totalMs": 2732 + "totalMs": 2665 }, "pagePauseUnderResumeText.test.js": { - "totalMs": 1 + "totalMs": 0 }, "paneKeyboardTimeoutMessage.test.js": { - "totalMs": 0 + "totalMs": 1 }, "parseApplicationGroupMarker.test.js": { "totalMs": 2 }, "parseRecordedStudyGroups.test.js": { - "totalMs": 2 + "totalMs": 3 }, "passIfMissing.test.js": { "totalMs": 3 @@ -1136,7 +1154,7 @@ "totalMs": 1 }, "pendingRepositoryBreakpoint.test.js": { - "totalMs": 658 + "totalMs": 639 }, "placeAfterDeclaringLine.test.js": { "totalMs": 1 @@ -1145,19 +1163,19 @@ "totalMs": 0 }, "plannedStopLine.test.js": { - "totalMs": 1 + "totalMs": 2 }, "playbackController.test.js": { - "totalMs": 81 + "totalMs": 79 }, "playbackPreferenceNamesStudy.test.js": { "totalMs": 1 }, "prepareNodeTestLaunch.test.js": { - "totalMs": 26 + "totalMs": 31 }, "prepareNodeTestStudy.test.js": { - "totalMs": 505 + "totalMs": 525 }, "presentationPixelLayout.test.js": { "totalMs": 3 @@ -1174,72 +1192,81 @@ "projectHistoricalTimeline.test.js": { "totalMs": 1 }, + "projectNodeHistoryTimeline.test.js": { + "totalMs": 1 + }, + "projectNodeTestApplication.test.js": { + "totalMs": 3 + }, "projectNodeTestOutcome.test.js": { "totalMs": 2 }, + "projectNodeTestSection.test.js": { + "totalMs": 2 + }, "projectRecording.test.js": { - "totalMs": 18 + "totalMs": 17 }, "protocol.test.js": { - "totalMs": 17529, + "totalMs": 17467, "tests": { - "MCP discovery declares application execution effects without broadening source reader or storage annotations": 113, - "Node learning material is exposed through MCP with exact workspace history identity and revisions": 107, - "a ninth MCP client while eight sessions are idle replaces the least recently seen one, which then answers Unknown MCP session": 120, - "a ninth client is admitted although the session it replaces fails to close": 94, - "a ninth client whose session cannot be connected is answered with the reconnect advice, and its reserved slot is free for the next client": 94, - "a stalled authenticated body reaches its read deadline without dispatching a tool": 5076, - "an incomplete HTTP header is rejected near the five-second read deadline before authentication": 5138, - "authentication and Host Origin body boundaries reject requests even with a valid transport session": 93, - "cancelled MCP calls release HTTP capacity without closing their shared session": 2042, - "deleting an in-flight MCP session settles its HTTP response and preserves capacity and the paused study": 3929, + "MCP discovery declares application execution effects without broadening source reader or storage annotations": 118, + "Node learning material is exposed through MCP with exact workspace history identity and revisions": 117, + "a ninth MCP client while eight sessions are idle replaces the least recently seen one, which then answers Unknown MCP session": 107, + "a ninth client is admitted although the session it replaces fails to close": 89, + "a ninth client whose session cannot be connected is answered with the reconnect advice, and its reserved slot is free for the next client": 91, + "a stalled authenticated body reaches its read deadline without dispatching a tool": 5068, + "an incomplete HTTP header is rejected near the five-second read deadline before authentication": 5131, + "authentication and Host Origin body boundaries reject requests even with a valid transport session": 109, + "cancelled MCP calls release HTTP capacity without closing their shared session": 2031, + "deleting an in-flight MCP session settles its HTTP response and preserves capacity and the paused study": 3879, "eight MCP sessions each with a request in flight refuse a ninth client until expiry releases their slots": 135, - "foreign instance and run errors are structured domain failures and invalid tool arguments dispatch nothing": 68, - "real MCP discovery, action and reconnect retain one runtime and one click after GET 405": 106, - "standard MCP explanation calls persist learning material and reject foreign sequence references": 99, - "status identifies extension build changes without claiming that the target workspace changed": 112, - "tool-only editor chats receive public help and current run data in structured results": 106, - "two clients that initialize at the same moment while eight sessions are idle each replace one idle session, and eight sessions remain": 97 + "foreign instance and run errors are structured domain failures and invalid tool arguments dispatch nothing": 65, + "real MCP discovery, action and reconnect retain one runtime and one click after GET 405": 112, + "standard MCP explanation calls persist learning material and reject foreign sequence references": 108, + "status identifies extension build changes without claiming that the target workspace changed": 107, + "tool-only editor chats receive public help and current run data in structured results": 107, + "two clients that initialize at the same moment while eight sessions are idle each replace one idle session, and eight sessions remain": 94 } }, "readBootIdentity.test.js": { - "totalMs": 6 + "totalMs": 7 }, "readLiveWikiUpdateMarker.test.js": { - "totalMs": 45 + "totalMs": 43 }, "readProcessStart.test.js": { - "totalMs": 1158 + "totalMs": 1155 }, "readRecordedOwner.test.js": { - "totalMs": 14 + "totalMs": 18 }, "readVitestPrerequisite.test.js": { - "totalMs": 8 + "totalMs": 10 }, "readWikiPublicationIdentity.test.js": { "totalMs": 13 }, "readWikiPublishToken.test.js": { - "totalMs": 10 + "totalMs": 9 }, "readWikiPublishedAt.test.js": { - "totalMs": 322 + "totalMs": 247 }, "readWikiRegularFile.test.js": { - "totalMs": 36 + "totalMs": 66 }, "readWikiWatchStamp.test.js": { - "totalMs": 784 + "totalMs": 719 }, "readmeDelivery.test.js": { - "totalMs": 3 + "totalMs": 2 }, "readsExplicitFocusEditorOnBreak.test.js": { "totalMs": 1 }, "rebindDeepWikiEditorLinks.test.js": { - "totalMs": 417 + "totalMs": 393 }, "recordedFileId.test.js": { "totalMs": 1 @@ -1248,65 +1275,65 @@ "totalMs": 1 }, "recordingContext.test.js": { - "totalMs": 4519 + "totalMs": 4667 }, "recordingProtocol.test.js": { "totalMs": 1251 }, "recordingStore.test.js": { - "totalMs": 2070 + "totalMs": 2612 }, "recordingWriterOf.test.js": { - "totalMs": 2577 + "totalMs": 1998 }, "refreshCursorMcpCatalog.test.js": { - "totalMs": 6106 + "totalMs": 5614 }, "refreshCursorMcpCatalogFileIdentity.test.js": { - "totalMs": 403 + "totalMs": 379 }, "refreshCursorMcpCatalogRecovery.test.js": { - "totalMs": 1248 + "totalMs": 1153 }, "removeAbandonedProfiles.test.js": { - "totalMs": 757 + "totalMs": 731 }, "removeStaleStorageClaims.test.js": { - "totalMs": 18 + "totalMs": 25 }, "removeStaleStorageLock.test.js": { - "totalMs": 14 + "totalMs": 16 }, "removeWithoutFollowing.test.js": { - "totalMs": 68 + "totalMs": 75 }, "replayDebug.test.js": { - "totalMs": 17 + "totalMs": 18 }, "replayDebugger.test.js": { - "totalMs": 23121, + "totalMs": 23096, "tests": { - "a background native debugger cannot be selected by historical default-session resolution": 1000, + "a background native debugger cannot be selected by historical default-session resolution": 1002, "a backward wall-clock jump cannot stretch the capture deadline for a stop Run and Debug is never told about": 1, "a backward wall-clock jump cannot stretch the grace for a stop whose values Run and Debug never loads": 1, "a disposed historical debugger leaves no values-loaded notice waiting on a timer": 0, - "a duplicate replay presentation cannot skip pending native inspection": 103, - "a foreign paused debugger keeps its selected model while a recorded stack becomes available": 1001, + "a duplicate replay presentation cannot skip pending native inspection": 102, + "a foreign paused debugger keeps its selected model while a recorded stack becomes available": 1002, "a healthy startup slower than the capture timeout is adopted when it completes, so the next stop presents without reopening the replay": 0, "a launch configuration cannot borrow another learning session owner": 0, "a learner-stopped historical session reports itself unavailable so an explicit replay reopen can replace it": 0, "a missing-history interval commits at once without waiting for native Call Stack": 0, "a new recorded stop waits for native termination before replacing historical values": 0, "a newer active debugger is never selected by a historical presentation waiting for command discovery": 1002, - "a newer replay stop cannot be confirmed by inspection of the superseded frame": 103, + "a newer replay stop cannot be confirmed by inspection of the superseded frame": 101, "a presentation cancelled while the old stop is still retiring leaves at once with its own reason": 0, - "a reader listener and error channel that both throw when Run and Debug loads values or the historical session ends let no error escape into the editor": 1205, + "a reader listener and error channel that both throw when Run and Debug loads values or the historical session ends let no error escape into the editor": 1203, "a reader listener that throws when the startup bound expires still lets the waiting presentation fail with the closed-debugger error": 0, - "a recorded moment commits without native values when Run and Debug does not load them, and later inspection loads them": 1002, - "a recorded native stack selects its current historical model without requiring a second learner frame choice": 7, + "a recorded moment commits without native values when Run and Debug does not load them, and later inspection loads them": 1001, + "a recorded native stack selects its current historical model without requiring a second learner frame choice": 8, "a recorded stop is shown at once, without its values, while a paused frame of another debug session keeps the Run and Debug focus": 0, - "a recorded stop shown while another debugger was active selects its native model at its next frame once that debugger ended, once": 1000, - "a recorded stop whose native model selection the host rejects still shows its frame, reports the refusal once, and selects the model at the next frame of the stop": 125, + "a recorded stop shown while another debugger was active selects its native model at its next frame once that debugger ended, once": 1001, + "a recorded stop whose native model selection the host rejects still shows its frame, reports the refusal once, and selects the model at the next frame of the stop": 114, "a recorded stop whose stack arrives after the grace selects its native model at its next frame, once": 1, "a recorded stop without scopes commits at once and later stops keep committing without waiting while Variables stays hidden": 1002, "a recorded stop’s model selection still in flight when its presentation is aborted is the selection of the next frame of that stop, which asks no second time": 0, @@ -1316,8 +1343,8 @@ "a retirement requested during a 4 s startup whose stop then takes 2 s keeps the historical debugger available": 1, "a retirement that outlives the capture timeout asks the editor once more to stop the session still showing history": 1, "a retirement that was waiting for a startup during which the reader closed fails closed and stops the session only once": 0, - "a retirement that was waiting for a startup which then expired leaves the historical debugger unavailable": 0, - "a retirement the editor never finishes makes later presentations fail with the closed-debugger error after the capture timeout": 0, + "a retirement that was waiting for a startup which then expired leaves the historical debugger unavailable": 1, + "a retirement the editor never finishes makes later presentations fail with the closed-debugger error after the capture timeout": 1, "a seek between the old adapter disconnect and its termination during a stop change still presents the next stop": 0, "a startup the editor never answers makes the historical debugger unavailable after the capture timeout instead of waiting forever": 0, "a startup the editor refuses after its only presentation was abandoned is retried by the next presentation": 2, @@ -1334,249 +1361,249 @@ "a stop whose only Variables group is the recording limitations note commits at once without waiting for Run and Debug": 0, "a superseded seek cannot publish after native debugger startup completes": 0, "a termination that arrives after the retirement bound expired leaves the historical debugger unavailable": 0, - "a termination that arrives after the retirement bound expired leaves the historical debugger unavailable when the editor had disconnected the adapter first": 0, - "a wait for native Variables ends at once without the scopes when the learner stops the recorded session": 1002, - "a wait for native Variables ends when that view asks for the presented stop scopes, and its values wait ends when the first scope is listed": 1003, - "a wait for native Variables that never asks for the stop ends at its bound without the scopes": 1001, + "a termination that arrives after the retirement bound expired leaves the historical debugger unavailable when the editor had disconnected the adapter first": 1, + "a wait for native Variables ends at once without the scopes when the learner stops the recorded session": 1001, + "a wait for native Variables ends when that view asks for the presented stop scopes, and its values wait ends when the first scope is listed": 1001, + "a wait for native Variables that never asks for the stop ends at its bound without the scopes": 1002, "a waiting presentation still fails with the closed-debugger error when the reader listener and its error channel both throw as the startup bound expires": 0, "an abandoned presentation leaves a native startup that never answers, and the next presentation shows its stop once startup completes": 0, "an editor relaunch of a learner-stopped historical session is refused instead of adopted without history": 0, - "an empty gap stack shown in Call Stack does not make the next recorded stop wait for Variables again": 1003, - "an unavailable native selection command leaves historical inspection truthful and never dispatches another command": 1003, + "an empty gap stack shown in Call Stack does not make the next recorded stop wait for Variables again": 1002, + "an unavailable native selection command leaves historical inspection truthful and never dispatches another command": 1001, "an unrelated debugger ending does not detach or stop the selected historical session": 0, "canceling a replay during native inspection cannot confirm that recorded moment": 0, "cancelling a historical presentation awaiting its stack prevents a later native model selection": 1, "closing during delayed native startup retires the acquired session exactly once": 0, "closing the historical debugger completes after the capture timeout when the editor never acknowledges the stop, and asks the editor to stop once more": 0, - "ending an observed competing debugger lets the next recorded native moment load its own values": 1003, - "historical model selection waits for the current stack and leaves an unavailable stack uninspected": 1004, + "ending an observed competing debugger lets the next recorded native moment load its own values": 1001, + "historical model selection waits for the current stack and leaves an unavailable stack uninspected": 1002, "historical workspace closure stops only its owned native session": 0, - "later video frames of a stop committed without native values do not wait for Run and Debug again": 1001, + "later video frames of a stop committed without native values do not wait for Run and Debug again": 1002, "manual native termination does not silently relaunch a session during playback": 0, "native disconnect during a pending inspection wait fails the replay moment at once instead of at the inspection grace": 0, "native disconnect during replay inspection refuses confirmation and requires explicit reopening": 0, "native terminate during a pending inspection wait fails the replay moment at once instead of at the inspection grace": 1, "native terminate during replay inspection refuses confirmation and requires explicit reopening": 0, - "recorded stops that Codebook restarts the session for keep committing at once while Run and Debug loads no values": 1002, + "recorded stops that Codebook restarts the session for keep committing at once while Run and Debug loads no values": 1001, "replacing a recorded stop keeps history available when the editor disconnects the old adapter before termination": 0, - "replay entered while another debugger is already active never guesses the native session cohort": 1001, - "replay remains loading until the native debugger retrieves the current recorded Local values": 203, + "replay entered while another debugger is already active never guesses the native session cohort": 1002, + "replay remains loading until the native debugger retrieves the current recorded Local values": 202, "retrying a stop whose presentation was interrupted keeps the native session showing it instead of restarting": 1, "seeking another recorded stop retires the old owned session before opening new native values": 0, - "several video frames of a gap shown in Call Stack do not make the next recorded stop wait for Variables again": 1003, + "several video frames of a gap shown in Call Stack do not make the next recorded stop wait for Variables again": 1001, "stopping the recorded session from the native debugger marks history unavailable before the editor reports termination": 0, "stopping the recorded session from the native debugger notifies the reader": 1000, "superseded recorded history cannot select a native model after the newer gap commits": 0, "the frames of one recorded stop ask the host for its commands once and select the native model once, and the next stop is selected again": 2, - "the reader is told that Run and Debug loaded the values 150 ms after they were served, not in the same instant": 0, - "the real historical debugger follows the model-selection scenario the workspace harness’s fake is held to": 2006, + "the reader is told that Run and Debug loaded the values 150 ms after they were served, not in the same instant": 1, + "the real historical debugger follows the model-selection scenario the workspace harness’s fake is held to": 2004, "two overlapping frames of one recorded stop select its native model once, in every order of the first frame’s answer and the next frame’s steps": 7, "unanswered native command discovery cannot stall a saved recorded moment indefinitely": 0, - "unanswered native model selection ends within its bound without claiming inspected values": 0, + "unanswered native model selection ends within its bound without claiming inspected values": 1, "unsupported command discovery cannot commit obsolete recorded history after a newer gap": 0, "values Run and Debug loads just before the grace deadline commit the stop as inspected": 1, "values served for a stop the recording has left by the time the reader would be told are not reported": 0, "video frames at an already inspected stop reuse recorded values without asking the native client again": 0, "video frames within one recorded stop preserve their native debug session": 0, - "while Run and Debug loads no values, later recorded stops commit at once until it loads them again": 1303, + "while Run and Debug loads no values, later recorded stops commit at once until it loads them again": 1302, "while another tab covers the recorded application Run and Debug says that the recording is covered, not that the moment was not recorded": 0, "with Variables hidden a stop commits without values exactly one grace after Run and Debug is told about it, without polling": 1, "workspace closure during pending native inspection rejects the moment and stops only its owned session": 0 } }, "repositoryBook.test.js": { - "totalMs": 5075 + "totalMs": 5287 }, "repositoryConfig.test.js": { - "totalMs": 8 + "totalMs": 10 }, "repositoryEntry.test.js": { "totalMs": 18 }, "repositoryEvidenceFeedback.test.js": { - "totalMs": 619 + "totalMs": 669 }, "repositoryHtml.test.js": { "totalMs": 2 }, "repositoryProtocol.test.js": { - "totalMs": 2507 + "totalMs": 2485 }, "repositoryReader.test.js": { - "totalMs": 35283, + "totalMs": 36283, "tests": { - "Close Repository Wiki keeps a cited-source copy the learner moved beside the Wiki when it is the only other tab of the Wiki’s group": 143, - "Close during actual citation acquisition prevents a late native source or Wiki reveal": 192, - "Close during cold Wiki reservation releases its own focus receipt without a stale reveal": 109, - "Close during pending source acquisition prevents native source reveal and obsolete error publication": 164, - "Close while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 284, - "Retry saves an unsaved choice for its original article exactly once after navigation": 257, - "Wiki Return without an open Wiki opens its real retained citation before resolving an otherwise ambiguous primary pane": 139, - "Wiki ordinary open opens its real retained citation before resolving an otherwise ambiguous primary pane": 140, - "a Close while the Wiki document loads prevents the old entry from taking keyboard focus later": 182, - "a Repository Wiki closed with Close Repository Wiki leaves its group, as the editors close a disposed pane": 145, - "a Repository Wiki reader the extension disposes stops listening to the editor’s tabs": 107, - "a Repository Wiki reader whose dispose fails while it closes its pane releases what it registered with the editor all the same, and tells the failure": 122, - "a Wiki pane shown again whose new document says it is ready before the editor reports the pane shown renders its article and its receipt counts": 168, - "a chat while the Wiki document loads prevents the old entry from taking keyboard focus later": 211, - "a cited-source copy an earlier reader showed and the learner reads in stays at Close Repository Wiki after the new reader's display of the same citation was refused": 154, - "a cited-source copy an earlier reader showed and the learner reads in stays when the reader made after a folder change shows and closes its own Wiki": 181, - "a cited-source copy the learner closed and reopened stays in front of the first group when the Wiki closes": 132, - "a cited-source copy the learner moved beside the Wiki and left is retired by the next citation, as a copy the reader showed": 170, + "Close Repository Wiki keeps a cited-source copy the learner moved beside the Wiki when it is the only other tab of the Wiki’s group": 139, + "Close during actual citation acquisition prevents a late native source or Wiki reveal": 127, + "Close during cold Wiki reservation releases its own focus receipt without a stale reveal": 126, + "Close during pending source acquisition prevents native source reveal and obsolete error publication": 157, + "Close while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 264, + "Retry saves an unsaved choice for its original article exactly once after navigation": 236, + "Wiki Return without an open Wiki opens its real retained citation before resolving an otherwise ambiguous primary pane": 215, + "Wiki ordinary open opens its real retained citation before resolving an otherwise ambiguous primary pane": 191, + "a Close while the Wiki document loads prevents the old entry from taking keyboard focus later": 220, + "a Repository Wiki closed with Close Repository Wiki leaves its group, as the editors close a disposed pane": 134, + "a Repository Wiki reader the extension disposes stops listening to the editor’s tabs": 100, + "a Repository Wiki reader whose dispose fails while it closes its pane releases what it registered with the editor all the same, and tells the failure": 107, + "a Wiki pane shown again whose new document says it is ready before the editor reports the pane shown renders its article and its receipt counts": 180, + "a chat while the Wiki document loads prevents the old entry from taking keyboard focus later": 209, + "a cited-source copy an earlier reader showed and the learner reads in stays at Close Repository Wiki after the new reader's display of the same citation was refused": 141, + "a cited-source copy an earlier reader showed and the learner reads in stays when the reader made after a folder change shows and closes its own Wiki": 170, + "a cited-source copy the learner closed and reopened stays in front of the first group when the Wiki closes": 127, + "a cited-source copy the learner moved beside the Wiki and left is retired by the next citation, as a copy the reader showed": 165, "a cited-source copy the learner moved beside the Wiki and types in keeps its tab and the keyboard when an agent opens another article": 168, - "a cited-source copy the learner pinned stays when the learner follows the next citation": 167, - "a cited-source copy the next citation retired and the learner reopened stays when the Wiki closes, and the next citation’s copy leaves": 176, - "a cited-source copy the reader showed itself still leaves with Close Repository Wiki after a later display of the same citation was refused": 146, - "a cited-source copy whose display was refused after the editor opened its tab leaves with Close Repository Wiki": 143, - "a cited-source tab that is the only tab of its group stays when the Wiki closes": 140, - "a cited-source tab the learner pinned stays in front of the first group when the Wiki closes": 131, - "a fresh reader restores exact revision article citation section-relative position and focus from the shared ledger": 217, - "a learner's change of group while a cold Open Repository Wiki beside Cursor's chat part shows its citation is still refused as the learner's newer focus": 114, - "a learner’s own Wiki open in an editor window that does not have the focus is refused before it activates the Wiki": 133, - "a newer article cancels an old renderer wait and only the latest article receives keyboard focus": 237, - "a newer article retires an unvisited Return so later Wiki focus cannot restore its old layout": 242, - "a newer group roundtrip after the own quiet Wiki selection still cancels the old Study Return": 255, - "a newer group roundtrip after the own quiet Wiki selection still cancels the old recording Return": 246, - "a newer other group after the own quiet Wiki selection still cancels the old Study Return": 270, - "a newer other group after the own quiet Wiki selection still cancels the old recording Return": 234, - "a newer source after the own quiet Wiki selection still cancels the old Study Return": 285, - "a newer source after the own quiet Wiki selection still cancels the old recording Return": 230, - "a palette Return to Wiki completes at the learner’s click on the Wiki also when the editor names the Wiki’s group before the Wiki’s tab comes to its front": 210, - "a palette Return to Wiki completes at the learner’s click on the Wiki also when the editor reports the lost text editor before it names the Wiki’s group": 210, - "a palette Return to Wiki from the Study pane does not restore the article layout when a Study close makes the editor select the Wiki": 222, - "a palette Return to Wiki from the Study pane does not restore the article layout when the Study closes while the Return still loads": 213, - "a palette Return to Wiki from the Study pane restores the article layout when the learner selects the Wiki": 213, - "a palette Return to Wiki is dropped once the learner moves to a file of the Wiki’s own group, so a later selection of the Wiki restores no article layout": 207, - "a palette Return to Wiki is dropped once the learner moves to a file, so a later Wiki activation restores no article layout": 221, + "a cited-source copy the learner pinned stays when the learner follows the next citation": 176, + "a cited-source copy the next citation retired and the learner reopened stays when the Wiki closes, and the next citation’s copy leaves": 162, + "a cited-source copy the reader showed itself still leaves with Close Repository Wiki after a later display of the same citation was refused": 152, + "a cited-source copy whose display was refused after the editor opened its tab leaves with Close Repository Wiki": 147, + "a cited-source tab that is the only tab of its group stays when the Wiki closes": 125, + "a cited-source tab the learner pinned stays in front of the first group when the Wiki closes": 134, + "a fresh reader restores exact revision article citation section-relative position and focus from the shared ledger": 202, + "a learner's change of group while a cold Open Repository Wiki beside Cursor's chat part shows its citation is still refused as the learner's newer focus": 103, + "a learner’s own Wiki open in an editor window that does not have the focus is refused before it activates the Wiki": 139, + "a newer article cancels an old renderer wait and only the latest article receives keyboard focus": 229, + "a newer article retires an unvisited Return so later Wiki focus cannot restore its old layout": 236, + "a newer group roundtrip after the own quiet Wiki selection still cancels the old Study Return": 275, + "a newer group roundtrip after the own quiet Wiki selection still cancels the old recording Return": 247, + "a newer other group after the own quiet Wiki selection still cancels the old Study Return": 281, + "a newer other group after the own quiet Wiki selection still cancels the old recording Return": 266, + "a newer source after the own quiet Wiki selection still cancels the old Study Return": 219, + "a newer source after the own quiet Wiki selection still cancels the old recording Return": 263, + "a palette Return to Wiki completes at the learner’s click on the Wiki also when the editor names the Wiki’s group before the Wiki’s tab comes to its front": 222, + "a palette Return to Wiki completes at the learner’s click on the Wiki also when the editor reports the lost text editor before it names the Wiki’s group": 213, + "a palette Return to Wiki from the Study pane does not restore the article layout when a Study close makes the editor select the Wiki": 228, + "a palette Return to Wiki from the Study pane does not restore the article layout when the Study closes while the Return still loads": 215, + "a palette Return to Wiki from the Study pane restores the article layout when the learner selects the Wiki": 231, + "a palette Return to Wiki is dropped once the learner moves to a file of the Wiki’s own group, so a later selection of the Wiki restores no article layout": 202, + "a palette Return to Wiki is dropped once the learner moves to a file, so a later Wiki activation restores no article layout": 217, "a palette Return to Wiki is dropped once the learner moves to another group whose front tab is no file, so a later selection of the Wiki restores no article layout": 209, - "a palette Return to Wiki made while the learner types in a file in front of the Wiki in its group survives that typing and restores the article layout at the learner’s click on the Wiki’s tab": 216, - "a palette Return to Wiki refused for an unreadable cited source leaves no Return behind, so a later Wiki activation restores no article layout": 200, - "a palette Return to Wiki refused for the learner’s click into a file during its load leaves no Return behind, so a later Wiki activation restores no article layout": 222, - "a palette Return to Wiki survives a tab-group event that leaves the focus where it was and restores the article layout when the learner selects the Wiki": 212, - "a pending Wiki citation preview preserves a closed reader instead of revealing its old source": 210, - "a pending Wiki citation preview preserves newer file input instead of revealing its old source": 224, - "a previous article render receipt cannot release a newer pending Wiki entry": 240, - "a quiet Wiki selection cannot retire a text editor selected in another group": 192, - "a refused another article evidence request preserves the current Wiki's deferred citation preview": 216, - "a refused observation request lets an already-started Wiki citation preview finish without leaving and returning again": 226, - "a refused unavailable observation evidence request preserves the current Wiki's deferred citation preview": 220, - "a source key while the Wiki document loads prevents the old entry from taking keyboard focus later": 217, - "a source selection after the Wiki-group return still cancels opening the original article right after Study Close": 157, - "a source-group choice after the Wiki-group return still cancels opening the original article right after Study Close": 157, - "a visible Wiki waits for its updated article without selecting its tab or taking keyboard": 287, - "a window roundtrip while the Wiki document loads prevents the old entry from taking keyboard focus later": 200, - "a window while the Wiki document loads prevents the old entry from taking keyboard focus later": 200, - "abort during cold Wiki reservation releases its own focus receipt without a stale reveal": 100, - "ambiguous primary Wiki opens after native citation activation reports a missing editor and initial caret": 141, - "ambiguous scope Wiki citation display response preserves later none without adopting new learner ownership": 149, - "ambiguous scope Wiki citation display response preserves later selection without adopting new learner ownership": 112, - "ambiguous scope Wiki citation display response preserves later tab roundtrip without adopting new learner ownership": 109, - "an agent opening an article where no Wiki and no Study arrangement is open keeps the learner's chat input": 139, - "an agent opening an article where no Wiki and no Study arrangement is open keeps the learner's file input": 149, - "an agent opening an article while no Wiki is open shows the Wiki without taking the learner's chat input": 138, - "an agent opening an article while no Wiki is open shows the Wiki without taking the learner's file input": 140, - "an agent opening another article in the existing Wiki preserves the learner's chat input": 178, - "an agent opening another article in the existing Wiki preserves the learner's file input": 183, - "an agent's cold Wiki open in an editor window that loses the focus while the Wiki loads shows the article without taking the keyboard": 139, - "an agent's cold Wiki open in an editor window without the focus from the start shows the article without taking the keyboard": 148, - "an agent's cold Wiki open that cannot give back the keyboard its layout borrowed gives it to the Wiki and says so once": 164, - "an agent's cold Wiki open whose give-back fails while the learner clicks into a file leaves the keyboard in that file, reveals no Wiki with the focus and tells nothing": 134, - "an agent's cold Wiki open whose layout borrowed the cited source's focus gives Cursor's chat tab its keyboard back": 137, - "an agent’s Wiki open closed with Close Repository Wiki leaves no cited-source tab and brings the learner’s file in the first group to the front again": 140, - "an agent’s read refused for the learner’s newer input during its load keeps the deferred preview of the article it shows, so the learner’s later selection of the Wiki shows that cited source": 214, - "an external Return preserves native chat input and completes while the hidden Wiki renderer is still unavailable": 210, - "an old dirty buffer cannot certify a changed or unavailable cited file as current": 162, - "an unavailable Wiki citation cannot acquire native layout or focus as a temporary anchor": 111, - "an unavailable Wiki renderer times out without taking native input, and a late receipt cannot revive that entry": 5214, - "an unchanged BOM source opens in the current native editor while retained bytes keep their original hash": 224, - "another editor after the Wiki-group return still cancels opening the original article right after Study Close": 170, - "another file departure during deferred citation loading prevents the recreated Wiki from taking keyboard later": 216, - "another group while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 272, - "bracket-named route citations update review status after external edit deletion and recreation without manual refresh": 818, - "captured source URIs reject forged hashes and a reader rejects actions after workspace ownership changes": 149, - "changing a Wiki article completes when its prepared citation clears the old editor before group activation": 167, - "changing a Wiki article preserves another source during the prepared citation's early editor gap": 140, + "a palette Return to Wiki made while the learner types in a file in front of the Wiki in its group survives that typing and restores the article layout at the learner’s click on the Wiki’s tab": 212, + "a palette Return to Wiki refused for an unreadable cited source leaves no Return behind, so a later Wiki activation restores no article layout": 212, + "a palette Return to Wiki refused for the learner’s click into a file during its load leaves no Return behind, so a later Wiki activation restores no article layout": 204, + "a palette Return to Wiki survives a tab-group event that leaves the focus where it was and restores the article layout when the learner selects the Wiki": 222, + "a pending Wiki citation preview preserves a closed reader instead of revealing its old source": 223, + "a pending Wiki citation preview preserves newer file input instead of revealing its old source": 222, + "a previous article render receipt cannot release a newer pending Wiki entry": 251, + "a quiet Wiki selection cannot retire a text editor selected in another group": 201, + "a refused another article evidence request preserves the current Wiki's deferred citation preview": 211, + "a refused observation request lets an already-started Wiki citation preview finish without leaving and returning again": 234, + "a refused unavailable observation evidence request preserves the current Wiki's deferred citation preview": 228, + "a source key while the Wiki document loads prevents the old entry from taking keyboard focus later": 278, + "a source selection after the Wiki-group return still cancels opening the original article right after Study Close": 223, + "a source-group choice after the Wiki-group return still cancels opening the original article right after Study Close": 152, + "a visible Wiki waits for its updated article without selecting its tab or taking keyboard": 265, + "a window roundtrip while the Wiki document loads prevents the old entry from taking keyboard focus later": 214, + "a window while the Wiki document loads prevents the old entry from taking keyboard focus later": 214, + "abort during cold Wiki reservation releases its own focus receipt without a stale reveal": 119, + "ambiguous primary Wiki opens after native citation activation reports a missing editor and initial caret": 146, + "ambiguous scope Wiki citation display response preserves later none without adopting new learner ownership": 211, + "ambiguous scope Wiki citation display response preserves later selection without adopting new learner ownership": 182, + "ambiguous scope Wiki citation display response preserves later tab roundtrip without adopting new learner ownership": 225, + "an agent opening an article where no Wiki and no Study arrangement is open keeps the learner's chat input": 136, + "an agent opening an article where no Wiki and no Study arrangement is open keeps the learner's file input": 150, + "an agent opening an article while no Wiki is open shows the Wiki without taking the learner's chat input": 136, + "an agent opening an article while no Wiki is open shows the Wiki without taking the learner's file input": 137, + "an agent opening another article in the existing Wiki preserves the learner's chat input": 171, + "an agent opening another article in the existing Wiki preserves the learner's file input": 167, + "an agent's cold Wiki open in an editor window that loses the focus while the Wiki loads shows the article without taking the keyboard": 145, + "an agent's cold Wiki open in an editor window without the focus from the start shows the article without taking the keyboard": 135, + "an agent's cold Wiki open that cannot give back the keyboard its layout borrowed gives it to the Wiki and says so once": 173, + "an agent's cold Wiki open whose give-back fails while the learner clicks into a file leaves the keyboard in that file, reveals no Wiki with the focus and tells nothing": 135, + "an agent's cold Wiki open whose layout borrowed the cited source's focus gives Cursor's chat tab its keyboard back": 141, + "an agent’s Wiki open closed with Close Repository Wiki leaves no cited-source tab and brings the learner’s file in the first group to the front again": 129, + "an agent’s read refused for the learner’s newer input during its load keeps the deferred preview of the article it shows, so the learner’s later selection of the Wiki shows that cited source": 207, + "an external Return preserves native chat input and completes while the hidden Wiki renderer is still unavailable": 198, + "an old dirty buffer cannot certify a changed or unavailable cited file as current": 186, + "an unavailable Wiki citation cannot acquire native layout or focus as a temporary anchor": 170, + "an unavailable Wiki renderer times out without taking native input, and a late receipt cannot revive that entry": 5221, + "an unchanged BOM source opens in the current native editor while retained bytes keep their original hash": 234, + "another editor after the Wiki-group return still cancels opening the original article right after Study Close": 151, + "another file departure during deferred citation loading prevents the recreated Wiki from taking keyboard later": 208, + "another group while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 270, + "bracket-named route citations update review status after external edit deletion and recreation without manual refresh": 833, + "captured source URIs reject forged hashes and a reader rejects actions after workspace ownership changes": 128, + "changing a Wiki article completes when its prepared citation clears the old editor before group activation": 165, + "changing a Wiki article preserves another source during the prepared citation's early editor gap": 142, "changing a Wiki article preserves citation tab roundtrip during the prepared citation's early editor gap": 140, - "chat focus during Wiki progress storage prevents the old Open from revealing its reader again": 200, - "chat roundtrip while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 271, - "chat while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 259, - "cold Wiki preserves Keyboard during native citation initial caret before the requested range arrives": 112, + "chat focus during Wiki progress storage prevents the old Open from revealing its reader again": 224, + "chat roundtrip while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 269, + "chat while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 257, + "cold Wiki preserves Keyboard during native citation initial caret before the requested range arrives": 120, "cold Wiki preserves Mouse during native citation initial caret before the requested range arrives": 110, - "cold Wiki preserves chat focus during progress storage after its native reservation": 115, - "cold Wiki preserves chat focus during source lookup after its native reservation": 106, - "cold Wiki preserves chat focus during source refresh after its native reservation": 126, - "cold Wiki preserves document version roundtrip during native citation initial caret before the requested range arrives": 108, - "cold Wiki preserves editor retreat during native citation initial caret before the requested range arrives": 115, - "cold Wiki preserves group during native citation initial caret before the requested range arrives": 107, - "cold Wiki preserves group roundtrip during native citation initial caret before the requested range arrives": 111, - "cold Wiki preserves selection during native citation initial caret before the requested range arrives": 103, - "cold Wiki preserves selection roundtrip during native citation initial caret before the requested range arrives": 104, - "cold Wiki preserves tab roundtrip during native citation initial caret before the requested range arrives": 108, - "cold Wiki preserves text gap during native citation initial caret before the requested range arrives": 110, - "cold Wiki rejects newer editor input during citation target tab before the target editor appears": 105, - "cold Wiki rejects newer editor input during citation text gap before the target editor appears": 119, - "cold Wiki reservation opens the actual citation without losing navigation ownership": 130, - "cold Wiki reservation preserves newer different file instead of revealing stale Wiki": 111, - "cold Wiki reservation preserves newer selection instead of revealing stale Wiki": 111, - "cold Wiki reservation preserves newer tab roundtrip instead of revealing stale Wiki": 111, - "cold Wiki with an empty library activates its empty reader without inventing a citation or retaining listeners": 102, - "cold article keeps native input until its current Wiki document is rendered, then gives the article its keyboard": 251, - "cold ordinary text Wiki citation display response preserves later none without adopting new learner ownership": 208, - "cold ordinary text Wiki citation display response preserves later selection without adopting new learner ownership": 155, - "cold ordinary text Wiki citation display response preserves later tab roundtrip without adopting new learner ownership": 171, - "cold ordinary text Wiki opens after native citation activation reports a missing editor and initial caret": 130, - "corrupt shared progress leaves articles readable but understanding disabled without replacing the corrupt file": 151, - "delayed scroll and render receipts from a previous article do not warn on the new article or overwrite its return context": 178, - "evidence navigation persists exact return context and rejects changed checkpoints before entering a study": 253, - "following a second citation in the open Wiki leaves one cited-source copy in front of the learner’s file in the first group": 169, - "following the citation on screen again in the open Wiki brings its one copy to the front of the first group, as the editors do": 163, - "hidden Study Return keeps native input until its current Wiki document is rendered, then gives the article its keyboard": 300, - "hiding Wiki retires its earlier same-article render receipt before the document is recreated": 203, - "intentional Study Return accepts its own quiet Wiki selection and captured source retirement": 243, - "intentional Study Return accepts its own quiet Wiki selection before the document is ready": 261, - "keyboard moved into the Wiki after the Wiki-group return still cancels opening the original article right after Study Close": 155, - "keyboard moved into the Wiki without a Wiki-group return still cancels opening the original article right after Study Close": 155, - "late article navigation cannot replace a newer selection or reopen a closed repository panel": 208, - "late hidden-document receipts cannot certify a visible Wiki before its new document is ready": 206, - "manual draft focus while opaque-primary Wiki layout waits prevents a later citation or reader reveal": 193, - "manual draft focus while text-primary Wiki layout waits prevents a later citation or reader reveal": 168, - "manual draft focus while the Wiki catalog loads prevents later source focus acquisition": 222, - "manual focus during actual citation acquisition prevents a late native source or Wiki reveal": 160, - "missing saved history reports its exact revision instead of silently falling forward to the latest": 112, - "mixed and CR-only line endings retain bytes while citation lines and current-file reveal match the native text model": 204, - "new Open during cold Wiki reservation releases its own focus receipt without a stale reveal": 137, - "new native chat input cancels an unanchored Wiki entry while its document is still loading": 249, - "opening the original article right after Study Close completes when the Wiki group becomes active again while the article loads and the acquired source keeps the keyboard": 169, - "opening the original article right after Study Close completes when the Wiki group becomes active again while the article renders and the acquired source keeps the keyboard": 225, - "publishing clearer prose advertises a newer revision without replacing the selected historical article or its understanding": 305, + "cold Wiki preserves chat focus during progress storage after its native reservation": 118, + "cold Wiki preserves chat focus during source lookup after its native reservation": 115, + "cold Wiki preserves chat focus during source refresh after its native reservation": 154, + "cold Wiki preserves document version roundtrip during native citation initial caret before the requested range arrives": 111, + "cold Wiki preserves editor retreat during native citation initial caret before the requested range arrives": 113, + "cold Wiki preserves group during native citation initial caret before the requested range arrives": 117, + "cold Wiki preserves group roundtrip during native citation initial caret before the requested range arrives": 106, + "cold Wiki preserves selection during native citation initial caret before the requested range arrives": 115, + "cold Wiki preserves selection roundtrip during native citation initial caret before the requested range arrives": 115, + "cold Wiki preserves tab roundtrip during native citation initial caret before the requested range arrives": 111, + "cold Wiki preserves text gap during native citation initial caret before the requested range arrives": 116, + "cold Wiki rejects newer editor input during citation target tab before the target editor appears": 122, + "cold Wiki rejects newer editor input during citation text gap before the target editor appears": 116, + "cold Wiki reservation opens the actual citation without losing navigation ownership": 153, + "cold Wiki reservation preserves newer different file instead of revealing stale Wiki": 120, + "cold Wiki reservation preserves newer selection instead of revealing stale Wiki": 110, + "cold Wiki reservation preserves newer tab roundtrip instead of revealing stale Wiki": 124, + "cold Wiki with an empty library activates its empty reader without inventing a citation or retaining listeners": 120, + "cold article keeps native input until its current Wiki document is rendered, then gives the article its keyboard": 207, + "cold ordinary text Wiki citation display response preserves later none without adopting new learner ownership": 196, + "cold ordinary text Wiki citation display response preserves later selection without adopting new learner ownership": 167, + "cold ordinary text Wiki citation display response preserves later tab roundtrip without adopting new learner ownership": 158, + "cold ordinary text Wiki opens after native citation activation reports a missing editor and initial caret": 145, + "corrupt shared progress leaves articles readable but understanding disabled without replacing the corrupt file": 173, + "delayed scroll and render receipts from a previous article do not warn on the new article or overwrite its return context": 177, + "evidence navigation persists exact return context and rejects changed checkpoints before entering a study": 226, + "following a second citation in the open Wiki leaves one cited-source copy in front of the learner’s file in the first group": 160, + "following the citation on screen again in the open Wiki brings its one copy to the front of the first group, as the editors do": 170, + "hidden Study Return keeps native input until its current Wiki document is rendered, then gives the article its keyboard": 255, + "hiding Wiki retires its earlier same-article render receipt before the document is recreated": 204, + "intentional Study Return accepts its own quiet Wiki selection and captured source retirement": 265, + "intentional Study Return accepts its own quiet Wiki selection before the document is ready": 258, + "keyboard moved into the Wiki after the Wiki-group return still cancels opening the original article right after Study Close": 149, + "keyboard moved into the Wiki without a Wiki-group return still cancels opening the original article right after Study Close": 790, + "late article navigation cannot replace a newer selection or reopen a closed repository panel": 204, + "late hidden-document receipts cannot certify a visible Wiki before its new document is ready": 231, + "manual draft focus while opaque-primary Wiki layout waits prevents a later citation or reader reveal": 113, + "manual draft focus while text-primary Wiki layout waits prevents a later citation or reader reveal": 118, + "manual draft focus while the Wiki catalog loads prevents later source focus acquisition": 178, + "manual focus during actual citation acquisition prevents a late native source or Wiki reveal": 113, + "missing saved history reports its exact revision instead of silently falling forward to the latest": 133, + "mixed and CR-only line endings retain bytes while citation lines and current-file reveal match the native text model": 212, + "new Open during cold Wiki reservation releases its own focus receipt without a stale reveal": 192, + "new native chat input cancels an unanchored Wiki entry while its document is still loading": 231, + "opening the original article right after Study Close completes when the Wiki group becomes active again while the article loads and the acquired source keeps the keyboard": 163, + "opening the original article right after Study Close completes when the Wiki group becomes active again while the article renders and the acquired source keeps the keyboard": 236, + "publishing clearer prose advertises a newer revision without replacing the selected historical article or its understanding": 191, "reopening the Wiki marks its existing article as loading before source and layout navigation": 170, "repository articles open retained source without connecting an agent or marking understanding": 168, - "retiring an agent open before its checkpoint completes prevents source and selection effects while local reading remains available": 177, - "returning to Wiki from chat keeps its input and restores the article layout only when Wiki is selected": 223, - "returning to Wiki from file keeps its input and restores the article layout only when Wiki is selected": 226, - "secondary citation edits and unsaved editor changes require review while historical understanding stays retained": 227, - "selecting Wiki during a Return freshness check completes that Return without superseding its caller": 191, - "selecting a recreated Wiki gives it keyboard focus after its deferred citation and current article are ready": 260, - "selecting a recreated Wiki gives it keyboard focus after its deferred citation and current document are ready": 271, - "selecting the Wiki after a quiet agent article displays its exact citation without another article request": 213, - "selecting the Wiki while its requested article is loading completes that article and displays its cited source": 167, - "the Wiki’s tab closed by hand keeps a cited-source copy the learner moved beside the Wiki when it is the only other tab of the Wiki’s group": 135, - "the citation an agent’s article change shows once the learner selects the Wiki replaces the copy of the citation before in the first group": 215, - "the learner's cold Open Repository Wiki run while Cursor's chat part has the keyboard opens the Wiki after the citation took the keyboard under the chat's group name": 142, - "the learner's cold Open Repository Wiki still gives the Wiki the keyboard and asks for no keyboard return": 144, - "the learner’s own Wiki whose tab the learner closes by hand leaves no cited-source tab and brings the learner’s file in the first group to the front again with its caret": 147, - "the reader made after the workspace folders change retires the cited-source copy the reader before it left in front of the learner’s file": 135, - "window departure during deferred citation loading prevents the recreated Wiki from taking keyboard later": 223, - "window roundtrip departure during deferred citation loading prevents the recreated Wiki from taking keyboard later": 219, - "window roundtrip while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 271, - "window while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 260 + "retiring an agent open before its checkpoint completes prevents source and selection effects while local reading remains available": 227, + "returning to Wiki from chat keeps its input and restores the article layout only when Wiki is selected": 210, + "returning to Wiki from file keeps its input and restores the article layout only when Wiki is selected": 229, + "secondary citation edits and unsaved editor changes require review while historical understanding stays retained": 199, + "selecting Wiki during a Return freshness check completes that Return without superseding its caller": 192, + "selecting a recreated Wiki gives it keyboard focus after its deferred citation and current article are ready": 267, + "selecting a recreated Wiki gives it keyboard focus after its deferred citation and current document are ready": 259, + "selecting the Wiki after a quiet agent article displays its exact citation without another article request": 225, + "selecting the Wiki while its requested article is loading completes that article and displays its cited source": 168, + "the Wiki’s tab closed by hand keeps a cited-source copy the learner moved beside the Wiki when it is the only other tab of the Wiki’s group": 148, + "the citation an agent’s article change shows once the learner selects the Wiki replaces the copy of the citation before in the first group": 236, + "the learner's cold Open Repository Wiki run while Cursor's chat part has the keyboard opens the Wiki after the citation took the keyboard under the chat's group name": 128, + "the learner's cold Open Repository Wiki still gives the Wiki the keyboard and asks for no keyboard return": 136, + "the learner’s own Wiki whose tab the learner closes by hand leaves no cited-source tab and brings the learner’s file in the first group to the front again with its caret": 138, + "the reader made after the workspace folders change retires the cited-source copy the reader before it left in front of the learner’s file": 140, + "window departure during deferred citation loading prevents the recreated Wiki from taking keyboard later": 206, + "window roundtrip departure during deferred citation loading prevents the recreated Wiki from taking keyboard later": 217, + "window roundtrip while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 272, + "window while the selected Wiki document loads prevents its deferred preview from taking keyboard later": 268 } }, "repositorySource.test.js": { - "totalMs": 1869 + "totalMs": 1839 }, "requestCursorWikiText.test.js": { - "totalMs": 230 + "totalMs": 214 }, "resolveArmedPlace.test.js": { "totalMs": 1 @@ -1588,134 +1615,136 @@ "totalMs": 1 }, "resolveExternalNodeExecutable.test.js": { - "totalMs": 26 + "totalMs": 28 }, "retryWhileBusy.test.js": { "totalMs": 1 }, "runBoundedQuery.test.js": { - "totalMs": 328 + "totalMs": 327 }, "runCursorWikiUpdate.test.js": { - "totalMs": 465 + "totalMs": 450 }, "runNodeScriptInChild.test.js": { - "totalMs": 23 + "totalMs": 25 }, "runtime-awaitResponse.test.js": { - "totalMs": 18 + "totalMs": 17 }, "runtime-browserViewport.test.js": { - "totalMs": 11448, + "totalMs": 10853, "tests": { - "a failed App keyboard answer cannot bypass final ownership refusal or hide native source input": 104, + "a failed App keyboard answer cannot bypass final ownership refusal or hide native source input": 103, "a held viewport transfers its paused pixels without letting the retired panel close or acknowledge the session": 53, - "a hidden recorded gap waits without polling until Application becomes visible": 304, - "a live capture whose Application pane paints no frame within the bound ends with what was observed and the step that makes a new run possible": 379, + "a hidden recorded gap waits without polling until Application becomes visible": 303, + "a history shown after a test replay’s later moment is what a replacement panel restores": 1, + "a history update keeps the shown document and a replacement panel restores the latest moment, written only then": 1, + "a live capture whose Application pane paints no frame within the bound ends with what was observed and the step that makes a new run possible": 344, "a live lease writing its history page over the recording renderer on one shared panel leaves that renderer unable to confirm a paint": 3002, "a paused file covered by Application gives Application the keyboard even while Cursor still names the chat tab group": 52, - "a paused file covered by Application gives the chat its keyboard back before reveal even while Cursor still names the chat tab group": 53, + "a paused file covered by Application gives the chat its keyboard back before reveal even while Cursor still names the chat tab group": 51, "a rebound live viewport keeps one CDP stream and records later frames without closing the recorder": 103, - "a recorded gap receipt sent while the recording is hidden cannot confirm the placeholder": 205, + "a recorded gap receipt sent while the recording is hidden cannot confirm the placeholder": 203, "a recorded gap requires its own current renderer receipt and never certifies a PNG": 3, - "a recorded image already hidden waits for real painting instead of exhausting its deadline in the background": 412, - "a recorded image hidden after decode waits for real painting instead of exhausting its deadline in the background": 395, + "a recorded image already hidden waits for real painting instead of exhausting its deadline in the background": 376, + "a recorded image hidden after decode waits for real painting instead of exhausting its deadline in the background": 365, "a recorded seek clears pending pixels and rejects their late acknowledgement before a replacement image": 3, "a reveal of the Application pane that is aborted while its owner is asked about the keyboard reveals nothing, takes no keyboard and tells nothing": 1, - "a stalled recorded gap keeps the paint time it used before Application was hidden": 588, - "a visible unresponsive recorded gap still fails within its paint budget": 378, - "an already unsafe App reveal never asks a keyboard owner that would move source input into chat": 53, - "an explicit recorded gap waits through background suspension and confirms only its own painted placeholder": 390, + "a stalled recorded gap keeps the paint time it used before Application was hidden": 526, + "a visible unresponsive recorded gap still fails within its paint budget": 342, + "an already unsafe App reveal never asks a keyboard owner that would move source input into chat": 51, + "an explicit recorded gap waits through background suspension and confirms only its own painted placeholder": 360, "cancelling a hidden recorded gap releases its wait without a fabricated placeholder receipt": 2, "cancelling placement while a recorded image is hidden releases only the placement reservation": 3, - "close retires hidden recorded pixels without waiting for a foreground window": 3, + "close retires hidden recorded pixels without waiting for a foreground window": 2, "closing a shared application panel ends both live and replay leases unless each lease has transferred": 2, "closing a viewport releases held placement without delivering a queued historical image": 1, "closing the current panel releases a reserved placement and rejects waiting capture without later cleanup": 1, "continuation during renderer reload prevents the retired pause from being displayed or acknowledged": 51, - "disposing the recording panel promptly rejects a hidden recorded gap without fabricated paint confirmation": 3, + "disposing the recording panel promptly rejects a hidden recorded gap without fabricated paint confirmation": 2, "historical reading rejects hidden current captures and releases the runtime without closing its reader panel": 1, "invalidating a displayed pause rejects its late acknowledgement before any newer image can be certified": 2, - "live painting without a valid current hidden receipt retains a bounded timeout": 384, + "live painting without a valid current hidden receipt retains a bounded timeout": 343, "live-follow refresh restores an adopted renderer after placement fails without revealing a newer learner tab": 1, - "manual continuation while placement drains invalidates the old paint and releases waiting work": 2, - "moving the App group during a keyboard answer preserves native source input and refuses the late reveal": 53, + "manual continuation while placement drains invalidates the old paint and releases waiting work": 3, + "moving the App group during a keyboard answer preserves native source input and refuses the late reveal": 52, "native placement drains the current required image and holds newer image delivery until release": 6, - "new recorded selection promptly rejects a hidden recorded gap without an AbortSignal or fabricated paint confirmation": 3, - "new seek retires hidden recorded pixels without waiting for a foreground window": 2, + "new recorded selection promptly rejects a hidden recorded gap without an AbortSignal or fabricated paint confirmation": 2, + "new seek retires hidden recorded pixels without waiting for a foreground window": 3, "pane handoff refuses unleased, unreserved, aborted and already closed viewport ownership": 2, "pane handoff waits for the accepted required paint before detaching its old acknowledgement listener": 2, - "placement behind a hidden recorded image times out, releases its reservation and leaves the image to paint later": 2530, - "rebinding both live-history and replay leases preserves the independent recorder and paints only the chosen presentation": 53, + "placement behind a hidden recorded image times out, releases its reservation and leaves the image to paint later": 2297, + "rebinding both live-history and replay leases preserves the independent recorder and paints only the chosen presentation": 52, "recorded phase receipt precedes presentation and hidden history never earns a renderer confirmation": 1, - "recording painting without a valid current hidden receipt retains a bounded timeout": 380, - "recording receives a stream frame only after its CDP acknowledgement is sent and observer failure cannot stop rendering": 61, - "refreshing a visible recorded application does not reveal its native pane over Study focus": 53, + "recording painting without a valid current hidden receipt retains a bounded timeout": 340, + "recording receives a stream frame only after its CDP acknowledgement is sent and observer failure cannot stop rendering": 62, + "refreshing a visible recorded application does not reveal its native pane over Study focus": 51, "replacement renderer promptly rejects a hidden recorded gap without an AbortSignal or fabricated paint confirmation": 3, "required frame progress remains private diagnostic evidence until the matching paint acknowledgement": 3, - "revealing a destroyed renderer cannot confirm an image using its old readiness response": 55, - "stale or malformed visibility cannot confirm hidden recorded pixels or change the current renderer clock": 4, - "the Application pane asks its owner to give the keyboard back before it is revealed over the file the debugger focused at a pause, and leaves the keyboard where the owner put it when the owner gave the keyboard back": 53, + "revealing a destroyed renderer cannot confirm an image using its old readiness response": 54, + "stale or malformed visibility cannot confirm hidden recorded pixels or change the current renderer clock": 3, + "the Application pane asks its owner to give the keyboard back before it is revealed over the file the debugger focused at a pause, and leaves the keyboard where the owner put it when the owner gave the keyboard back": 52, "the Application pane asks its owner to give the keyboard back before it is revealed over the file the debugger focused at a pause, and takes the keyboard and tells its owner when the owner could not answer": 52, - "the Application pane asks its owner to give the keyboard back before it is revealed over the file the debugger focused at a pause, and takes the keyboard and tells its owner when the owner gave it to nobody": 53, - "the Application pane leaves the keyboard focus where it is when it is revealed while the learner went back to Cursor's chat after a pause and the editor names the chat's group": 51, + "the Application pane asks its owner to give the keyboard back before it is revealed over the file the debugger focused at a pause, and takes the keyboard and tells its owner when the owner gave it to nobody": 52, + "the Application pane leaves the keyboard focus where it is when it is revealed while the learner went back to Cursor's chat after a pause and the editor names the chat's group": 52, "the Application pane leaves the keyboard focus where it is when it is revealed while the learner went back to Cursor's chat after a pause and the editor still names the paused file's tab, with no active text editor": 52, - "the Application pane takes the keyboard and tells its owner two seconds after it asked an owner that does not answer, and not before": 302, - "the Application pane takes the keyboard focus when it is revealed over the file the debugger focused at a pause": 53, - "the Application pane tells its owner once when it took the keyboard from the file the debugger focused at a pause": 53, - "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak leaves the keyboard where it is when the owner could not answer": 53, - "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak leaves the keyboard where it is when the owner does not exist": 53, - "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak leaves the keyboard where it is when the owner says that the keyboard is not in that editor": 53, - "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak takes the keyboard and tells its owner when the owner says that the learner works in that editor": 53, - "the Application pane that comes to the front over the active text editor while no debug session has stopped yet leaves the keyboard where it is when the owner could not answer": 53, - "the Application pane that comes to the front over the active text editor while no debug session has stopped yet leaves the keyboard where it is when the owner does not exist": 53, + "the Application pane takes the keyboard and tells its owner two seconds after it asked an owner that does not answer, and not before": 271, + "the Application pane takes the keyboard focus when it is revealed over the file the debugger focused at a pause": 51, + "the Application pane tells its owner once when it took the keyboard from the file the debugger focused at a pause": 52, + "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak leaves the keyboard where it is when the owner could not answer": 52, + "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak leaves the keyboard where it is when the owner does not exist": 52, + "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak leaves the keyboard where it is when the owner says that the keyboard is not in that editor": 52, + "the Application pane that comes to the front over the active text editor while a session is paused and the learner turned off debug.focusEditorOnBreak takes the keyboard and tells its owner when the owner says that the learner works in that editor": 52, + "the Application pane that comes to the front over the active text editor while no debug session has stopped yet leaves the keyboard where it is when the owner could not answer": 52, + "the Application pane that comes to the front over the active text editor while no debug session has stopped yet leaves the keyboard where it is when the owner does not exist": 52, "the Application pane that comes to the front over the active text editor while no debug session has stopped yet leaves the keyboard where it is when the owner says that the keyboard is not in that editor": 52, - "the Application pane that comes to the front over the active text editor while no debug session has stopped yet takes the keyboard and tells its owner when the owner says that the learner works in that editor": 53, - "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread leaves the keyboard where it is when the owner could not answer": 53, - "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread leaves the keyboard where it is when the owner does not exist": 53, - "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread leaves the keyboard where it is when the owner says that the keyboard is not in that editor": 53, - "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread takes the keyboard and tells its owner when the owner says that the learner works in that editor": 51, - "viewport closure promptly rejects a hidden recorded gap without an AbortSignal or fabricated paint confirmation": 3 + "the Application pane that comes to the front over the active text editor while no debug session has stopped yet takes the keyboard and tells its owner when the owner says that the learner works in that editor": 52, + "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread leaves the keyboard where it is when the owner could not answer": 52, + "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread leaves the keyboard where it is when the owner does not exist": 51, + "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread leaves the keyboard where it is when the owner says that the keyboard is not in that editor": 52, + "the Application pane that comes to the front over the active text editor while the session runs again after a pause and the editor reports its thread takes the keyboard and tells its owner when the owner says that the learner works in that editor": 52, + "viewport closure promptly rejects a hidden recorded gap without an AbortSignal or fabricated paint confirmation": 1 } }, "runtime-cdp.test.js": { - "totalMs": 18 + "totalMs": 17 }, "runtime-cursorCdpBridge.test.js": { - "totalMs": 33 + "totalMs": 32 }, "runtime-evidence.test.js": { - "totalMs": 23 + "totalMs": 18 }, "runtime-frameDelivery.test.js": { - "totalMs": 256 + "totalMs": 252 }, "runtime-host.test.js": { "totalMs": 1 }, "runtime-hostCleanup.test.js": { - "totalMs": 1145 + "totalMs": 1123 }, "runtime-hostInstallation.test.js": { - "totalMs": 60 + "totalMs": 55 }, "runtime-isEndpointClosed.test.js": { - "totalMs": 7 + "totalMs": 8 }, "runtime-pauseGate.test.js": { "totalMs": 1 }, "runtime-profileProcesses.test.js": { - "totalMs": 107 + "totalMs": 105 }, "runtime-waitUntil.test.js": { - "totalMs": 258 + "totalMs": 255 }, "runtimeHarnessUtils.test.js": { - "totalMs": 179 + "totalMs": 181 }, "sanitizeCause.test.js": { - "totalMs": 1 + "totalMs": 2 }, "savedLaterNote.test.js": { "totalMs": 1 @@ -1730,19 +1759,19 @@ "totalMs": 3 }, "servedWikiPageHtml.test.js": { - "totalMs": 13 + "totalMs": 12 }, "serverBundle.test.js": { - "totalMs": 33 + "totalMs": 29 }, "serverInspectorOwnership.test.js": { - "totalMs": 135 + "totalMs": 140 }, "service.test.js": { - "totalMs": 2809 + "totalMs": 3052 }, "settledWithin.test.js": { - "totalMs": 2 + "totalMs": 3 }, "showWikiChatWatchStatus.test.js": { "totalMs": 1 @@ -1754,7 +1783,7 @@ "totalMs": 1 }, "sourceMapGeneratedRange.test.js": { - "totalMs": 3 + "totalMs": 4 }, "stackRowsAtOneHeight.test.js": { "totalMs": 2 @@ -1766,1756 +1795,1768 @@ "totalMs": 1 }, "stepPastNoRealFolder.test.js": { - "totalMs": 4 + "totalMs": 3 }, "stopKeyboardHandOver.test.js": { "totalMs": 3 }, "storageCapacity.test.js": { - "totalMs": 1646 + "totalMs": 1506 }, "storedDebugStops.test.js": { "totalMs": 3 }, + "stripTerminalControls.test.js": { + "totalMs": 1 + }, "studyAdmission.test.js": { - "totalMs": 8221, + "totalMs": 8257, "tests": { - "a repeat of a refused start that is rejected because another run is live keeps the refused run, and begins a new run once that run has stopped": 296, - "a repeat of a refused start that is rejected while a presentation change is pending keeps the refused run": 150, - "a repeat of a refused start that names an unsupported profile is rejected and keeps the refused run": 136, - "a repeat of a refused start whose arguments do not match the profile is rejected and keeps the refused run": 133, - "a repeat of the newest refused start with sixteen runs retained takes that run's slot and keeps the oldest run": 974, - "a run on a full study library is refused before the application receives any input and names the limit setting": 168, - "a run on a study library below its limit prepares and its click reaches the application": 371, - "a run refused on a full study library after the Trash refused a removal names only the limit setting": 102, - "a run started under an invalid Saved Study Limit setting ends as a missing prerequisite that names the setting, before the application receives any input": 149, - "a run stopped while its study library admission is being read acquires no runtime and reserves no recording": 143, - "a run the full study library refuses is never offered for a history checkpoint, also while its admission is still being read": 149, - "a run whose final evidence write fails after its release freed every resource is stopped with that failure as its error, and the next start is admitted": 240, - "a run whose recording slots alone are used up still prepares and reports its recording as failed": 324, - "a run whose repository storage is unavailable ends as a missing prerequisite and is still offered for a history checkpoint": 113, - "a run whose repository storage is unavailable on a full study library is not offered for a history checkpoint": 144, - "a run whose study library cannot be read ends as a missing prerequisite whose message names the read error, and is still offered for a history checkpoint": 83, - "a start repeated while its run awaits the admission, and while the refused run is still ending, returns the same receipt": 186, - "a start that repeats the key of a refused run on a library that is still full is refused again as a new run and retains one run": 253, - "a start that repeats the key of a run the full study library refused begins a new run, which prepares once the library has room": 262, - "a start that repeats the key of an admitted run returns the same receipt, also after its saved study was removed": 219, - "a start that reuses the key of a forgotten refused run begins a new run": 1049, - "a start that reuses the key of a refused run with other arguments begins a new run instead of a conflict": 170, - "after sixteen runs refused on a full study library a further start is accepted and the oldest refused run is forgotten": 1037, + "a repeat of a refused start that is rejected because another run is live keeps the refused run, and begins a new run once that run has stopped": 353, + "a repeat of a refused start that is rejected while a presentation change is pending keeps the refused run": 136, + "a repeat of a refused start that names an unsupported profile is rejected and keeps the refused run": 138, + "a repeat of a refused start whose arguments do not match the profile is rejected and keeps the refused run": 144, + "a repeat of the newest refused start with sixteen runs retained takes that run's slot and keeps the oldest run": 984, + "a run on a full study library is refused before the application receives any input and names the limit setting": 176, + "a run on a study library below its limit prepares and its click reaches the application": 336, + "a run refused on a full study library after the Trash refused a removal names only the limit setting": 104, + "a run started under an invalid Saved Study Limit setting ends as a missing prerequisite that names the setting, before the application receives any input": 140, + "a run stopped while its study library admission is being read acquires no runtime and reserves no recording": 130, + "a run the full study library refuses is never offered for a history checkpoint, also while its admission is still being read": 147, + "a run whose final evidence write fails after its release freed every resource is stopped with that failure as its error, and the next start is admitted": 275, + "a run whose recording slots alone are used up still prepares and reports its recording as failed": 277, + "a run whose repository storage is unavailable ends as a missing prerequisite and is still offered for a history checkpoint": 150, + "a run whose repository storage is unavailable on a full study library is not offered for a history checkpoint": 121, + "a run whose study library cannot be read ends as a missing prerequisite whose message names the read error, and is still offered for a history checkpoint": 177, + "a start repeated while its run awaits the admission, and while the refused run is still ending, returns the same receipt": 160, + "a start that repeats the key of a refused run on a library that is still full is refused again as a new run and retains one run": 225, + "a start that repeats the key of a run the full study library refused begins a new run, which prepares once the library has room": 271, + "a start that repeats the key of an admitted run returns the same receipt, also after its saved study was removed": 264, + "a start that reuses the key of a forgotten refused run begins a new run": 1027, + "a start that reuses the key of a refused run with other arguments begins a new run instead of a conflict": 204, + "after sixteen runs refused on a full study library a further start is accepted and the oldest refused run is forgotten": 981, "codebook_status reports how many studies are saved beside the current limit and says that the 256 is only the highest limit": 307, - "in a WSL remote window the first full-library refusal names no removal": 237, - "publishing a Repository Wiki revision that links a saved study the library no longer holds is refused as an unavailable book that names that study": 203, - "the events and manifest resources of a run refused on a full study library answer as for a run that never started, not as evidence that was removed": 138, - "the next actions of a run refused on a full study library do not offer to read its history": 151, - "the run resource of a run refused on a full study library reports its history as unavailable because the run never started": 143, - "the run resource of a run whose saved study the learner removed reports its history and its recording as gone": 194 + "in a WSL remote window the first full-library refusal names no removal": 238, + "publishing a Repository Wiki revision that links a saved study the library no longer holds is refused as an unavailable book that names that study": 184, + "the events and manifest resources of a run refused on a full study library answer as for a run that never started, not as evidence that was removed": 129, + "the next actions of a run refused on a full study library do not offer to read its history": 161, + "the run resource of a run refused on a full study library reports its history as unavailable because the run never started": 119, + "the run resource of a run whose saved study the learner removed reports its history and its recording as gone": 200 } }, "studyErrorNamingCause.test.js": { "totalMs": 1 }, "studyEvidence.test.js": { - "totalMs": 25 + "totalMs": 14 }, "studyHtml.test.js": { - "totalMs": 2 + "totalMs": 3 }, "studyRemoval.test.js": { - "totalMs": 7126 + "totalMs": 7013 }, "studyRemovalMessages.test.js": { - "totalMs": 5 + "totalMs": 4 }, "studyWorkspace.test.js": { - "totalMs": 32826, + "totalMs": 32923, "tests": { - "Cursor's chat that the editor still names at a pause of a live run gets the keyboard back once the captured source is shown, and the learner is told once that a view cannot be told from it, while the learner typed in the chat": 159, - "Cursor's chat that the editor still names at a pause of a live run gets the keyboard back once the captured source is shown, and the learner is told once that a view cannot be told from it, while the learner typed in the terminal": 179, - "Node journal time seeking restores exact stops and clears debugger across output and result events": 339, - "Show Variables finishes without an error when Run and Debug keeps showing another debug session": 702, - "Show Variables lists the recorded values on its first press when Run and Debug was not opened in the editor session": 618, - "Show Variables on a host with neither a Variables nor a Run and Debug command tells the learner the manual step in one sentence": 184, - "Show Variables on a host with the Variables focus command runs only the steps that host registers": 168, - "Show Variables on a host without a Variables focus command opens Run and Debug and leaves no error": 152, - "Show Variables on a reader that is closed while the press waits for Variables sends no list command": 517, - "Show Variables opens Run and Debug with Variables expanded and then expands its first scope": 106, - "Show Variables waits for a Variables view that missed the stop while hidden and sends it no list command once it listed the values itself": 777, - "VS Code's chat editor tab in a floating window that had the keyboard before a pause of a live run has it again once the captured source is shown, and the learner is told once that a view cannot be told from it": 167, - "VS Code's chat editor tab that had the keyboard before a pause of a live run has it again once the captured source is shown, and the learner is told once that a view cannot be told from it": 164, - "a Node history stop whose native presentation fails while still selected reports the failure and keeps the previous event": 217, - "a Node stop selected before the reader closed keeps its matching captured source when its history is selected again": 260, - "a Node stop selected on the timeline whose captured source differs from its recorded position is reported with unavailable captured source": 228, - "a Node stop selection that was waiting for the stopped historical debugger when the reader closed starts no new session": 220, - "a Node stop still loading when a recording opens never becomes the Node timeline position": 377, - "a frame selected at a pause while the learner types in Cursor's chat tab leaves the keyboard in the chat: nothing is shown with the keyboard and no notice is told": 199, - "a later explanation invalidates the earlier save label until its new content is explicitly saved": 243, - "a learner file explicitly placed in App after chat return rejects background replacement and permits explicit App recovery": 170, - "a learner in Cursor who clicks into a file during a pause of a live run keeps the keyboard in that file through the reader's next render of the pause, and the chat's tab does not take it": 196, - "a learner in Cursor who clicks into the paused file and steps through it keeps the keyboard in that file at every step and when the run goes on, and the chat's tab does not take it": 232, - "a learner in Cursor who clicks into the paused file as a pause of a live run ends, before the reader settled that pause, keeps the keyboard in that file, and the chat's tab does not take it": 203, - "a learner in Cursor who left the chat for a file 1.001 seconds before Run and Debug named a pause of a live run keeps the keyboard in the editor, and the chat's tab does not take it": 175, - "a learner in Cursor who left the chat for a file between two pauses of a live run keeps the keyboard in the editor at the second pause, and the chat's tab does not take it": 158, - "a learner in Cursor who presses Focus source at a pause of a live run keeps the keyboard in the captured source, and Read Source then shows it enlarged": 152, - "a learner in Cursor who presses Focus source before the reader showed a pause of a live run keeps the keyboard in the captured source through the next render of that pause": 171, - "a learner in Cursor who selects another frame of a stop the reader has not shown yet keeps the keyboard in the Call Stack view when the run goes on, and the chat's tab does not take it": 143, - "a learner in Cursor who went from a file to the chat between two pauses of a live run has the keyboard in the chat again at the second pause": 139, - "a learner in Cursor who went from a file to the chat during a pause of a live run has the keyboard in the chat again at the next stop, also when the run stops again before the editor reports that it runs": 194, - "a learner in Cursor who went from the chat to a file during a pause of a live run keeps the keyboard in the editor at the next pause, and the chat's tab does not take it": 142, - "a learner in Cursor who went from the chat to a file while no debug session is paused keeps the keyboard in that file when the reader shows a captured source, and the chat's tab does not take it": 157, - "a learner in Cursor who worked in a file for a minute before a pause of a live run keeps the keyboard in the editor at that pause, and the chat's tab does not take it": 165, - "a learner in Cursor whose own debug session stops and goes on, with no live run of Codebook, keeps the keyboard in the file the debugger opened, and the chat's tab does not take it": 142, - "a learner who selects other frames of one pause in the Call Stack view keeps the keyboard in that view beside Cursor's chat as an editor tab: nothing is shown with the keyboard, no notice is told and no return runs": 240, + "Cursor's chat that the editor still names at a pause of a live run gets the keyboard back once the captured source is shown, and the learner is told once that a view cannot be told from it, while the learner typed in the chat": 181, + "Cursor's chat that the editor still names at a pause of a live run gets the keyboard back once the captured source is shown, and the learner is told once that a view cannot be told from it, while the learner typed in the terminal": 168, + "Node journal time seeking restores exact stops and clears debugger across output and result events": 353, + "Show Variables finishes without an error when Run and Debug keeps showing another debug session": 676, + "Show Variables lists the recorded values on its first press when Run and Debug was not opened in the editor session": 646, + "Show Variables on a host with neither a Variables nor a Run and Debug command tells the learner the manual step in one sentence": 155, + "Show Variables on a host with the Variables focus command runs only the steps that host registers": 165, + "Show Variables on a host without a Variables focus command opens Run and Debug and leaves no error": 156, + "Show Variables on a reader that is closed while the press waits for Variables sends no list command": 531, + "Show Variables opens Run and Debug with Variables expanded and then expands its first scope": 108, + "Show Variables waits for a Variables view that missed the stop while hidden and sends it no list command once it listed the values itself": 804, + "VS Code's chat editor tab in a floating window that had the keyboard before a pause of a live run has it again once the captured source is shown, and the learner is told once that a view cannot be told from it": 174, + "VS Code's chat editor tab that had the keyboard before a pause of a live run has it again once the captured source is shown, and the learner is told once that a view cannot be told from it": 146, + "a Node history stop whose native presentation fails while still selected reports the failure and keeps the previous event": 215, + "a Node stop selected before the reader closed keeps its matching captured source when its history is selected again": 252, + "a Node stop selected on the timeline whose captured source differs from its recorded position is reported with unavailable captured source": 247, + "a Node stop selection that was waiting for the stopped historical debugger when the reader closed starts no new session": 219, + "a Node stop still loading when a recording opens never becomes the Node timeline position": 370, + "a frame selected at a pause while the learner types in Cursor's chat tab leaves the keyboard in the chat: nothing is shown with the keyboard and no notice is told": 195, + "a later explanation invalidates the earlier save label until its new content is explicitly saved": 215, + "a learner file explicitly placed in App after chat return rejects background replacement and permits explicit App recovery": 165, + "a learner in Cursor who clicks into a file during a pause of a live run keeps the keyboard in that file through the reader's next render of the pause, and the chat's tab does not take it": 200, + "a learner in Cursor who clicks into the paused file and steps through it keeps the keyboard in that file at every step and when the run goes on, and the chat's tab does not take it": 237, + "a learner in Cursor who clicks into the paused file as a pause of a live run ends, before the reader settled that pause, keeps the keyboard in that file, and the chat's tab does not take it": 176, + "a learner in Cursor who left the chat for a file 1.001 seconds before Run and Debug named a pause of a live run keeps the keyboard in the editor, and the chat's tab does not take it": 146, + "a learner in Cursor who left the chat for a file between two pauses of a live run keeps the keyboard in the editor at the second pause, and the chat's tab does not take it": 171, + "a learner in Cursor who presses Focus source at a pause of a live run keeps the keyboard in the captured source, and Read Source then shows it enlarged": 165, + "a learner in Cursor who presses Focus source before the reader showed a pause of a live run keeps the keyboard in the captured source through the next render of that pause": 182, + "a learner in Cursor who selects another frame of a stop the reader has not shown yet keeps the keyboard in the Call Stack view when the run goes on, and the chat's tab does not take it": 130, + "a learner in Cursor who went from a file to the chat between two pauses of a live run has the keyboard in the chat again at the second pause": 137, + "a learner in Cursor who went from a file to the chat during a pause of a live run has the keyboard in the chat again at the next stop, also when the run stops again before the editor reports that it runs": 145, + "a learner in Cursor who went from the chat to a file during a pause of a live run keeps the keyboard in the editor at the next pause, and the chat's tab does not take it": 143, + "a learner in Cursor who went from the chat to a file while no debug session is paused keeps the keyboard in that file when the reader shows a captured source, and the chat's tab does not take it": 230, + "a learner in Cursor who worked in a file for a minute before a pause of a live run keeps the keyboard in the editor at that pause, and the chat's tab does not take it": 166, + "a learner in Cursor whose own debug session stops and goes on, with no live run of Codebook, keeps the keyboard in the file the debugger opened, and the chat's tab does not take it": 138, + "a learner who selects other frames of one pause in the Call Stack view keeps the keyboard in that view beside Cursor's chat as an editor tab: nothing is shown with the keyboard, no notice is told and no return runs": 216, "a learner who selects other frames of one pause in the Call Stack view keeps the keyboard in that view beside a side-view chat: nothing is shown with the keyboard, no notice is told and no return runs": 237, - "a learner's move back onto the captured source after the reader's render of a pause settled is the learner's, so an agent's next request reads the learner's place as known": 151, - "a normal chat run retires the explanation pane without reopening the reader": 123, - "a pause of a live run is shown and committed when the editor refuses to give the keyboard back to Cursor's chat, and the learner is told where the keyboard is": 168, - "a refused recording open lets a loading Node history stop finish its selection": 232, - "a render of a saved study while a debug session of the learner's own is paused, with no live run of Codebook, does not send the keyboard to Cursor's chat": 179, - "a saved Node stop shown in Run and Debug before the reader closed offers Inspect again after the reader reopens": 254, - "a saved Node stop whose values Run and Debug has not loaded tells the learner where to load them until they load": 220, - "a settings page of the main editor that was in front before a pause of a live run does not get Cursor's chat focused while the editor's group count cannot be read": 163, - "a settings page that was in front before a pause of a live run does not get the keyboard at that pause, and the learner is told once where the keyboard is": 156, - "a shown Node stop whose captured text no longer matches its hash is reported to the reader even while another event is selected": 198, - "a stale save button cannot finalize a different recorded session": 175, - "a stop reported beside an actual recording preserves its playhead and external source without returning to Cursor chat": 509, - "a window round trip during summary opening cannot confirm an obsolete focus request": 275, - "actual captured-source takeovers tell the learner once across reader replacement in the same editor session": 239, - "an agent returning the reader to the current run leaves a selected Node history even while the reader still follows the run": 203, - "an isolated App preserves closed-reader native input and actual source replacements tell the learner once in Cursor": 160, - "an unanswered Move Learning Summary offer is made again in the next editor session": 427, - "an unreadable Node history folder is reported while the saved-study reader still opens": 116, - "before the first pause of a run whose stop was requested after its declared line, the Study pane and the source highlight stand on the requested line": 624, - "bottom playback remains available with the summary collapsed and restores fallback when hidden": 314, - "captured-source refresh shares chat return right after that return, before the editor reports the chat without another App reveal": 169, + "a learner's move back onto the captured source after the reader's render of a pause settled is the learner's, so an agent's next request reads the learner's place as known": 178, + "a normal chat run retires the explanation pane without reopening the reader": 146, + "a pause of a live run is shown and committed when the editor refuses to give the keyboard back to Cursor's chat, and the learner is told where the keyboard is": 159, + "a refused recording open lets a loading Node history stop finish its selection": 248, + "a render of a saved study while a debug session of the learner's own is paused, with no live run of Codebook, does not send the keyboard to Cursor's chat": 174, + "a saved Node stop shown in Run and Debug before the reader closed offers Inspect again after the reader reopens": 239, + "a saved Node stop whose values Run and Debug has not loaded tells the learner where to load them until they load": 216, + "a settings page of the main editor that was in front before a pause of a live run does not get Cursor's chat focused while the editor's group count cannot be read": 150, + "a settings page that was in front before a pause of a live run does not get the keyboard at that pause, and the learner is told once where the keyboard is": 143, + "a shown Node stop whose captured text no longer matches its hash is reported to the reader even while another event is selected": 170, + "a stale save button cannot finalize a different recorded session": 223, + "a stop reported beside an actual recording preserves its playhead and external source without returning to Cursor chat": 507, + "a window round trip during summary opening cannot confirm an obsolete focus request": 311, + "actual captured-source takeovers tell the learner once across reader replacement in the same editor session": 225, + "an agent returning the reader to the current run leaves a selected Node history even while the reader still follows the run": 167, + "an isolated App preserves closed-reader native input and actual source replacements tell the learner once in Cursor": 165, + "an unanswered Move Learning Summary offer is made again in the next editor session": 385, + "an unreadable Node history folder is reported while the saved-study reader still opens": 120, + "before the first pause of a run whose stop was requested after its declared line, the Study pane and the source highlight stand on the requested line": 620, + "bottom playback remains available with the summary collapsed and restores fallback when hidden": 313, + "captured-source refresh shares chat return right after that return, before the editor reports the chat without another App reveal": 156, "captured-source refresh shares chat return while the reader's return of the keyboard to the chat is still running without another App reveal": 157, - "closing it after the learner went to another part leaves the focus where it is": 779, - "closing replay rejects late summary controls and leaves saved learning unchanged": 305, - "closing the reader drops the Run and Debug hint of a saved Node stop": 252, - "closing the reader stops Node Play at once, so no Node stop starts while closing drains": 781, - "closing the side bar while the Learning summary holds the keyboard focus moves the focus to the active editor group": 1204, - "disposed bottom playback documents cannot move the selected recorded moment": 287, - "editor Settings changes recover full study and recording storage without recreating the workspace": 215, - "ending the historical session re-enables Inspect for the selected Node stop, and Inspect restarts the session": 269, - "explicit learning save verifies durable context and labels missing summary and debugger history as partial": 201, - "failed explicit learning context save stays retryable without replacing durable history with success": 209, - "in Cursor the Learning summary offers Move Learning Summary… in its title after the offer's notification is gone": 283, - "in Cursor the first shown Learning summary offers the Move View step once, and choosing it opens the move list for the summary": 301, - "in Cursor, Show Variables pressed in the Learning summary leaves the keyboard focus in Run and Debug when its view takes the summary’s place": 943, - "in Cursor, Show Variables that took the Learning summary's place in the side bar offers the Move View step": 310, - "in VS Code, which accepts the secondary side bar container, showing the Learning summary offers no move": 347, - "inspecting a Node stop whose captured source differs from its recorded position refuses native debugging": 206, - "live Restore refuses a late native receipt loss instead of claiming recovery": 122, - "live entry preserves a learner document sharing the former explanation group": 132, - "live explanation reserves app and source without a custom explanation pane": 124, - "live explanation reserves app and source without a custom explanation pane while preserving a separate chat": 120, - "moving to another Node history event while a stop still loads its native values reports no failure for the abandoned stop": 241, - "native values loading for a saved Node stop drops its Run and Debug hint and keeps the stop shown in the native debugger": 222, - "opening a recording drops the Run and Debug hint of a saved Node stop and re-enables its Inspect": 450, - "opening a recording while a Node history stop still loads its native values reports no failure for the abandoned stop": 444, - "opening another view in the Learning summary’s place leaves the keyboard focus in that view when the summary reports the lost focus after it was hidden": 755, - "pressing Inspect again while the editor is still stopping the ended historical session shows the Node stop through one new session": 366, - "reading the replay summary leaves an unfocused work window and historical position untouched": 302, - "reopening a Node history after the learner stops its historical debugger restores native values": 258, - "repeated save clicks share finalization and keep the pending status non-actionable": 214, - "replay Restore preserves newer draft intent during native unmaximize": 583, - "replay Restore preserves newer window round trip intent during native unmaximize": 277, - "restored Observed moments leaves its loading state after workspace initialization": 162, - "restoring the live layout cannot recreate a custom explanation pane or select a retired variant": 124, - "returning to the current run leaves a selected Node history so its missing-video notice no longer masks the live application": 172, - "saved Node history is selectable in the reader without entering browser playback": 1120, - "saved replay restores its summary after a native-chat-only live explanation": 308, - "saving an active explanation stops only its owned capture and retains the recorded learning": 170, - "saving without a captured session leaves the learning status hidden": 83, - "sealed repository source remains restorable before the first debugger observation": 173, - "seeking a Node history onto a stop after the learner stops its historical debugger explains how to restart it": 333, - "selecting a Node stop after the learner stops its historical debugger restarts it instead of freezing the reader": 391, - "starting live explanation retires only its previous empty explanation group": 223, - "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while no debug session is paused": 161, - "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the learner turned off debug.focusEditorOnBreak": 143, - "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the learner went back to Cursor's chat after the pause and the editor names the chat's group": 159, - "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the learner went back to Cursor's chat after the pause and the editor still names the paused file's tab, with no active text editor": 144, - "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the session runs again after a pause and the editor reports its thread": 153, - "the captured source takes the keyboard focus when it replaces the file the debugger focused at a pause in the source group": 183, - "the captured source takes the keyboard focus when it replaces the file the debugger focused at a stop of a debug session that started before the reader, whose stop events the reader does not hear": 173, - "the captured source that takes the keyboard from the file the debugger focused at a pause says once in an editor session where the keyboard is, in Cursor with a side-view chat": 165, - "the captured source that takes the keyboard from the file the debugger focused at a pause says once in an editor session where the keyboard is, in Visual Studio Code with a side-view chat": 159, - "the captured source the reader's render of a pause gave the keyboard is no learner's move onto it, so an agent's next request reads the learner's place as unknown": 197, - "the chat keeps the keyboard after native source capture without a delayed App focus": 280, - "the chat that had the keyboard before a pause of a live run has it again after the captured source is shown, at that pause and at the next, when the editor named the chat's group": 161, - "the chat that had the keyboard before a pause of a live run has it again after the captured source is shown, at that pause and at the next, when the editor named the learner's file without an active text editor": 157, - "the chat that had the keyboard before a pause of a live run has it again at the next stop, also when the run stops again before the editor reports that it runs": 154, - "the chat that had the keyboard before a pause of a live run has it again when that pause ends before the reader showed its captured source, and at the next pause": 255, + "closing it after the learner went to another part leaves the focus where it is": 781, + "closing replay rejects late summary controls and leaves saved learning unchanged": 280, + "closing the reader drops the Run and Debug hint of a saved Node stop": 221, + "closing the reader stops Node Play at once, so no Node stop starts while closing drains": 775, + "closing the side bar while the Learning summary holds the keyboard focus moves the focus to the active editor group": 1221, + "disposed bottom playback documents cannot move the selected recorded moment": 293, + "editor Settings changes recover full study and recording storage without recreating the workspace": 212, + "ending the historical session re-enables Inspect for the selected Node stop, and Inspect restarts the session": 256, + "explicit learning save verifies durable context and labels missing summary and debugger history as partial": 243, + "failed explicit learning context save stays retryable without replacing durable history with success": 258, + "in Cursor the Learning summary offers Move Learning Summary… in its title after the offer's notification is gone": 320, + "in Cursor the first shown Learning summary offers the Move View step once, and choosing it opens the move list for the summary": 292, + "in Cursor, Show Variables pressed in the Learning summary leaves the keyboard focus in Run and Debug when its view takes the summary’s place": 750, + "in Cursor, Show Variables that took the Learning summary's place in the side bar offers the Move View step": 316, + "in VS Code, which accepts the secondary side bar container, showing the Learning summary offers no move": 343, + "inspecting a Node stop whose captured source differs from its recorded position refuses native debugging": 202, + "live Restore refuses a late native receipt loss instead of claiming recovery": 120, + "live entry preserves a learner document sharing the former explanation group": 124, + "live explanation reserves app and source without a custom explanation pane": 117, + "live explanation reserves app and source without a custom explanation pane while preserving a separate chat": 124, + "moving to another Node history event while a stop still loads its native values reports no failure for the abandoned stop": 257, + "native values loading for a saved Node stop drops its Run and Debug hint and keeps the stop shown in the native debugger": 250, + "opening a recording drops the Run and Debug hint of a saved Node stop and re-enables its Inspect": 417, + "opening a recording while a Node history stop still loads its native values reports no failure for the abandoned stop": 420, + "opening another view in the Learning summary’s place leaves the keyboard focus in that view when the summary reports the lost focus after it was hidden": 1382, + "pressing Inspect again while the editor is still stopping the ended historical session shows the Node stop through one new session": 369, + "reading the replay summary leaves an unfocused work window and historical position untouched": 316, + "reopening a Node history after the learner stops its historical debugger restores native values": 256, + "repeated save clicks share finalization and keep the pending status non-actionable": 192, + "replay Restore preserves newer draft intent during native unmaximize": 588, + "replay Restore preserves newer window round trip intent during native unmaximize": 295, + "restored Observed moments leaves its loading state after workspace initialization": 147, + "restoring the live layout cannot recreate a custom explanation pane or select a retired variant": 126, + "returning to the current run leaves a selected Node history so its missing-video notice no longer masks the live application": 157, + "saved Node history is selectable in the reader without entering browser playback": 1218, + "saved replay restores its summary after a native-chat-only live explanation": 300, + "saving an active explanation stops only its owned capture and retains the recorded learning": 180, + "saving without a captured session leaves the learning status hidden": 78, + "sealed repository source remains restorable before the first debugger observation": 157, + "seeking a Node history onto a stop after the learner stops its historical debugger explains how to restart it": 259, + "selecting a Node stop after the learner stops its historical debugger restarts it instead of freezing the reader": 272, + "starting live explanation retires only its previous empty explanation group": 230, + "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while no debug session is paused": 162, + "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the learner turned off debug.focusEditorOnBreak": 153, + "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the learner went back to Cursor's chat after the pause and the editor names the chat's group": 147, + "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the learner went back to Cursor's chat after the pause and the editor still names the paused file's tab, with no active text editor": 141, + "the captured source leaves the keyboard focus where it is when it replaces a file in the source group while the session runs again after a pause and the editor reports its thread": 155, + "the captured source takes the keyboard focus when it replaces the file the debugger focused at a pause in the source group": 220, + "the captured source takes the keyboard focus when it replaces the file the debugger focused at a stop of a debug session that started before the reader, whose stop events the reader does not hear": 140, + "the captured source that takes the keyboard from the file the debugger focused at a pause says once in an editor session where the keyboard is, in Cursor with a side-view chat": 146, + "the captured source that takes the keyboard from the file the debugger focused at a pause says once in an editor session where the keyboard is, in Visual Studio Code with a side-view chat": 177, + "the captured source the reader's render of a pause gave the keyboard is no learner's move onto it, so an agent's next request reads the learner's place as unknown": 149, + "the chat keeps the keyboard after native source capture without a delayed App focus": 234, + "the chat that had the keyboard before a pause of a live run has it again after the captured source is shown, at that pause and at the next, when the editor named the chat's group": 142, + "the chat that had the keyboard before a pause of a live run has it again after the captured source is shown, at that pause and at the next, when the editor named the learner's file without an active text editor": 151, + "the chat that had the keyboard before a pause of a live run has it again at the next stop, also when the run stops again before the editor reports that it runs": 187, + "the chat that had the keyboard before a pause of a live run has it again when that pause ends before the reader showed its captured source, and at the next pause": 207, "the chat that had the keyboard gets it back at a pause of a live run when the paused file became the active editor one second before Run and Debug named the pause, the longest the debugger's own opening of that file is given": 140, - "the chat that had the keyboard still gets it back at a pause of a live run when the learner went to a file and clicked into it half a second before the debugger opened the paused file, by the pause's own bound": 147, - "the chat that had the keyboard when the debugger was stepped from outside an editor has it again when that stop ends": 132, - "the chat that took the keyboard from the Application pane has it again at a pause of a live run, also when the editor reports the pane's view state after the tab events of that click": 160, + "the chat that had the keyboard still gets it back at a pause of a live run when the learner went to a file and clicked into it half a second before the debugger opened the paused file, by the pause's own bound": 143, + "the chat that had the keyboard when the debugger was stepped from outside an editor has it again when that stop ends": 124, + "the chat that took the keyboard from the Application pane has it again at a pause of a live run, also when the editor reports the pane's view state after the tab events of that click": 140, "the chat that took the keyboard from the Study pane has it again when a stop of a live run ends, also when the editor reports the pane's view state after the tab events of that click": 240, "the focus return runs no command for a group of the main editor, and Cursor's own for the chat's group, while the editor's layout read is no proof of which editor part answered": 75, - "time seeking in a second opened Node history presents its own stop instead of reporting a changed history": 318 + "time seeking in a second opened Node history presents its own stop instead of reporting a changed history": 306 } }, "studyWorkspaceDebugStops.test.js": { - "totalMs": 15945, + "totalMs": 15691, "tests": { "Call Stack frame clicks keep list input when captured source refreshes": 178, - "Call Stack frame clicks keep list input when captured source refreshes after source acquisition starts": 169, - "Call Stack navigation keeps source input when captured source refreshes": 167, - "Call Stack navigation keeps source input when captured source refreshes after source acquisition starts": 169, - "Cursor chat is usable at a debugger pause before historical capture publishes its observation": 234, - "Cursor chat regains keyboard at a later pause while a redundant command catalog reply is stalled": 268, - "Cursor chat regains keyboard at a pause despite a stalled layout query when its native group membership is retained": 193, - "Cursor chat regains keyboard at a pause despite a stalled layout query when its source tab report is stale": 196, - "Cursor chat regains keyboard when its command becomes available after an earlier pause could not return it": 181, - "Read Source revokes a pending chat return when the captured source is already ready": 157, - "Retry after Navigate Down Call Stack keeps the frame's file and its keyboard while VS Code reports its window unfocused": 173, - "Retry after a Call Stack click keeps the frame's file in front while Cursor names its chat part": 196, - "Retry after a click into the selected frame's file gives the captured source the keyboard while Cursor names another group": 192, - "Retry after a click into the selected frame's file gives the captured source the keyboard while VS Code reports its window unfocused": 169, - "Retry after a click into the selected frame's file leaves the keyboard in the chat input when no text editor is active": 173, - "Retry at a stop handed to the paused file gives the captured source the keyboard instead of leaving it on the window body": 182, - "a Codebook run's stop read while the learner's handed-over stop is shown does not undo that hand-over: its captured source takes the keyboard from the learner's file": 255, - "a breakpoint in a skipped file that the editor shows hands its paused file the keyboard": 79, - "a breakpoint in a skipped file whose stacks the adapter declared invalid before the editor showed it still hands its paused file the keyboard": 79, - "a browser stop read 20 ms after the server session went on, behind the server's frame, gives the paused file the keyboard when its frame arrives 468 ms after its stopped event, the longest time measured: captured source takes the keyboard while App remains visible": 142, - "a browser stop read 20 ms after the server session went on, behind the server's frame, gives the paused file the keyboard when its frame arrives 779 ms after its stopped event, one millisecond before the editor can pass the focus: captured source takes the keyboard while App remains visible": 134, - "a capture presented after Navigate Down Call Stack keeps the frame's file and its keyboard while Cursor still names the Application group": 146, - "a chat return at a Codebook stop is not undone when the editor reveals the stop's file again": 192, - "a click 200 ms after a stop whose adapter asked to keep the focus leaves the keyboard in the Call Stack view": 112, - "a click on the top frame of a pause in skipped Node code, for which the editor focused no frame, leaves the keyboard in the Call Stack view": 80, - "a file chosen while the early chat return waits keeps native keyboard ownership through the next pause": 133, - "a file opened from the Explorer after a stop whose adapter asked to keep the focus gets no keyboard from Codebook": 77, - "a file opened from the Explorer before the editor opens the paused file gets no keyboard, and the paused file gets it at its opening": 76, - "a file opened from the Explorer two seconds after a step within the paused file gets no keyboard from Codebook": 76, - "a frame the learner selects after a stop the editor never showed is a selected frame (the adapter asked the editor to keep the focus where it is): the keyboard stays in the Call Stack view and no notice is told": 162, - "a frame the learner selects after a stop the editor never showed is a selected frame (the session went on before the editor showed it): the keyboard stays in the Call Stack view and no notice is told": 162, - "a frame's file that the learner opened with one click and that is replaced by a kept tab of another file in the same column is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 145, - "a frame's file that the learner opened with one click and that is reported as a kept tab in another column is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 155, - "a frame's file that the learner opened with one click and that is reported as a new object kept open by an edit with unsaved text is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 160, - "a frame's file that the learner opened with one click and that is reported as a new object while it is a preview tab still is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 152, - "a hand-over to the paused file is not undone by a later chat return": 185, - "a learner who clicked into a frame's file and then selects another frame in the Call Stack view has the keyboard in that view: captured-source refresh leaves it there": 146, - "a learner who clicked into that file four seconds ago while the session runs is not taken to have the keyboard in it: captured-source refresh leaves the keyboard in the view and nothing is told": 159, + "Call Stack frame clicks keep list input when captured source refreshes after source acquisition starts": 164, + "Call Stack navigation keeps source input when captured source refreshes": 165, + "Call Stack navigation keeps source input when captured source refreshes after source acquisition starts": 171, + "Cursor chat is usable at a debugger pause before historical capture publishes its observation": 205, + "Cursor chat regains keyboard at a later pause while a redundant command catalog reply is stalled": 241, + "Cursor chat regains keyboard at a pause despite a stalled layout query when its native group membership is retained": 223, + "Cursor chat regains keyboard at a pause despite a stalled layout query when its source tab report is stale": 200, + "Cursor chat regains keyboard when its command becomes available after an earlier pause could not return it": 186, + "Read Source revokes a pending chat return when the captured source is already ready": 109, + "Retry after Navigate Down Call Stack keeps the frame's file and its keyboard while VS Code reports its window unfocused": 171, + "Retry after a Call Stack click keeps the frame's file in front while Cursor names its chat part": 191, + "Retry after a click into the selected frame's file gives the captured source the keyboard while Cursor names another group": 165, + "Retry after a click into the selected frame's file gives the captured source the keyboard while VS Code reports its window unfocused": 164, + "Retry after a click into the selected frame's file leaves the keyboard in the chat input when no text editor is active": 184, + "Retry at a stop handed to the paused file gives the captured source the keyboard instead of leaving it on the window body": 216, + "a Codebook run's stop read while the learner's handed-over stop is shown does not undo that hand-over: its captured source takes the keyboard from the learner's file": 214, + "a breakpoint in a skipped file that the editor shows hands its paused file the keyboard": 101, + "a breakpoint in a skipped file whose stacks the adapter declared invalid before the editor showed it still hands its paused file the keyboard": 70, + "a browser stop read 20 ms after the server session went on, behind the server's frame, gives the paused file the keyboard when its frame arrives 468 ms after its stopped event, the longest time measured: captured source takes the keyboard while App remains visible": 147, + "a browser stop read 20 ms after the server session went on, behind the server's frame, gives the paused file the keyboard when its frame arrives 779 ms after its stopped event, one millisecond before the editor can pass the focus: captured source takes the keyboard while App remains visible": 136, + "a capture presented after Navigate Down Call Stack keeps the frame's file and its keyboard while Cursor still names the Application group": 188, + "a chat return at a Codebook stop is not undone when the editor reveals the stop's file again": 171, + "a click 200 ms after a stop whose adapter asked to keep the focus leaves the keyboard in the Call Stack view": 79, + "a click on the top frame of a pause in skipped Node code, for which the editor focused no frame, leaves the keyboard in the Call Stack view": 68, + "a file chosen while the early chat return waits keeps native keyboard ownership through the next pause": 129, + "a file opened from the Explorer after a stop whose adapter asked to keep the focus gets no keyboard from Codebook": 76, + "a file opened from the Explorer before the editor opens the paused file gets no keyboard, and the paused file gets it at its opening": 67, + "a file opened from the Explorer two seconds after a step within the paused file gets no keyboard from Codebook": 59, + "a frame the learner selects after a stop the editor never showed is a selected frame (the adapter asked the editor to keep the focus where it is): the keyboard stays in the Call Stack view and no notice is told": 159, + "a frame the learner selects after a stop the editor never showed is a selected frame (the session went on before the editor showed it): the keyboard stays in the Call Stack view and no notice is told": 187, + "a frame's file that the learner opened with one click and that is replaced by a kept tab of another file in the same column is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 151, + "a frame's file that the learner opened with one click and that is reported as a kept tab in another column is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 133, + "a frame's file that the learner opened with one click and that is reported as a new object kept open by an edit with unsaved text is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 138, + "a frame's file that the learner opened with one click and that is reported as a new object while it is a preview tab still is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 143, + "a hand-over to the paused file is not undone by a later chat return": 145, + "a learner who clicked into a frame's file and then selects another frame in the Call Stack view has the keyboard in that view: captured-source refresh leaves it there": 151, + "a learner who clicked into that file four seconds ago while the session runs is not taken to have the keyboard in it: captured-source refresh leaves the keyboard in the view and nothing is told": 147, "a learner who clicks into a file while the session runs has the keyboard in that file: captured source keeps the keyboard while App stays visible and Codebook says so": 149, - "a learner who had the file opened from the Explorer with one click while the session runs is not taken to have the keyboard in it: captured-source refresh leaves the keyboard in the view and nothing is told": 137, - "a learner who selects a frame and then clicks into its file has the keyboard in that editor: captured source keeps input while App stays visible": 162, - "a learner who selects a frame and then clicks into its file has the keyboard in that editor: the captured source shown in its place takes the keyboard": 211, - "a learner who selects a frame and then goes to another file in that group has the keyboard in that editor: captured source keeps input while App stays visible": 171, - "a learner who selects a frame and then opens it with a double click after the editor sent its whole tab model again has the keyboard in that editor: captured source keeps input while App stays visible": 156, - "a learner who selects a frame and then opens it with a double click has the keyboard in that editor: captured source keeps input while App stays visible": 171, - "a learner who selects a frame and then presses a key in its file after the Navigate Call Stack command has the keyboard in that editor: captured source keeps input while App stays visible": 176, - "a learner's Step Into from the captured source gives the stepped-into file the keyboard": 187, - "a learner's stop read behind a Codebook run's frame that the editor shows before its focus pass hands its paused file the keyboard": 119, - "a live run that the learner resumes by hand hands the keyboard to the paused file": 116, - "a new main editor group cannot inherit the separate chat command from the previous layout receipt": 137, - "a newly displayed capture retains its pending chat return before its source identity is published": 160, - "a pause whose stacks the adapter declares invalid gives the paused file the keyboard again: captured source keeps the keyboard while App stays visible": 168, - "a refresh the adapter makes after a palette command gives the paused file the keyboard once": 162, - "a replayed recording never moves the keyboard into a recorded file": 863, - "a second frame of the same stop does not hand the keyboard over again": 121, - "a selection that a command moves in a selected frame's file is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 155, - "a server stop read after the editor reported the browser's thread gives the paused file the keyboard however late its frame arrives: captured source takes the keyboard while App remains visible": 191, - "a server stop read behind the frame of a session the reader does not hear counts as shown by its own handling however late its frame arrives: the captured source takes the keyboard while App remains visible": 169, - "a server stop read while the browser session is paused again is not shown by its own handling: a frame of it that arrives 300 ms later leaves the keyboard in the Call Stack view, and no notice is told": 155, - "a server stop that Codebook's own continue caused leaves the keyboard in the chat when the editor's focus pass opens its file": 150, - "a server stop that the editor shows 800 ms after the browser session went on leaves the keyboard where the learner has it: nothing is shown with the keyboard and no notice is told": 152, - "a single click on the frame of a learner's stop kept behind a Codebook run's paused frame gives no file the keyboard when its frame arrives before the file": 157, - "a single click on the frame of a learner's stop kept behind a Codebook run's paused frame leaves the keyboard in the Call Stack view": 169, - "a step within the paused file that the learner starts from a view gives the paused file the keyboard when the editor reports the stop": 99, - "a stop of a learner's own debug session that the editor shows hands its paused file the keyboard once": 103, - "a stop that Codebook's own continue causes leaves the keyboard in the chat input": 128, - "a stop that the run resumes before the editor showed it still gives the paused file the keyboard when its frame arrives right after: captured source keeps the keyboard while App stays visible": 142, - "an explicit false debug.focusEditorOnBreak leaves the editor's own keyboard handling": 118, - "an invalidated stack after a learner's stop with preserveFocusHint went on is noted as a stop that does not keep the focus, so the editor's handling of it hands its paused file the keyboard": 71, - "an invalidated stack in Cursor of a learner's session whose first stopped thread has preserveFocusHint and whose second has none arms no hand-over, so the learner's click on the second thread's frame leaves the keyboard in the Call Stack view, as Cursor handles only its oldest stored stop again": 70, - "an invalidated stack in VS Code of a learner's session whose first stopped thread has no preserveFocusHint and whose second has it hands the first thread's paused file the keyboard, as VS Code handles every stored stop again": 64, - "an invalidated stack of a learner's stop whose adapter asked to keep the focus arms no keyboard hand-over, so the editor's later focus pass leaves the keyboard in the Call Stack view": 102, - "an invalidated stack of a learner's stop with preserveFocusHint after a refused step arms no keyboard hand-over, so the editor's later focus pass leaves the keyboard in the Call Stack view": 80, - "an invalidated stack of a learner's stop with preserveFocusHint after another thread went on arms no keyboard hand-over, so the editor's later focus pass leaves the keyboard in the Call Stack view": 75, - "an owned Node test run's stop keeps the keyboard where Codebook left it": 66, - "at a stop with debug.focusEditorOnBreak off, a learner who clicks into the paused file has the keyboard in that file: captured source keeps the keyboard while App stays visible and Codebook says so": 189, - "at a stop with debug.focusEditorOnBreak off, a learner who leaves the keyboard in the view keeps it there: captured source comes without the keyboard and nothing is told": 166, - "captured source capacity preserves every pinned view and recovers after an older view is unpinned": 305, - "explicit Source in another live run reuses its unpinned native view without accumulating old live tabs": 334, - "the editor's focus pass 200 ms after a stop whose adapter asked to keep the focus gets no keyboard from Codebook": 136, - "the editor's focus pass to a learner's stop whose adapter asked to keep the focus gets no keyboard from Codebook": 123, - "the next captured source does not infer source keyboard ownership without a separate editor part": 278, - "the next captured source does not update or commit a live source after Close during native document I/O": 239, - "the next captured source keeps a pinned native projection immutable when the next captured file arrives": 282, - "the next captured source keeps a projection pinned during native document I/O immutable and offers Retry": 267, - "the next captured source keeps the learner source keyboard after another frame with native focus disabled": 320, - "the next captured source leaves an unreported native view choice alone after the learner left captured source": 256, - "the next captured source leaves the keyboard in chat when the learner returned before the new frame": 272, - "the next captured source takes no keyboard from another window after a manual source choice": 259, - "the next captured source waits for delayed native content delivery before the new captured moment becomes ready": 285, - "the paused file of a learner's stop gets the keyboard when the editor opens it, before the stop's frame is reported": 77, - "the paused file of a stop kept behind a Codebook run's paused frame gets no keyboard when the learner opens it from the Explorer": 127, - "the reader follows a debug session only while it lives: an ended session is no longer followed, and one that starts again under the same id is followed again": 87, - "the reader's own source activation is no sign of learner work after the keyboard returns to the Call Stack view": 157 + "a learner who had the file opened from the Explorer with one click while the session runs is not taken to have the keyboard in it: captured-source refresh leaves the keyboard in the view and nothing is told": 770, + "a learner who selects a frame and then clicks into its file has the keyboard in that editor: captured source keeps input while App stays visible": 140, + "a learner who selects a frame and then clicks into its file has the keyboard in that editor: the captured source shown in its place takes the keyboard": 165, + "a learner who selects a frame and then goes to another file in that group has the keyboard in that editor: captured source keeps input while App stays visible": 145, + "a learner who selects a frame and then opens it with a double click after the editor sent its whole tab model again has the keyboard in that editor: captured source keeps input while App stays visible": 146, + "a learner who selects a frame and then opens it with a double click has the keyboard in that editor: captured source keeps input while App stays visible": 129, + "a learner who selects a frame and then presses a key in its file after the Navigate Call Stack command has the keyboard in that editor: captured source keeps input while App stays visible": 161, + "a learner's Step Into from the captured source gives the stepped-into file the keyboard": 150, + "a learner's stop read behind a Codebook run's frame that the editor shows before its focus pass hands its paused file the keyboard": 127, + "a live run that the learner resumes by hand hands the keyboard to the paused file": 110, + "a new main editor group cannot inherit the separate chat command from the previous layout receipt": 142, + "a newly displayed capture retains its pending chat return before its source identity is published": 163, + "a pause whose stacks the adapter declares invalid gives the paused file the keyboard again: captured source keeps the keyboard while App stays visible": 182, + "a refresh the adapter makes after a palette command gives the paused file the keyboard once": 115, + "a replayed recording never moves the keyboard into a recorded file": 379, + "a second frame of the same stop does not hand the keyboard over again": 113, + "a selection that a command moves in a selected frame's file is no sign of the learner: captured-source refresh leaves the keyboard in the Call Stack view": 139, + "a server stop read after the editor reported the browser's thread gives the paused file the keyboard however late its frame arrives: captured source takes the keyboard while App remains visible": 152, + "a server stop read behind the frame of a session the reader does not hear counts as shown by its own handling however late its frame arrives: the captured source takes the keyboard while App remains visible": 175, + "a server stop read while the browser session is paused again is not shown by its own handling: a frame of it that arrives 300 ms later leaves the keyboard in the Call Stack view, and no notice is told": 148, + "a server stop that Codebook's own continue caused leaves the keyboard in the chat when the editor's focus pass opens its file": 138, + "a server stop that the editor shows 800 ms after the browser session went on leaves the keyboard where the learner has it: nothing is shown with the keyboard and no notice is told": 157, + "a single click on the frame of a learner's stop kept behind a Codebook run's paused frame gives no file the keyboard when its frame arrives before the file": 115, + "a single click on the frame of a learner's stop kept behind a Codebook run's paused frame leaves the keyboard in the Call Stack view": 157, + "a step within the paused file that the learner starts from a view gives the paused file the keyboard when the editor reports the stop": 76, + "a stop of a learner's own debug session that the editor shows hands its paused file the keyboard once": 64, + "a stop that Codebook's own continue causes leaves the keyboard in the chat input": 131, + "a stop that the run resumes before the editor showed it still gives the paused file the keyboard when its frame arrives right after: captured source keeps the keyboard while App stays visible": 150, + "an explicit false debug.focusEditorOnBreak leaves the editor's own keyboard handling": 116, + "an invalidated stack after a learner's stop with preserveFocusHint went on is noted as a stop that does not keep the focus, so the editor's handling of it hands its paused file the keyboard": 75, + "an invalidated stack in Cursor of a learner's session whose first stopped thread has preserveFocusHint and whose second has none arms no hand-over, so the learner's click on the second thread's frame leaves the keyboard in the Call Stack view, as Cursor handles only its oldest stored stop again": 68, + "an invalidated stack in VS Code of a learner's session whose first stopped thread has no preserveFocusHint and whose second has it hands the first thread's paused file the keyboard, as VS Code handles every stored stop again": 89, + "an invalidated stack of a learner's stop whose adapter asked to keep the focus arms no keyboard hand-over, so the editor's later focus pass leaves the keyboard in the Call Stack view": 78, + "an invalidated stack of a learner's stop with preserveFocusHint after a refused step arms no keyboard hand-over, so the editor's later focus pass leaves the keyboard in the Call Stack view": 88, + "an invalidated stack of a learner's stop with preserveFocusHint after another thread went on arms no keyboard hand-over, so the editor's later focus pass leaves the keyboard in the Call Stack view": 88, + "an owned Node test run's stop keeps the keyboard where Codebook left it": 130, + "at a stop with debug.focusEditorOnBreak off, a learner who clicks into the paused file has the keyboard in that file: captured source keeps the keyboard while App stays visible and Codebook says so": 147, + "at a stop with debug.focusEditorOnBreak off, a learner who leaves the keyboard in the view keeps it there: captured source comes without the keyboard and nothing is told": 150, + "captured source capacity preserves every pinned view and recovers after an older view is unpinned": 296, + "explicit Source in another live run reuses its unpinned native view without accumulating old live tabs": 411, + "the editor's focus pass 200 ms after a stop whose adapter asked to keep the focus gets no keyboard from Codebook": 122, + "the editor's focus pass to a learner's stop whose adapter asked to keep the focus gets no keyboard from Codebook": 178, + "the next captured source does not infer source keyboard ownership without a separate editor part": 281, + "the next captured source does not update or commit a live source after Close during native document I/O": 291, + "the next captured source keeps a pinned native projection immutable when the next captured file arrives": 274, + "the next captured source keeps a projection pinned during native document I/O immutable and offers Retry": 245, + "the next captured source keeps the learner source keyboard after another frame with native focus disabled": 359, + "the next captured source leaves an unreported native view choice alone after the learner left captured source": 248, + "the next captured source leaves the keyboard in chat when the learner returned before the new frame": 313, + "the next captured source takes no keyboard from another window after a manual source choice": 253, + "the next captured source waits for delayed native content delivery before the new captured moment becomes ready": 309, + "the paused file of a learner's stop gets the keyboard when the editor opens it, before the stop's frame is reported": 71, + "the paused file of a stop kept behind a Codebook run's paused frame gets no keyboard when the learner opens it from the Explorer": 120, + "the reader follows a debug session only while it lives: an ended session is no longer followed, and one that starts again under the same id is followed again": 82, + "the reader's own source activation is no sign of learner work after the keyboard returns to the Call Stack view": 132 } }, "studyWorkspaceEntry.test.js": { - "totalMs": 18837, + "totalMs": 18844, "tests": { - "Close during Live preparation keeps its keyboard settlement without an obsolete return to the separate chat": 82, - "Close during application registration cannot reserve panes after the late native tab appears": 126, - "Close releases the owned App while its preparation waits for native chat command discovery": 129, - "Close while Live return waits for a Node preview leaves the closed reader revision unchanged": 181, - "Live return waiting for the native command catalog preserves Close": 77, - "Live return waiting for the native command catalog preserves a new source choice": 89, - "Live return waiting for the native command catalog preserves a same-source selection": 109, - "Live return waiting for the native command catalog preserves another window": 78, - "MCP-first App preparation reserves its own locked group and preserves both learner groups": 118, - "MCP-first App preparation reserves its own locked group and preserves both learner groups across native wrapper replacement": 117, - "Wiki entry from a retained Study keeps Context focus when the native primary webview emits a late focus event": 65, - "Wiki entry from focused chat preserves its separate pane when its layout read reports a stale matching main grid": 78, - "a Learning Outline click after an extension-host restart closes the leftover captured-source tab of an earlier session": 76, + "Close during Live preparation keeps its keyboard settlement without an obsolete return to the separate chat": 96, + "Close during application registration cannot reserve panes after the late native tab appears": 160, + "Close releases the owned App while its preparation waits for native chat command discovery": 153, + "Close while Live return waits for a Node preview leaves the closed reader revision unchanged": 171, + "Live return waiting for the native command catalog preserves Close": 92, + "Live return waiting for the native command catalog preserves a new source choice": 83, + "Live return waiting for the native command catalog preserves a same-source selection": 153, + "Live return waiting for the native command catalog preserves another window": 93, + "MCP-first App preparation reserves its own locked group and preserves both learner groups": 145, + "MCP-first App preparation reserves its own locked group and preserves both learner groups across native wrapper replacement": 91, + "Wiki entry from a retained Study keeps Context focus when the native primary webview emits a late focus event": 74, + "Wiki entry from focused chat preserves its separate pane when its layout read reports a stale matching main grid": 72, + "a Learning Outline click after an extension-host restart closes the leftover captured-source tab of an earlier session": 72, "a Learning Outline click after an extension-host restart closes the old host’s dead Repository Wiki pane": 81, - "a Learning Outline click after an extension-host restart closes the old host’s dead panes and opens one Application and one Study pane": 155, - "a Learning Outline click places the panes after closing the dead Application pane removed the first editor group": 95, - "a Learning Outline click with the old host’s dead Study pane focused ends with keyboard focus in the new Study pane": 73, - "a Return Current beside Cursor’s chat whose Focus Agent the editor rejects at the end still answers with its Live arrangement": 97, - "a Return Current during which the learner closes the Study workspace refuses because the named reader lifetime ended, not for a source error": 97, - "a close request the editor rejects does not stop the Study workspace from opening": 85, - "a dead Codebook pane the editor refuses to close does not stop the Study workspace from opening": 69, - "a duplicate Open Study during initialization reports busy while the first entry remains usable": 90, - "a failed cold initialization allows the next explicit Open Study to retry": 102, - "a foreign tab during application registration prevents first Study from adopting the changed layout": 143, - "a learner tab selected while borrowing application primary focus prevents a late Wiki arrangement or focus restoration": 74, - "a learner tab selected while borrowing text primary focus prevents a late Wiki arrangement or focus restoration": 68, - "a learner-adopted App group keeps its document and layout when background reveal is refused and the reader closes": 89, - "a live entry from the Study layout arranges the application above the source when the editor closes the retired Study pane a moment after its disposal": 347, - "a live entry from the three-pane Study layout stays confirmed when the context pane's group closes and the editor replaces every group object": 567, - "a live entry in Cursor stays confirmed when the editor rebuilds the source group as its placeholder source tab closes": 250, - "a native Call Stack click keeps its input and source visible beside the prepared App": 72, - "a native Call Stack navigation-command keeps its input and source visible beside the prepared App": 101, - "a queued Wiki after Study preserves later learner focus before measuring an owned layout": 87, - "a real fourth main pane remains learner-owned even when its tab list is empty and a separate chat part exists": 72, - "a replacement group during application registration prevents first Study from adopting the changed layout": 176, - "a second cold Open Study reports busy without creating Context before the first native reservation completes": 75, - "an Open Study cancelled while it waits for an abandoned first entry leaves with its own cancellation instead of reporting busy": 68, - "an Open Study waiting for an abandoned first entry is refused when a presentation change starts during the wait": 91, - "an Open after a Return to the current run whose run then started and stopped arranges the Study composition with its Study pane again": 210, - "an ambiguous duplicate App tab stays visible and receives no background reveal of the earlier panel": 143, - "an existing App lease is reusable while an unrelated native layout read remains pending": 154, - "an existing three-pane Study can restore its presentation while preserving a separate chat part": 412, - "background refresh cannot open captured source into Application before cold Study reserves its panes": 82, - "cancel during application registration cannot reserve panes after the late native tab appears": 184, + "a Learning Outline click after an extension-host restart closes the old host’s dead panes and opens one Application and one Study pane": 156, + "a Learning Outline click places the panes after closing the dead Application pane removed the first editor group": 84, + "a Learning Outline click with the old host’s dead Study pane focused ends with keyboard focus in the new Study pane": 69, + "a Return Current beside Cursor’s chat whose Focus Agent the editor rejects at the end still answers with its Live arrangement": 120, + "a Return Current during which the learner closes the Study workspace refuses because the named reader lifetime ended, not for a source error": 92, + "a close request the editor rejects does not stop the Study workspace from opening": 92, + "a dead Codebook pane the editor refuses to close does not stop the Study workspace from opening": 74, + "a duplicate Open Study during initialization reports busy while the first entry remains usable": 100, + "a failed cold initialization allows the next explicit Open Study to retry": 81, + "a foreign tab during application registration prevents first Study from adopting the changed layout": 137, + "a learner tab selected while borrowing application primary focus prevents a late Wiki arrangement or focus restoration": 64, + "a learner tab selected while borrowing text primary focus prevents a late Wiki arrangement or focus restoration": 64, + "a learner-adopted App group keeps its document and layout when background reveal is refused and the reader closes": 82, + "a live entry from the Study layout arranges the application above the source when the editor closes the retired Study pane a moment after its disposal": 328, + "a live entry from the three-pane Study layout stays confirmed when the context pane's group closes and the editor replaces every group object": 529, + "a live entry in Cursor stays confirmed when the editor rebuilds the source group as its placeholder source tab closes": 239, + "a native Call Stack click keeps its input and source visible beside the prepared App": 81, + "a native Call Stack navigation-command keeps its input and source visible beside the prepared App": 107, + "a queued Wiki after Study preserves later learner focus before measuring an owned layout": 85, + "a real fourth main pane remains learner-owned even when its tab list is empty and a separate chat part exists": 89, + "a replacement group during application registration prevents first Study from adopting the changed layout": 151, + "a second cold Open Study reports busy without creating Context before the first native reservation completes": 90, + "an Open Study cancelled while it waits for an abandoned first entry leaves with its own cancellation instead of reporting busy": 69, + "an Open Study waiting for an abandoned first entry is refused when a presentation change starts during the wait": 71, + "an Open after a Return to the current run whose run then started and stopped arranges the Study composition with its Study pane again": 192, + "an ambiguous duplicate App tab stays visible and receives no background reveal of the earlier panel": 97, + "an existing App lease is reusable while an unrelated native layout read remains pending": 144, + "an existing three-pane Study can restore its presentation while preserving a separate chat part": 398, + "background refresh cannot open captured source into Application before cold Study reserves its panes": 80, + "cancel during application registration cannot reserve panes after the late native tab appears": 118, "cancelling App preparation after allocation leaves original groups and creates no viewport": 88, - "cancelling App preparation before reservation leaves original groups and creates no viewport": 90, - "chat focus acquired during application registration prevents first Study from arranging either editor part": 150, - "cold Study accepts a verified Wiki group and tab wrapper refresh during layout": 179, - "cold Study accepts a verified Wiki group and tab wrapper refresh during registration": 201, - "cold Study opens from Wiki when the covered background text receipt is cleared": 131, - "cold Study opens from Wiki when the covered background text receipt is cleared before registration": 225, - "cold Study opens from Wiki when the covered background text receipt is cleared during layout": 203, - "cold Study opens from Wiki when the covered background text receipt is retained": 121, - "cold Study rejects closing Wiki and opening a lookalike during layout": 240, - "cold Study rejects closing Wiki and opening a lookalike during registration": 408, - "cold Wiki entry from the focused chat measures and reserves only the main editor grid": 78, - "cold Wiki entry reserves a second main pane without treating the separate chat part as its destination": 104, - "cold Wiki resolves blank primary focus through its real citation while retaining the draft and chat part": 75, - "cold Wiki resolves settings primary focus through its real citation while retaining the draft and chat part": 69, - "cold Wiki retains ordinary text focus without invoking the optional cited-source acquisition": 83, - "cold Wiki scope from the chat leaves the borrowed first group's file the keyboard after unchanged layout measurement": 90, - "cold Wiki scope from the chat leaves the borrowed first group's file the keyboard after unchanged primary focus response": 75, - "cold Wiki scope preserves a newer primary edit during layout measurement": 102, - "cold Wiki scope preserves a newer primary edit during primary focus response": 83, - "cold Wiki scope preserves a newer primary selection during layout measurement": 90, - "cold Wiki scope preserves a newer primary selection during primary focus response": 90, - "cold Wiki-to-Study layout preserves different text when background text clears before registration": 220, - "cold Wiki-to-Study layout preserves different text when background text clears during layout": 182, - "cold Wiki-to-Study layout preserves different webview when background text clears before registration": 191, - "cold Wiki-to-Study layout preserves different webview when background text clears during layout": 168, - "cold Wiki-to-Study layout preserves text roundtrip when background text clears before registration": 199, - "cold Wiki-to-Study layout preserves text roundtrip when background text clears during layout": 312, - "cold Wiki-to-Study layout preserves webview roundtrip when background text clears before registration": 185, - "cold Wiki-to-Study layout preserves webview roundtrip when background text clears during layout": 179, - "cold Wiki-to-Study registration rejects clearing text in a group the new application does not cover": 136, - "different text during cold Wiki-to-Study registration preserves the newer learner choice": 128, + "cancelling App preparation before reservation leaves original groups and creates no viewport": 85, + "chat focus acquired during application registration prevents first Study from arranging either editor part": 191, + "cold Study accepts a verified Wiki group and tab wrapper refresh during layout": 195, + "cold Study accepts a verified Wiki group and tab wrapper refresh during registration": 199, + "cold Study opens from Wiki when the covered background text receipt is cleared": 172, + "cold Study opens from Wiki when the covered background text receipt is cleared before registration": 189, + "cold Study opens from Wiki when the covered background text receipt is cleared during layout": 177, + "cold Study opens from Wiki when the covered background text receipt is retained": 130, + "cold Study rejects closing Wiki and opening a lookalike during layout": 181, + "cold Study rejects closing Wiki and opening a lookalike during registration": 169, + "cold Wiki entry from the focused chat measures and reserves only the main editor grid": 65, + "cold Wiki entry reserves a second main pane without treating the separate chat part as its destination": 112, + "cold Wiki resolves blank primary focus through its real citation while retaining the draft and chat part": 71, + "cold Wiki resolves settings primary focus through its real citation while retaining the draft and chat part": 72, + "cold Wiki retains ordinary text focus without invoking the optional cited-source acquisition": 65, + "cold Wiki scope from the chat leaves the borrowed first group's file the keyboard after unchanged layout measurement": 81, + "cold Wiki scope from the chat leaves the borrowed first group's file the keyboard after unchanged primary focus response": 90, + "cold Wiki scope preserves a newer primary edit during layout measurement": 109, + "cold Wiki scope preserves a newer primary edit during primary focus response": 72, + "cold Wiki scope preserves a newer primary selection during layout measurement": 70, + "cold Wiki scope preserves a newer primary selection during primary focus response": 89, + "cold Wiki-to-Study layout preserves different text when background text clears before registration": 243, + "cold Wiki-to-Study layout preserves different text when background text clears during layout": 233, + "cold Wiki-to-Study layout preserves different webview when background text clears before registration": 165, + "cold Wiki-to-Study layout preserves different webview when background text clears during layout": 184, + "cold Wiki-to-Study layout preserves text roundtrip when background text clears before registration": 175, + "cold Wiki-to-Study layout preserves text roundtrip when background text clears during layout": 183, + "cold Wiki-to-Study layout preserves webview roundtrip when background text clears before registration": 671, + "cold Wiki-to-Study layout preserves webview roundtrip when background text clears during layout": 180, + "cold Wiki-to-Study registration rejects clearing text in a group the new application does not cover": 155, + "different text during cold Wiki-to-Study registration preserves the newer learner choice": 127, "different webview during cold Wiki-to-Study registration preserves the newer learner choice": 124, - "failed App focus grants no cleanup authority over a newly reported group without an observed identity": 72, - "failed cold application creation releases temporary native listeners and preserves learner panes": 77, - "first Study cannot confirm a learner source move that covers Application during final arrangement": 103, - "first Study entry accepts its application tab registering during the initial native layout read": 130, - "first Study entry confirms a visible explanation in the only editor part without a Context focus acknowledgement": 78, - "first Study entry does not resize chat while a new application panel only reports optimistic focus": 132, - "first Study entry from one editor group keeps empty Context separate from the application": 74, - "first Study entry refuses an unfocused explanation when a second editor part makes scope ambiguous": 5093, - "first Study entry reserves all three main panes when a separate chat part already occupies a global column": 112, - "first Study entry waits for its explanation focus before confirming the final native layout": 136, - "live entry waits for retired Study tabs before measurement and measures its final arrangement once": 334, - "live entry waits for retired Study tabs before measurement and measures its final arrangement once, returning the keyboard to chat": 240, - "opening Wiki after Study acquires its citation from a Settings-focused main pane without changing chat or drafts": 73, - "opening a recording after an extension-host restart closes the old host’s dead Application pane and presents the recording in one Application pane": 355, - "opening a recording with the old host’s dead Application pane focused ends with keyboard focus moved to the learning summary": 288, - "presentation preserves a replacement Wiki while its prior background source receipt remains visible": 243, - "starting a run after cold Live reopening preserves the separate chat keyboard without rearranging its prepared panes": 161, - "starting a run after idle Live selection preserves the separate chat keyboard without rearranging its prepared panes": 155, - "text roundtrip during cold Wiki-to-Study registration preserves the newer learner choice": 131, - "webview roundtrip during cold Wiki-to-Study registration preserves the newer learner choice": 118 + "failed App focus grants no cleanup authority over a newly reported group without an observed identity": 87, + "failed cold application creation releases temporary native listeners and preserves learner panes": 106, + "first Study cannot confirm a learner source move that covers Application during final arrangement": 85, + "first Study entry accepts its application tab registering during the initial native layout read": 132, + "first Study entry confirms a visible explanation in the only editor part without a Context focus acknowledgement": 75, + "first Study entry does not resize chat while a new application panel only reports optimistic focus": 121, + "first Study entry from one editor group keeps empty Context separate from the application": 100, + "first Study entry refuses an unfocused explanation when a second editor part makes scope ambiguous": 5086, + "first Study entry reserves all three main panes when a separate chat part already occupies a global column": 87, + "first Study entry waits for its explanation focus before confirming the final native layout": 123, + "live entry waits for retired Study tabs before measurement and measures its final arrangement once": 332, + "live entry waits for retired Study tabs before measurement and measures its final arrangement once, returning the keyboard to chat": 245, + "opening Wiki after Study acquires its citation from a Settings-focused main pane without changing chat or drafts": 89, + "opening a recording after an extension-host restart closes the old host’s dead Application pane and presents the recording in one Application pane": 357, + "opening a recording with the old host’s dead Application pane focused ends with keyboard focus moved to the learning summary": 305, + "presentation preserves a replacement Wiki while its prior background source receipt remains visible": 193, + "starting a run after cold Live reopening preserves the separate chat keyboard without rearranging its prepared panes": 176, + "starting a run after idle Live selection preserves the separate chat keyboard without rearranging its prepared panes": 158, + "text roundtrip during cold Wiki-to-Study registration preserves the newer learner choice": 119, + "webview roundtrip during cold Wiki-to-Study registration preserves the newer learner choice": 136 } }, "studyWorkspaceEntryObstacles.test.js": { - "totalMs": 50733, + "totalMs": 49657, "tests": { - "Close Study Workspace after Enlarge application and then a Read of the application in the live arrangement leaves the learner's two editor groups at the sizes they had before the first of them": 254, - "Close Study Workspace after Enlarge application in the live arrangement leaves the learner's two editor groups at the sizes they had before the Enlarge, and none of them maximized": 232, - "Close Study Workspace after Enlarge application in the replay arrangement leaves the learner's two editor groups at the sizes they had before the Enlarge, and none of them maximized": 407, - "Close Study Workspace after Enlarge application twice in the live arrangement leaves the learner's two editor groups at the sizes they had before the first of them": 273, - "Close Study Workspace after Read App leaves the secondary side bar closed, as it was before the Read": 90, - "Close Study Workspace after Read App shows the secondary side bar the Read hid": 70, - "Close Study Workspace after Read Explanation leaves the secondary side bar closed, as it was before the Read": 100, - "Close Study Workspace after Read Explanation shows the secondary side bar the Read hid": 98, - "Close Study Workspace after Read Source leaves the secondary side bar closed, as it was before the Read": 108, - "Close Study Workspace after Read Source shows the secondary side bar the Read hid": 76, - "Close Study Workspace after a Read during which the learner opened another editor group applies no layout of before the Read: the three groups stay": 146, - "Close Study Workspace after a Read in the live arrangement leaves the learner's two editor groups at the sizes they had before the Read": 136, - "Close Study Workspace after a Read in the live arrangement while Cursor's chat tab has the keyboard applies no layout: the chat's editor part keeps the sizes of its own two groups": 127, - "Close Study Workspace after a Read in the live arrangement whose captured source has a group of its own ends the maximization with Expand before it applies the layout of before the Read, and one group of the learner is left": 284, - "Close Study Workspace after a Read in the replay arrangement leaves the learner's two editor groups at the sizes they had before the Read": 306, - "Close Study Workspace after a Read of the application and then Enlarge application in the live arrangement leaves the learner's two editor groups at the sizes they had before the first of them": 136, - "Close Study Workspace after a Read of the application and then of the captured source in the live arrangement leaves the learner's two editor groups at the sizes they had before the first Read": 132, - "Close Study Workspace after a Read of the explanation and then Enlarge application in the three-pane Study workspace leaves the columns at the widths they had before the Read": 189, - "Close Study Workspace after a Read of the explanation in an editor that keeps emptied groups leaves the three-pane columns at the widths they had before the Read": 74, - "Close Study Workspace after a Read whose secondary side bar could not be measured ends the maximization with Expand before it measures the editor area, and shows both side bars again": 233, - "Close Study Workspace after the learner opened another editor group during the session applies no layout of before the Open, and the group stays": 238, - "Close Study Workspace applies no original layout and keeps all three learner groups when a captured two-group layout reply waits while the third group is opened": 77, - "Close Study Workspace during a Read leaves the learner's editor groups at the sizes they had before the Read: the maximization ends as the panes' groups go, and no command that resizes a group is run": 240, - "Close Study Workspace ends the maximized editor group that a Read of a pane left": 74, - "Close Study Workspace in an editor that keeps emptied groups retires the group Codebook created for the Study pane and gives the learner’s two groups the layout they had before the Open": 81, - "Close Study Workspace keeps a third learner group whose model update was queued by the completed group comparison": 66, - "Close Study Workspace made while Cursor's chat tab has the keyboard applies no layout of before the Open: the chat's editor part keeps the sizes of its own two groups": 237, - "Close after a Living book Open beside no chat part leaves no group Codebook created, in an editor that keeps emptied groups": 92, - "Close after a Living book Open beside no chat part leaves no group Codebook created, in an editor that removes emptied groups": 73, - "Close after a Living book Open that took the MCP-first Application group forgets its record when the editor removes that group with the Context’s tab": 78, - "Close after a Living book Open that took the MCP-first Application group forgets its record, so a later empty group at column 1 stays at the next window’s cold select": 328, - "Close after a Living book Open that took the MCP-first Application group retires every empty group Codebook created and forgets the record, in an editor that keeps emptied groups": 76, - "Close forgets the recorded Application group, so a later empty group at column 1 stays at the next window’s cold select": 331, - "Close of a Study whose Context holds a group Codebook created gives back exactly the learner’s group, in an editor that keeps emptied groups": 101, - "Close while recorded entry waits for its work window prevents later App creation": 220, - "Enlarge application in the live arrangement that the editor refuses after its Expand ran leaves the learner's editor groups at the sizes they had before": 231, - "Open Study Workspace and Close Study Workspace from the learner's two groups one above the other in the proportion 7 to 3, with Enlarge application between, leave the two groups as they stood before the Open": 325, - "Open Study Workspace and Close Study Workspace from the learner's two groups one above the other in the proportion 7 to 3, with a Read of the application between, leave the two groups as they stood before the Open": 241, - "Open Study Workspace and Close Study Workspace from the learner's two groups one above the other in the proportion 7 to 3, with nothing between, leave the two groups as they stood before the Open": 241, - "Open Study Workspace and Close Study Workspace from the learner's two groups side by side of 785 and 336 px, with Enlarge application between, leave the two groups as they stood before the Open": 335, - "Open Study Workspace and Close Study Workspace from the learner's two groups side by side of 785 and 336 px, with a Read of the application between, leave the two groups as they stood before the Open": 224, - "Open Study Workspace and Close Study Workspace from the learner's two groups side by side of 785 and 336 px, with nothing between, leave the two groups as they stood before the Open": 231, - "Open Study Workspace and Close Study Workspace from the learner's two rows of equal height apply no layout at the Close: the rows are as before already": 235, - "Open Study Workspace and Close Study Workspace from the learner's two rows, the second of them empty, leave two rows of the sizes of before, the second empty again": 485, - "Open Study Workspace completes while VS Code retains the original text-editor receipt in the background group": 95, - "Open Study Workspace completes while VS Code retains the original text-editor receipt in the covered source group": 86, - "Open Study Workspace from the learner's two groups side by side ends in the confirmed three-pane split in Cursor, with no pane maximized and no side bar hidden": 155, - "Open Study Workspace from the learner's two groups side by side ends in the confirmed three-pane split in VS Code, with no pane maximized and no side bar hidden": 123, - "Open Study Workspace in a window too narrow for the split applies the layout in measured pixels once for each of its two arrangements and still ends in the readable explanation": 1716, - "Open Study Workspace made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 235, - "Open Study Workspace made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, in an editor that keeps its tab group objects": 228, - "Open Study Workspace made while Cursor's chat holds the keyboard and the editor names the chat's group arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 315, - "Open Study Workspace refused while Cursor's chat holds the keyboard opens no pane and leaves the keyboard focus where it was": 965, - "Open Study Workspace refuses a text-editor receipt whose source URI changes during Application registration": 84, - "Open Study Workspace refuses a text-editor receipt whose source column changes during Application registration": 701, - "Open Study Workspace refuses an unchanged text-editor receipt without an original column identity": 699, - "Open replay clicked while another window has the desktop focus opens the recording once the work window gains focus": 555, - "Open replay in Cursor beside a foreign preview tab that keeps the main editor from reporting focus names that tab and how to clear it": 5292, - "Open replay made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 393, - "Open replay made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, in an editor that keeps its tab group objects": 357, - "Open replay made while Cursor's chat holds the keyboard and the editor names the chat's group arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 459, - "Open replay refused for the desktop focus tells the learner in an editor notification which window to click": 1462, - "Open replay refused while Cursor's chat holds the keyboard opens no pane and leaves the keyboard focus where it was": 911, - "Open replay that presents the recording shows no error notification": 368, - "Open replay while another window keeps the desktop focus is refused after ten seconds with the window to click and the control to choose again": 1453, - "Open replay with the learner's file in front of the live Application pane opens the recording at the first click": 245, - "Restore after Read App leaves the secondary side bar closed, as it was before the Read": 182, - "Restore after Read App shows the secondary side bar the Read hid": 174, - "Restore after Read Explanation leaves the secondary side bar closed, as it was before the Read": 84, - "Restore after Read Explanation shows the secondary side bar the Read hid": 83, - "Restore after Read Source leaves the secondary side bar closed, as it was before the Read": 179, - "Restore after Read Source shows the secondary side bar the Read hid": 218, - "Restore beside a kept image tab leaves the enlarged Study pane and names the tab that keeps the panes from being arranged": 73, - "Return to the current pause from a saved item puts the Application in its own group at the first click": 165, - "a Living book Open that gives the MCP-first Application group to the Study Context keeps that group’s record": 81, - "a Read in the live arrangement that the editor refuses after its Expand ran leaves the learner's editor groups at the sizes they had before": 162, - "a Read refused while the reader measured the side bars leaves the primary side bar open and no maximized group": 79, - "a Restore after Enlarge application in the live arrangement beside a later group of the learner's gives every group the size it had before the Enlarge, also where it arranges nothing": 245, - "a Restore after Enlarge application that arranges nothing applies no layout once the learner changed the focus during its layout read, and the Close afterwards gives the learner's groups the sizes they had before the Enlarge": 248, - "a Restore after a Read in the live arrangement beside a later group of the learner's gives every group the size it had before the Read, also where it arranges nothing": 141, - "a Restore after a Read of the Application pane runs no command and no reveal that gives another pane the keyboard: the Application pane keeps it in an editor that moves none by itself": 66, - "a Restore after a Read of the Explanation pane runs no command and no reveal that gives another pane the keyboard: the Explanation pane keeps it in an editor that moves none by itself": 75, - "a Restore after a Read of the application beside a fourth group of the learner's gives every group the width it had before the Read, also where it arranges nothing": 174, - "a Restore after a Read of the captured source runs no command and no reveal that gives another pane the keyboard: the captured source keeps it in an editor that moves none by itself": 79, - "a Restore after a Read whose layout read failed once the primary side bar was hidden for the measurement shows the primary side bar again": 75, - "a Restore after the learner opened the primary side bar during a Read shows the bars the Read hid and keeps the primary one open, with the secondary side bar closed before the Read": 98, - "a Restore after the learner opened the primary side bar during a Read shows the bars the Read hid and keeps the primary one open, with the secondary side bar open before the Read": 70, - "a Restore after the learner widened the window during a Read shows the side bars as they were before the Read and opens no secondary side bar": 66, - "a Restore of a Read in the live arrangement that the learner's change of focus stops applies no layout, and the Close afterwards gives the learner's groups the sizes they had before the Read": 460, - "a Restore that cannot confirm its layout leaves the learner’s groups as they were": 314, - "a Restore that ends a Read brings back the side bars the Read hid and confirms the three panes between them": 98, - "a Restore with no confirmed layout for the window’s groups refuses the arrangement and leaves every group’s tabs": 285, - "a Return records the Application group it claimed for the window after a reload": 100, - "a Return that retires the Study Context’s group taken from the MCP-first Application forgets that group’s record although the editor refuses the new Application group": 74, - "a Return that retires the Study’s own Context group keeps the record of the Application group the Study still holds": 101, - "a Study Open without an Application reservation records the Source and Context groups it created at the layout it confirmed": 96, - "a Study select that gives the Context a group of its own records the Application’s group and the Context’s group at the layout it confirmed": 86, - "a cancelled Application preparation that already recorded its group forgets that record as it retires the group": 108, - "a cancelled Application preparation that already recorded its group forgets that record when the editor removes the group with the pane’s tab": 132, - "a cancelled Application preparation whose claimed group the editor refuses to close reports its cancellation and keeps the record of that group": 81, - "a cold Study open after a reload whose empty leftover group the editor refuses to close leaves the keyboard on the page the learner opened in that group while the close was pending": 63, - "a cold Study open after a reload whose leftover group comes to show its restored captured source while the close is pending, and is refused the close, gives the learner’s file its keyboard back": 67, - "a cold Study open after a reload whose leftover group loses its restored captured source while the close is pending, and is refused the close, gives the learner’s file its keyboard back": 65, - "a cold Study open after a reload whose leftover group the editor refuses to close gives the learner’s file its keyboard back before the refusal": 67, - "a cold Study open after a reload whose leftover group the editor refuses to close gives the learner’s file its keyboard back when a page opened in a new group beside while the close was pending": 63, - "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard in the captured source the learner selected in that group while the close was pending": 66, - "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard in the captured source the learner selected in that group while the editor still reported the one in front before": 66, - "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard in the file the learner clicked into while the close was pending": 64, - "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard on the page the learner focused in another group while the close was pending": 66, + "Close Study Workspace after Enlarge application and then a Read of the application in the live arrangement leaves the learner's two editor groups at the sizes they had before the first of them": 231, + "Close Study Workspace after Enlarge application in the live arrangement leaves the learner's two editor groups at the sizes they had before the Enlarge, and none of them maximized": 250, + "Close Study Workspace after Enlarge application in the replay arrangement leaves the learner's two editor groups at the sizes they had before the Enlarge, and none of them maximized": 374, + "Close Study Workspace after Enlarge application twice in the live arrangement leaves the learner's two editor groups at the sizes they had before the first of them": 250, + "Close Study Workspace after Read App leaves the secondary side bar closed, as it was before the Read": 115, + "Close Study Workspace after Read App shows the secondary side bar the Read hid": 86, + "Close Study Workspace after Read Explanation leaves the secondary side bar closed, as it was before the Read": 87, + "Close Study Workspace after Read Explanation shows the secondary side bar the Read hid": 77, + "Close Study Workspace after Read Source leaves the secondary side bar closed, as it was before the Read": 98, + "Close Study Workspace after Read Source shows the secondary side bar the Read hid": 79, + "Close Study Workspace after a Read during which the learner opened another editor group applies no layout of before the Read: the three groups stay": 168, + "Close Study Workspace after a Read in the live arrangement leaves the learner's two editor groups at the sizes they had before the Read": 125, + "Close Study Workspace after a Read in the live arrangement while Cursor's chat tab has the keyboard applies no layout: the chat's editor part keeps the sizes of its own two groups": 129, + "Close Study Workspace after a Read in the live arrangement whose captured source has a group of its own ends the maximization with Expand before it applies the layout of before the Read, and one group of the learner is left": 290, + "Close Study Workspace after a Read in the replay arrangement leaves the learner's two editor groups at the sizes they had before the Read": 339, + "Close Study Workspace after a Read of the application and then Enlarge application in the live arrangement leaves the learner's two editor groups at the sizes they had before the first of them": 127, + "Close Study Workspace after a Read of the application and then of the captured source in the live arrangement leaves the learner's two editor groups at the sizes they had before the first Read": 124, + "Close Study Workspace after a Read of the explanation and then Enlarge application in the three-pane Study workspace leaves the columns at the widths they had before the Read": 188, + "Close Study Workspace after a Read of the explanation in an editor that keeps emptied groups leaves the three-pane columns at the widths they had before the Read": 62, + "Close Study Workspace after a Read whose secondary side bar could not be measured ends the maximization with Expand before it measures the editor area, and shows both side bars again": 235, + "Close Study Workspace after the learner opened another editor group during the session applies no layout of before the Open, and the group stays": 221, + "Close Study Workspace applies no original layout and keeps all three learner groups when a captured two-group layout reply waits while the third group is opened": 90, + "Close Study Workspace during a Read leaves the learner's editor groups at the sizes they had before the Read: the maximization ends as the panes' groups go, and no command that resizes a group is run": 228, + "Close Study Workspace ends the maximized editor group that a Read of a pane left": 73, + "Close Study Workspace in an editor that keeps emptied groups retires the group Codebook created for the Study pane and gives the learner’s two groups the layout they had before the Open": 72, + "Close Study Workspace keeps a third learner group whose model update was queued by the completed group comparison": 87, + "Close Study Workspace made while Cursor's chat tab has the keyboard applies no layout of before the Open: the chat's editor part keeps the sizes of its own two groups": 228, + "Close after a Living book Open beside no chat part leaves no group Codebook created, in an editor that keeps emptied groups": 63, + "Close after a Living book Open beside no chat part leaves no group Codebook created, in an editor that removes emptied groups": 65, + "Close after a Living book Open that took the MCP-first Application group forgets its record when the editor removes that group with the Context’s tab": 98, + "Close after a Living book Open that took the MCP-first Application group forgets its record, so a later empty group at column 1 stays at the next window’s cold select": 327, + "Close after a Living book Open that took the MCP-first Application group retires every empty group Codebook created and forgets the record, in an editor that keeps emptied groups": 72, + "Close forgets the recorded Application group, so a later empty group at column 1 stays at the next window’s cold select": 286, + "Close of a Study whose Context holds a group Codebook created gives back exactly the learner’s group, in an editor that keeps emptied groups": 81, + "Close while recorded entry waits for its work window prevents later App creation": 224, + "Enlarge application in the live arrangement that the editor refuses after its Expand ran leaves the learner's editor groups at the sizes they had before": 210, + "Open Study Workspace and Close Study Workspace from the learner's two groups one above the other in the proportion 7 to 3, with Enlarge application between, leave the two groups as they stood before the Open": 322, + "Open Study Workspace and Close Study Workspace from the learner's two groups one above the other in the proportion 7 to 3, with a Read of the application between, leave the two groups as they stood before the Open": 223, + "Open Study Workspace and Close Study Workspace from the learner's two groups one above the other in the proportion 7 to 3, with nothing between, leave the two groups as they stood before the Open": 235, + "Open Study Workspace and Close Study Workspace from the learner's two groups side by side of 785 and 336 px, with Enlarge application between, leave the two groups as they stood before the Open": 320, + "Open Study Workspace and Close Study Workspace from the learner's two groups side by side of 785 and 336 px, with a Read of the application between, leave the two groups as they stood before the Open": 213, + "Open Study Workspace and Close Study Workspace from the learner's two groups side by side of 785 and 336 px, with nothing between, leave the two groups as they stood before the Open": 246, + "Open Study Workspace and Close Study Workspace from the learner's two rows of equal height apply no layout at the Close: the rows are as before already": 224, + "Open Study Workspace and Close Study Workspace from the learner's two rows, the second of them empty, leave two rows of the sizes of before, the second empty again": 587, + "Open Study Workspace completes while VS Code retains the original text-editor receipt in the background group": 87, + "Open Study Workspace completes while VS Code retains the original text-editor receipt in the covered source group": 70, + "Open Study Workspace from the learner's two groups side by side ends in the confirmed three-pane split in Cursor, with no pane maximized and no side bar hidden": 128, + "Open Study Workspace from the learner's two groups side by side ends in the confirmed three-pane split in VS Code, with no pane maximized and no side bar hidden": 120, + "Open Study Workspace in a window too narrow for the split applies the layout in measured pixels once for each of its two arrangements and still ends in the readable explanation": 1711, + "Open Study Workspace made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 196, + "Open Study Workspace made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, in an editor that keeps its tab group objects": 200, + "Open Study Workspace made while Cursor's chat holds the keyboard and the editor names the chat's group arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 236, + "Open Study Workspace refused while Cursor's chat holds the keyboard opens no pane and leaves the keyboard focus where it was": 743, + "Open Study Workspace refuses a text-editor receipt whose source URI changes during Application registration": 58, + "Open Study Workspace refuses a text-editor receipt whose source column changes during Application registration": 635, + "Open Study Workspace refuses an unchanged text-editor receipt without an original column identity": 631, + "Open replay clicked while another window has the desktop focus opens the recording once the work window gains focus": 551, + "Open replay in Cursor beside a foreign preview tab that keeps the main editor from reporting focus names that tab and how to clear it": 5237, + "Open replay made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 333, + "Open replay made while Cursor's chat holds the keyboard and the editor names a text tab without an active text editor arranges the panes and gives the chat its focus back, in an editor that keeps its tab group objects": 307, + "Open replay made while Cursor's chat holds the keyboard and the editor names the chat's group arranges the panes and gives the chat its focus back, also when the editor replaces every tab group object with each tab change": 355, + "Open replay refused for the desktop focus tells the learner in an editor notification which window to click": 1331, + "Open replay refused while Cursor's chat holds the keyboard opens no pane and leaves the keyboard focus where it was": 1417, + "Open replay that presents the recording shows no error notification": 283, + "Open replay while another window keeps the desktop focus is refused after ten seconds with the window to click and the control to choose again": 1335, + "Open replay with the learner's file in front of the live Application pane opens the recording at the first click": 292, + "Restore after Read App leaves the secondary side bar closed, as it was before the Read": 188, + "Restore after Read App shows the secondary side bar the Read hid": 172, + "Restore after Read Explanation leaves the secondary side bar closed, as it was before the Read": 77, + "Restore after Read Explanation shows the secondary side bar the Read hid": 68, + "Restore after Read Source leaves the secondary side bar closed, as it was before the Read": 220, + "Restore after Read Source shows the secondary side bar the Read hid": 192, + "Restore beside a kept image tab leaves the enlarged Study pane and names the tab that keeps the panes from being arranged": 163, + "Return to the current pause from a saved item puts the Application in its own group at the first click": 156, + "a Living book Open that gives the MCP-first Application group to the Study Context keeps that group’s record": 62, + "a Read in the live arrangement that the editor refuses after its Expand ran leaves the learner's editor groups at the sizes they had before": 117, + "a Read refused while the reader measured the side bars leaves the primary side bar open and no maximized group": 102, + "a Restore after Enlarge application in the live arrangement beside a later group of the learner's gives every group the size it had before the Enlarge, also where it arranges nothing": 225, + "a Restore after Enlarge application that arranges nothing applies no layout once the learner changed the focus during its layout read, and the Close afterwards gives the learner's groups the sizes they had before the Enlarge": 223, + "a Restore after a Read in the live arrangement beside a later group of the learner's gives every group the size it had before the Read, also where it arranges nothing": 111, + "a Restore after a Read of the Application pane runs no command and no reveal that gives another pane the keyboard: the Application pane keeps it in an editor that moves none by itself": 75, + "a Restore after a Read of the Explanation pane runs no command and no reveal that gives another pane the keyboard: the Explanation pane keeps it in an editor that moves none by itself": 69, + "a Restore after a Read of the application beside a fourth group of the learner's gives every group the width it had before the Read, also where it arranges nothing": 164, + "a Restore after a Read of the captured source runs no command and no reveal that gives another pane the keyboard: the captured source keeps it in an editor that moves none by itself": 66, + "a Restore after a Read whose layout read failed once the primary side bar was hidden for the measurement shows the primary side bar again": 92, + "a Restore after the learner opened the primary side bar during a Read shows the bars the Read hid and keeps the primary one open, with the secondary side bar closed before the Read": 76, + "a Restore after the learner opened the primary side bar during a Read shows the bars the Read hid and keeps the primary one open, with the secondary side bar open before the Read": 73, + "a Restore after the learner widened the window during a Read shows the side bars as they were before the Read and opens no secondary side bar": 73, + "a Restore of a Read in the live arrangement that the learner's change of focus stops applies no layout, and the Close afterwards gives the learner's groups the sizes they had before the Read": 442, + "a Restore that cannot confirm its layout leaves the learner’s groups as they were": 287, + "a Restore that ends a Read brings back the side bars the Read hid and confirms the three panes between them": 103, + "a Restore with no confirmed layout for the window’s groups refuses the arrangement and leaves every group’s tabs": 294, + "a Return records the Application group it claimed for the window after a reload": 107, + "a Return that retires the Study Context’s group taken from the MCP-first Application forgets that group’s record although the editor refuses the new Application group": 69, + "a Return that retires the Study’s own Context group keeps the record of the Application group the Study still holds": 95, + "a Study Open without an Application reservation records the Source and Context groups it created at the layout it confirmed": 91, + "a Study select that gives the Context a group of its own records the Application’s group and the Context’s group at the layout it confirmed": 81, + "a cancelled Application preparation that already recorded its group forgets that record as it retires the group": 68, + "a cancelled Application preparation that already recorded its group forgets that record when the editor removes the group with the pane’s tab": 142, + "a cancelled Application preparation whose claimed group the editor refuses to close reports its cancellation and keeps the record of that group": 72, + "a cold Study open after a reload whose empty leftover group the editor refuses to close leaves the keyboard on the page the learner opened in that group while the close was pending": 62, + "a cold Study open after a reload whose leftover group comes to show its restored captured source while the close is pending, and is refused the close, gives the learner’s file its keyboard back": 68, + "a cold Study open after a reload whose leftover group loses its restored captured source while the close is pending, and is refused the close, gives the learner’s file its keyboard back": 62, + "a cold Study open after a reload whose leftover group the editor refuses to close gives the learner’s file its keyboard back before the refusal": 62, + "a cold Study open after a reload whose leftover group the editor refuses to close gives the learner’s file its keyboard back when a page opened in a new group beside while the close was pending": 65, + "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard in the captured source the learner selected in that group while the close was pending": 63, + "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard in the captured source the learner selected in that group while the editor still reported the one in front before": 71, + "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard in the file the learner clicked into while the close was pending": 60, + "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard on the page the learner focused in another group while the close was pending": 67, "a cold Study open after a reload whose leftover group the editor refuses to close leaves the keyboard on the page the learner selected in that group while the close was pending": 66, - "a cold Study open after a reload whose resized grid no longer proves the earlier window’s record gives the learner’s file its keyboard back right after the proof": 67, + "a cold Study open after a reload whose resized grid no longer proves the earlier window’s record gives the learner’s file its keyboard back right after the proof": 66, "a cold Study open that is cancelled while the leftover proof focuses the earlier window’s group gives the learner’s file nothing back": 64, - "a cold Study select after a reload leaves the recorded leftovers untouched when the learner resized the groups after the last confirmed layout": 309, - "a cold Study select after a reload retires the recorded Source group with its restored captured source and the empty Context group, in an editor that keeps emptied groups": 394, - "a cold Study select after a reload retires the recorded Source group with its restored captured source and the empty Context group, in an editor that removes emptied groups": 481, - "a cold Study select after a reload retires the recorded empty Application group and keeps the recorded Context group that holds a learner’s file": 289, - "a cold Study select after a reload with the restored captured source focused retires every recorded leftover before that tab closes, and Close gives the learner’s group back": 475, - "a cold Study select after a window reload retires the empty Application group although a Return before the reload retired the Study’s Context group": 306, - "a cold Study select after a window reload retires the empty Application group and the Study Context’s empty created group the earlier window recorded": 312, - "a cold Study select after a window reload retires the empty Application group the earlier window recorded": 307, - "a cold Study select after an editor restart retires the empty Application group a version-1 record of a 0.2.30 candidate proves": 288, - "a cold Study select from the chat beside a dead pane in a recorded group retires the recorded leftovers first and gives the chat its keyboard back": 353, - "a presentation selection refused for a learner preview names that tab, its group and how to clear it": 196, - "a reloaded window's leftover empty Application group does not refuse Return to the current pause": 315, - "a run’s Application preparation refused by its focus return after it waited for the layout queue leaves the Application pane the learner’s Open made meanwhile": 120, - "a selection and a Restore made beside a focused kept image tab in editor group 1 arrange the Study panes without enlarging the Study pane": 524, - "a selection and a Restore made beside a focused kept image tab in editor group 2 arrange the Study panes without enlarging the Study pane": 496, - "a selection and a Restore made beside a focused kept image tab in editor group 3 arrange the Study panes without enlarging the Study pane": 511, - "a side bar the learner had closed before the Read stays closed, with the primary side bar closed and the secondary one closed": 80, - "a side bar the learner had closed before the Read stays closed, with the primary side bar closed and the secondary one open": 83, - "a side bar the learner had closed before the Read stays closed, with the primary side bar open and the secondary one closed": 95, - "after a cold Study select retired both recorded leftovers of a reload, Restore confirms the Study and Close gives back exactly the learner’s group": 522, - "an agent’s Study selection during a live run whose Application pane the learner closed gives no file the keyboard and says once that the new Application group has it": 523, - "an agent’s Study selection that ends a Read while the Study pane reports its keyboard gives it back to the pane without a word": 79, - "an agent’s Study selection that ends a Read while the learner types in a view outside the editor says once that the pane being read has the keyboard": 93, - "an agent’s cold Study select in VS Code that retires the earlier window’s leftover group after the chat editor tab’s group gives that chat its keyboard back at its unchanged column and says once that closing the leftover moved it": 423, - "an agent’s cold Study select in VS Code that retires the earlier window’s leftover group while the chat editor tab has the keyboard gives that chat its keyboard back and says once that closing the leftover moved it, naming no pause": 392, - "an agent’s first run after a reload retires the earlier window’s empty Application group the editor restored as active, leaves the keyboard in the chat view and says once where the keyboard may be": 69, - "an agent’s first run after a reload that must focus the earlier window’s leftover group for its proof gives no file the keyboard and says once that the Application’s group has it": 66, - "an agent’s first run after a reload whose record no longer proves the empty first group is refused at once with that group named, touching nothing": 66, - "an agent’s first run after a reload whose record no longer proves the leftovers places the Application in its own group beside them and unlocks or closes nothing": 64, - "an agent’s first run beside the chat with the learner’s own empty first group is refused at once with that group named, and the group stays": 62, - "an agent’s run that must focus the first editor group to place the Application gives no file the keyboard and says once that the Application’s group has it": 59, - "an agent’s run that prepares the Application while VS Code’s chat editor tab has the keyboard gives that chat tab its keyboard back and tells nothing": 72, - "an agent’s run that prepares the Application while VS Code’s chat editor tab in a floating window has the keyboard gives that chat its keyboard back and says once that a file of the main editor had it for a moment": 71, - "an agent’s run that prepares the Application while a Settings tab is the active tab gives that tab nothing back and says once that the Application’s group has the keyboard": 79, - "an agent’s run that prepares the Application while the chat view has the keyboard leaves the keyboard in the chat, focuses nothing and says once where the keyboard may be": 69, - "an agent’s run that prepares the Application while the learner reads a first-group file without a key press gives that file nothing it cannot prove and says once where the keyboard may be": 71, - "an agent’s run that prepares the Application while the learner types in the first group’s file gives that file the keyboard back": 68, - "an agent’s run whose return of the keyboard to VS Code’s chat editor tab the editor refuses still gets its Application pane in its own group": 78, - "an agent’s source reveal that opens the closed Study workspace gives no learner’s file the keyboard": 132, - "an empty locked group at column 1 that no record proves stays as it is at a cold Study select": 293, - "an entry from the repository fronts the captured source again after an agent’s run reacquired the Application while the learner’s file covered that source": 79, - "closing the Study workspace after a Read brings back the side bars the Read hid": 66, - "closing the Study workspace after the learner narrowed the window during a Read shows both side bars the Read hid": 89, - "in Cursor, a cold Study open from the chat that is cancelled while the leftover proof focuses the earlier window’s group gives the chat nothing back and tells nothing": 63, - "in Cursor, a cold Study open from the chat whose reader closes while the leftover proof focuses the earlier window’s group runs no Focus Agent after the Close and tells nothing": 67, - "in Cursor, a cold Study select after a reload that retired the earlier window’s leftover group still refuses beside a dead pane the editor keeps, though the retirement made every tab object new": 74, - "in Cursor, a selection after a removed group made every tab object new keeps this host’s own Study pane, whose panel reported another column, when a dead Study pane of the same name stands beside it": 74, - "in Cursor, a selection after the learner closed one of their groups still names the earlier host’s dead Study pane the editor kept, though the removal made every tab object new": 70, - "in Cursor, a selection after the learner closed one of their groups still names the earlier host’s dead Study pane, though this host’s own Study pane carries the same view type and title": 63, - "in Cursor, an agent's Return Current after a reload whose record no longer proves the leftover reaches the live run in a group of the Application's own": 540, - "in Cursor, an agent's Return Current after a reload whose record no longer proves the leftover stacks the Application above the source and the learner's other group, and Close gives the learner's groups back stacked": 596, - "in Cursor, an agent's Return Current whose lock reached the learner's group takes that lock off again although another learner group is the active one by then, and Close leaves no group locked": 306, - "in Cursor, an agent's Return Current whose lock reached the new Application group keeps the lock the learner set on their own group that Cursor names afterwards, through Close": 293, - "in Cursor, an agent's Return Current whose lock reaches the learner's group Cursor activated again locks only the Application's own group, and Close leaves no group locked": 317, - "in Cursor, an agent's Return Current whose lock reaches the learner's own locked group Cursor activated again keeps the learner's lock and locks the Application's own group": 297, + "a cold Study select after a reload leaves the recorded leftovers untouched when the learner resized the groups after the last confirmed layout": 319, + "a cold Study select after a reload retires the recorded Source group with its restored captured source and the empty Context group, in an editor that keeps emptied groups": 395, + "a cold Study select after a reload retires the recorded Source group with its restored captured source and the empty Context group, in an editor that removes emptied groups": 468, + "a cold Study select after a reload retires the recorded empty Application group and keeps the recorded Context group that holds a learner’s file": 298, + "a cold Study select after a reload with the restored captured source focused retires every recorded leftover before that tab closes, and Close gives the learner’s group back": 437, + "a cold Study select after a window reload retires the empty Application group although a Return before the reload retired the Study’s Context group": 311, + "a cold Study select after a window reload retires the empty Application group and the Study Context’s empty created group the earlier window recorded": 297, + "a cold Study select after a window reload retires the empty Application group the earlier window recorded": 280, + "a cold Study select after an editor restart retires the empty Application group a version-1 record of a 0.2.30 candidate proves": 312, + "a cold Study select from the chat beside a dead pane in a recorded group retires the recorded leftovers first and gives the chat its keyboard back": 338, + "a presentation selection refused for a learner preview names that tab, its group and how to clear it": 184, + "a reloaded window's leftover empty Application group does not refuse Return to the current pause": 327, + "a run’s Application preparation refused by its focus return after it waited for the layout queue leaves the Application pane the learner’s Open made meanwhile": 116, + "a selection and a Restore made beside a focused kept image tab in editor group 1 arrange the Study panes without enlarging the Study pane": 492, + "a selection and a Restore made beside a focused kept image tab in editor group 2 arrange the Study panes without enlarging the Study pane": 511, + "a selection and a Restore made beside a focused kept image tab in editor group 3 arrange the Study panes without enlarging the Study pane": 485, + "a side bar the learner had closed before the Read stays closed, with the primary side bar closed and the secondary one closed": 63, + "a side bar the learner had closed before the Read stays closed, with the primary side bar closed and the secondary one open": 81, + "a side bar the learner had closed before the Read stays closed, with the primary side bar open and the secondary one closed": 71, + "after a cold Study select retired both recorded leftovers of a reload, Restore confirms the Study and Close gives back exactly the learner’s group": 516, + "an agent’s Study selection during a live run whose Application pane the learner closed gives no file the keyboard and says once that the new Application group has it": 494, + "an agent’s Study selection that ends a Read while the Study pane reports its keyboard gives it back to the pane without a word": 67, + "an agent’s Study selection that ends a Read while the learner types in a view outside the editor says once that the pane being read has the keyboard": 72, + "an agent’s cold Study select in VS Code that retires the earlier window’s leftover group after the chat editor tab’s group gives that chat its keyboard back at its unchanged column and says once that closing the leftover moved it": 384, + "an agent’s cold Study select in VS Code that retires the earlier window’s leftover group while the chat editor tab has the keyboard gives that chat its keyboard back and says once that closing the leftover moved it, naming no pause": 377, + "an agent’s first run after a reload retires the earlier window’s empty Application group the editor restored as active, leaves the keyboard in the chat view and says once where the keyboard may be": 92, + "an agent’s first run after a reload that must focus the earlier window’s leftover group for its proof gives no file the keyboard and says once that the Application’s group has it": 69, + "an agent’s first run after a reload whose record no longer proves the empty first group is refused at once with that group named, touching nothing": 70, + "an agent’s first run after a reload whose record no longer proves the leftovers places the Application in its own group beside them and unlocks or closes nothing": 74, + "an agent’s first run beside the chat with the learner’s own empty first group is refused at once with that group named, and the group stays": 68, + "an agent’s run that must focus the first editor group to place the Application gives no file the keyboard and says once that the Application’s group has it": 74, + "an agent’s run that prepares the Application while VS Code’s chat editor tab has the keyboard gives that chat tab its keyboard back and tells nothing": 73, + "an agent’s run that prepares the Application while VS Code’s chat editor tab in a floating window has the keyboard gives that chat its keyboard back and says once that a file of the main editor had it for a moment": 129, + "an agent’s run that prepares the Application while a Settings tab is the active tab gives that tab nothing back and says once that the Application’s group has the keyboard": 73, + "an agent’s run that prepares the Application while the chat view has the keyboard leaves the keyboard in the chat, focuses nothing and says once where the keyboard may be": 74, + "an agent’s run that prepares the Application while the learner reads a first-group file without a key press gives that file nothing it cannot prove and says once where the keyboard may be": 75, + "an agent’s run that prepares the Application while the learner types in the first group’s file gives that file the keyboard back": 99, + "an agent’s run whose return of the keyboard to VS Code’s chat editor tab the editor refuses still gets its Application pane in its own group": 66, + "an agent’s source reveal that opens the closed Study workspace gives no learner’s file the keyboard": 150, + "an empty locked group at column 1 that no record proves stays as it is at a cold Study select": 275, + "an entry from the repository fronts the captured source again after an agent’s run reacquired the Application while the learner’s file covered that source": 88, + "closing the Study workspace after a Read brings back the side bars the Read hid": 77, + "closing the Study workspace after the learner narrowed the window during a Read shows both side bars the Read hid": 85, + "in Cursor, a cold Study open from the chat that is cancelled while the leftover proof focuses the earlier window’s group gives the chat nothing back and tells nothing": 65, + "in Cursor, a cold Study open from the chat whose reader closes while the leftover proof focuses the earlier window’s group runs no Focus Agent after the Close and tells nothing": 71, + "in Cursor, a cold Study select after a reload that retired the earlier window’s leftover group still refuses beside a dead pane the editor keeps, though the retirement made every tab object new": 94, + "in Cursor, a selection after a removed group made every tab object new keeps this host’s own Study pane, whose panel reported another column, when a dead Study pane of the same name stands beside it": 70, + "in Cursor, a selection after the learner closed one of their groups still names the earlier host’s dead Study pane the editor kept, though the removal made every tab object new": 71, + "in Cursor, a selection after the learner closed one of their groups still names the earlier host’s dead Study pane, though this host’s own Study pane carries the same view type and title": 70, + "in Cursor, an agent's Return Current after a reload whose record no longer proves the leftover reaches the live run in a group of the Application's own": 550, + "in Cursor, an agent's Return Current after a reload whose record no longer proves the leftover stacks the Application above the source and the learner's other group, and Close gives the learner's groups back stacked": 540, + "in Cursor, an agent's Return Current whose lock reached the learner's group takes that lock off again although another learner group is the active one by then, and Close leaves no group locked": 296, + "in Cursor, an agent's Return Current whose lock reached the new Application group keeps the lock the learner set on their own group that Cursor names afterwards, through Close": 290, + "in Cursor, an agent's Return Current whose lock reaches the learner's group Cursor activated again locks only the Application's own group, and Close leaves no group locked": 293, + "in Cursor, an agent's Return Current whose lock reaches the learner's own locked group Cursor activated again keeps the learner's lock and locks the Application's own group": 268, "in Cursor, an agent’s cold Study select from the chat beside a dead pane, whose leftover group the editor refuses to close, gives the chat its keyboard back and says once that Codebook could not close the groups": 61, - "in Cursor, an agent’s cold Study select from the chat beside a dead pane, whose resized grid no longer proves the earlier window’s record, gives the chat its keyboard back saying that no group was closed": 283, - "in Cursor, an agent’s cold Study select from the chat that retires the earlier window’s leftover groups gives the chat its keyboard back and says once that closing the leftovers moved it": 345, - "in Cursor, an agent’s cold Study select from the chat whose leftover group the editor refuses to close gives the chat its keyboard back and says once that Codebook could not close the groups": 64, - "in Cursor, an agent’s first run after a reload whose resized grid no longer proves the earlier window’s record gives the chat its keyboard back saying that no group was closed": 103, - "in Cursor, the first Application preparation of a reloaded window whose chat takes its keyboard late (as in c57-cursor-1f) retires the leftover, stands alone in its own group, and gives the chat its keyboard back": 73, - "in Cursor, the first Application preparation of a reloaded window whose chat takes its keyboard late (as in c57-cursor-1f2) retires the leftover, stands alone in its own group, and gives the chat its keyboard back": 66, - "in Cursor, the first Application preparation of a reloaded window whose leftover group the editor refuses to close gives the chat its keyboard back before the run fails": 83, - "in Cursor, the first Application preparation of a reloaded window whose proof focuses the leftover at column 1 shows no learner file with the keyboard, gives the chat its keyboard back and says once that closing the leftover moved it": 68, - "in VS Code, a group the learner adds while an agent's Return Current waits for the editor's late removal of the emptied leftover refuses the Return as a learner's change": 695, - "in VS Code, a learner's click into their file while an agent's Return Current waits for the editor's late removal of the emptied leftover refuses the Return as a learner's change": 710, - "in VS Code, a learner's tab brought to the front of their group while an agent's Return Current waits for the editor's late removal of the emptied leftover refuses the Return as a learner's change": 712, - "in VS Code, an agent's Return Current after a reload whose record no longer proves the leftover follows the editor's late removal of the leftover the Application's move emptied, reaches the live run stacked, and Close gives the learner's groups back stacked": 706, - "in VS Code, an agent's Return Current after a reload whose record no longer proves the leftover reaches the live run in a group of the Application's own": 539, - "in VS Code, an agent's Return Current after a reload whose record no longer proves the leftover stacks the Application above the source and the learner's other group, and Close gives the learner's groups back stacked": 548, - "recorded App preparation preserves newer source input at Close before allocating its native group": 222, - "recorded App preparation preserves newer source input at caller admission before allocating its native group": 197, + "in Cursor, an agent’s cold Study select from the chat beside a dead pane, whose resized grid no longer proves the earlier window’s record, gives the chat its keyboard back saying that no group was closed": 279, + "in Cursor, an agent’s cold Study select from the chat that retires the earlier window’s leftover groups gives the chat its keyboard back and says once that closing the leftovers moved it": 338, + "in Cursor, an agent’s cold Study select from the chat whose leftover group the editor refuses to close gives the chat its keyboard back and says once that Codebook could not close the groups": 61, + "in Cursor, an agent’s first run after a reload whose resized grid no longer proves the earlier window’s record gives the chat its keyboard back saying that no group was closed": 71, + "in Cursor, the first Application preparation of a reloaded window whose chat takes its keyboard late (as in c57-cursor-1f) retires the leftover, stands alone in its own group, and gives the chat its keyboard back": 71, + "in Cursor, the first Application preparation of a reloaded window whose chat takes its keyboard late (as in c57-cursor-1f2) retires the leftover, stands alone in its own group, and gives the chat its keyboard back": 70, + "in Cursor, the first Application preparation of a reloaded window whose leftover group the editor refuses to close gives the chat its keyboard back before the run fails": 61, + "in Cursor, the first Application preparation of a reloaded window whose proof focuses the leftover at column 1 shows no learner file with the keyboard, gives the chat its keyboard back and says once that closing the leftover moved it": 77, + "in VS Code, a group the learner adds while an agent's Return Current waits for the editor's late removal of the emptied leftover refuses the Return as a learner's change": 705, + "in VS Code, a learner's click into their file while an agent's Return Current waits for the editor's late removal of the emptied leftover refuses the Return as a learner's change": 677, + "in VS Code, a learner's tab brought to the front of their group while an agent's Return Current waits for the editor's late removal of the emptied leftover refuses the Return as a learner's change": 690, + "in VS Code, an agent's Return Current after a reload whose record no longer proves the leftover follows the editor's late removal of the leftover the Application's move emptied, reaches the live run stacked, and Close gives the learner's groups back stacked": 681, + "in VS Code, an agent's Return Current after a reload whose record no longer proves the leftover reaches the live run in a group of the Application's own": 572, + "in VS Code, an agent's Return Current after a reload whose record no longer proves the leftover stacks the Application above the source and the learner's other group, and Close gives the learner's groups back stacked": 549, + "recorded App preparation preserves newer source input at Close before allocating its native group": 236, + "recorded App preparation preserves newer source input at caller admission before allocating its native group": 171, "recorded App preparation preserves newer source input at native response before allocating its native group": 237, - "recorded App preparation preserves newer source input at same-source key before allocating its native group": 233, - "recorded App preparation preserves newer source input at window round trip before allocating its native group": 250, + "recorded App preparation preserves newer source input at same-source key before allocating its native group": 292, + "recorded App preparation preserves newer source input at window round trip before allocating its native group": 275, "the Restore of Enlarge application in the three-pane Study workspace applies one layout, the measured one, and the Close afterwards runs no Expand and applies no layout": 276, - "the end of a Study session applies no layout of before the Open when the learner replaced the file of the second group by another one during the session": 217, - "the end of a Study session applies no layout of before the Open when the reader is disposed and not closed by the learner": 229, - "the first Application preparation of a reloaded window retires the earlier window’s recorded leftovers before it allocates, and the chat keeps its keyboard": 63, - "the first presentation selection keeps a debugger preview of a cited workspace file and arranges the Study without restore": 644, - "the run after an Application preparation that a newer run replaced inside the layout queue prepares a new Application pane in its own group, with nothing left of the disposed one": 68 + "the end of a Study session applies no layout of before the Open when the learner replaced the file of the second group by another one during the session": 224, + "the end of a Study session applies no layout of before the Open when the reader is disposed and not closed by the learner": 218, + "the first Application preparation of a reloaded window retires the earlier window’s recorded leftovers before it allocates, and the chat keeps its keyboard": 80, + "the first presentation selection keeps a debugger preview of a cited workspace file and arranges the Study without restore": 637, + "the run after an Application preparation that a newer run replaced inside the layout queue prepares a new Application pane in its own group, with nothing left of the disposed one": 87 } }, "studyWorkspaceFocus.test.js": { - "totalMs": 22553, + "totalMs": 21983, "tests": { - "Arrange Study Workspace after a Read of the explanation gives the Study pane the keyboard with one reveal and restores the three-pane layout at once when that pane is the active one and its document reports no keyboard": 83, - "Arrange Study Workspace after a Read of the explanation restores the three-pane layout at once when the Study pane already has the keyboard, without revealing that pane again or waiting for its focus report": 68, - "Arrange Study Workspace run from the Application pane says in one sentence that the Explanation pane did not confirm the keyboard within five seconds and what to do, when that pane never reports the focus": 5103, - "Close during cold Wiki scope measurement cannot mutate the main or chat part": 73, - "Enlarge explanation pressed in the Study pane enlarges it at once, without revealing that pane again or waiting for its focus report": 102, - "Focus after a failed run reaches the Application pane without a pane click": 241, - "Living book adopts an MCP-first application into its reserved main pane before confirming the initial layout": 82, - "Living book preserves a learner move of its MCP-first application before the initial Open": 67, - "Living book retry after an accepted reservation is cancelled separates its application from the explanation": 105, - "MCP-first Study opens when its application covers the selected chat-like tab in the same editor group": 82, - "MCP-first Study preserves a newer chat tab choice during application registration": 144, - "MCP-first opaque primary preserves later input at Close without allocating App": 130, - "MCP-first opaque primary preserves later input at caller admission without allocating App": 89, - "MCP-first opaque primary preserves later input at native response without allocating App": 139, - "MCP-first opaque primary preserves later input at window round trip without allocating App": 170, - "Read Application does not maximize after the work window leaves during its webview reveal": 93, - "Read Explanation does not maximize after the work window leaves and returns during cold Open": 92, - "Read Explanation leaves a closed Study and foreign window untouched when unfocused": 70, - "Read Explanation opens Study when the command runs before Open Study Workspace": 95, - "Read Explanation stays readable when opening Study first needs a compact-layout focus": 1730, - "Restore after a failed run confirms the app and source layout without a pane click when the layout receipt was lost": 157, - "Restore after a failed run confirms the app and source layout without a pane click when the workbench resized the split": 157, + "Arrange Study Workspace after a Read of the explanation gives the Study pane the keyboard with one reveal and restores the three-pane layout at once when that pane is the active one and its document reports no keyboard": 76, + "Arrange Study Workspace after a Read of the explanation restores the three-pane layout at once when the Study pane already has the keyboard, without revealing that pane again or waiting for its focus report": 90, + "Arrange Study Workspace run from the Application pane says in one sentence that the Explanation pane did not confirm the keyboard within five seconds and what to do, when that pane never reports the focus": 5075, + "Close during cold Wiki scope measurement cannot mutate the main or chat part": 78, + "Enlarge explanation pressed in the Study pane enlarges it at once, without revealing that pane again or waiting for its focus report": 61, + "Focus after a failed run reaches the Application pane without a pane click": 275, + "Living book adopts an MCP-first application into its reserved main pane before confirming the initial layout": 72, + "Living book preserves a learner move of its MCP-first application before the initial Open": 79, + "Living book retry after an accepted reservation is cancelled separates its application from the explanation": 126, + "MCP-first Study opens when its application covers the selected chat-like tab in the same editor group": 78, + "MCP-first Study preserves a newer chat tab choice during application registration": 119, + "MCP-first opaque primary preserves later input at Close without allocating App": 134, + "MCP-first opaque primary preserves later input at caller admission without allocating App": 70, + "MCP-first opaque primary preserves later input at native response without allocating App": 123, + "MCP-first opaque primary preserves later input at window round trip without allocating App": 133, + "Read Application does not maximize after the work window leaves during its webview reveal": 77, + "Read Explanation does not maximize after the work window leaves and returns during cold Open": 74, + "Read Explanation leaves a closed Study and foreign window untouched when unfocused": 72, + "Read Explanation opens Study when the command runs before Open Study Workspace": 90, + "Read Explanation stays readable when opening Study first needs a compact-layout focus": 1729, + "Restore after a failed run confirms the app and source layout without a pane click when the layout receipt was lost": 141, + "Restore after a failed run confirms the app and source layout without a pane click when the workbench resized the split": 167, "a cold Wiki layout beside VS Code's chat view borrows no keyboard and its return focuses nothing": 83, - "a cold Wiki layout that borrowed the keyboard of Cursor's chat tab gives it back to the chat when the reader asks": 82, - "a layout read beside Cursor's chat part while a learner's diff editor in front of the second group has the keyboard borrows nothing and leaves the diff in front": 65, - "a layout read that borrows the first group while a learner's diff editor in front of the second group has the keyboard gives the keyboard back to the diff through its group's focus": 70, - "a layout read that borrows the main editor's first group gives the keyboard back to the learner's diff editor in VS Code's floating window through its group's focus": 62, - "a layout read that borrows the main editor's first group gives the keyboard back to the text editor of VS Code's floating window that had it": 69, - "a layout read while a text editor of VS Code's floating window with two groups has the keyboard borrows the main editor's first group and measures the main editor's one group": 64, - "a learner's click into another file while an agent's cold Wiki layout beside Cursor's chat part measures is still refused as the learner's newer focus": 77, - "a learner's file given the keyboard again after Cursor replaced every tab group object names the group object the editor lists now": 74, - "a leftover Repository Wiki pane of an earlier extension host selected beside the unchanged text editor still refuses the Wiki's arrangement beside Cursor's chat": 76, - "a passive layout read beside Cursor's chat part while the learner's file in the second of four main groups has the keyboard reads the main editor's four groups": 63, - "a passive layout read while a text editor of VS Code's floating window with two groups has the keyboard reads no main editor's layout": 62, - "a presentation read from chat reports unverified scope without stealing focus or invalidating the retained main grid": 101, - "a presentation read preserves changed learner focus and does not certify the returned editor part": 91, - "a presentation reselect from chat reports unverified scope without stealing focus or invalidating the retained main grid": 105, - "a queued cold Wiki checks its original learner focus before any native scope work": 84, - "a restored Living book preference positions its new application in the reserved main pane rather than the chat column": 75, - "a source edit after the Wiki-group return still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 210, - "a source selection after the Wiki-group return still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 216, - "an agent's cold Wiki layout beside Cursor's chat part refused after its measurement gives the chat its keyboard back and says that nothing was arranged": 99, - "an agent's cold Wiki layout beside Cursor's chat part that is cancelled after its measurement gives the chat nothing back and tells nothing": 80, - "an agent's cold Wiki layout beside Cursor's chat part that is refused after its measurement gives the chat its keyboard back": 73, - "an agent's cold Wiki layout beside Cursor's chat part that splits the only main group follows the editor's late name of the measured group and gives the chat its keyboard back": 71, - "an agent's cold Wiki layout beside Cursor's chat part whose reader closes after its measurement runs no focus command after the Close": 89, - "an agent's cold Wiki layout beside Cursor's chat part, which keeps naming the chat's group after the first group's focus, answers and gives the chat its keyboard back": 69, - "an explicit living-book Open retry after a failed passive scope read still reserves separate main Study panes": 78, - "an explicit study-workspace Open retry after a failed passive scope read still reserves separate main Study panes": 78, - "an older presentation read cannot suppress original focus recovery after a newer mode change fails": 279, - "another editor before the Wiki-group return still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 190, - "another webview selected in the Wiki's group beside the unchanged text editor still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 199, - "cancel during cold Wiki scope measurement cannot mutate the main or chat part": 80, - "chat focus after cited-source acquisition prevents cold Wiki from reserving a late native pane": 79, + "a cold Wiki layout that borrowed the keyboard of Cursor's chat tab gives it back to the chat when the reader asks": 89, + "a layout read beside Cursor's chat part while a learner's diff editor in front of the second group has the keyboard borrows nothing and leaves the diff in front": 64, + "a layout read that borrows the first group while a learner's diff editor in front of the second group has the keyboard gives the keyboard back to the diff through its group's focus": 73, + "a layout read that borrows the main editor's first group gives the keyboard back to the learner's diff editor in VS Code's floating window through its group's focus": 80, + "a layout read that borrows the main editor's first group gives the keyboard back to the text editor of VS Code's floating window that had it": 73, + "a layout read while a text editor of VS Code's floating window with two groups has the keyboard borrows the main editor's first group and measures the main editor's one group": 72, + "a learner's click into another file while an agent's cold Wiki layout beside Cursor's chat part measures is still refused as the learner's newer focus": 64, + "a learner's file given the keyboard again after Cursor replaced every tab group object names the group object the editor lists now": 60, + "a leftover Repository Wiki pane of an earlier extension host selected beside the unchanged text editor still refuses the Wiki's arrangement beside Cursor's chat": 70, + "a passive layout read beside Cursor's chat part while the learner's file in the second of four main groups has the keyboard reads the main editor's four groups": 69, + "a passive layout read while a text editor of VS Code's floating window with two groups has the keyboard reads no main editor's layout": 67, + "a presentation read from chat reports unverified scope without stealing focus or invalidating the retained main grid": 72, + "a presentation read preserves changed learner focus and does not certify the returned editor part": 76, + "a presentation reselect from chat reports unverified scope without stealing focus or invalidating the retained main grid": 85, + "a queued cold Wiki checks its original learner focus before any native scope work": 72, + "a restored Living book preference positions its new application in the reserved main pane rather than the chat column": 63, + "a source edit after the Wiki-group return still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 185, + "a source selection after the Wiki-group return still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 187, + "an agent's cold Wiki layout beside Cursor's chat part refused after its measurement gives the chat its keyboard back and says that nothing was arranged": 87, + "an agent's cold Wiki layout beside Cursor's chat part that is cancelled after its measurement gives the chat nothing back and tells nothing": 79, + "an agent's cold Wiki layout beside Cursor's chat part that is refused after its measurement gives the chat its keyboard back": 89, + "an agent's cold Wiki layout beside Cursor's chat part that splits the only main group follows the editor's late name of the measured group and gives the chat its keyboard back": 78, + "an agent's cold Wiki layout beside Cursor's chat part whose reader closes after its measurement runs no focus command after the Close": 69, + "an agent's cold Wiki layout beside Cursor's chat part, which keeps naming the chat's group after the first group's focus, answers and gives the chat its keyboard back": 82, + "an explicit living-book Open retry after a failed passive scope read still reserves separate main Study panes": 83, + "an explicit study-workspace Open retry after a failed passive scope read still reserves separate main Study panes": 81, + "an older presentation read cannot suppress original focus recovery after a newer mode change fails": 294, + "another editor before the Wiki-group return still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 211, + "another webview selected in the Wiki's group beside the unchanged text editor still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 194, + "cancel during cold Wiki scope measurement cannot mutate the main or chat part": 76, + "chat focus after cited-source acquisition prevents cold Wiki from reserving a late native pane": 88, "cold Study reservation retains Cursor wrapper replacements without adopting the separate chat pane": 86, - "cold Study reserves a third main pane before Context can target the existing chat column": 82, + "cold Study reserves a third main pane before Context can target the existing chat column": 70, "cold Wiki accepts the intended primary transition when native notifications arrive editor first": 81, - "cold Wiki accepts the intended primary transition when native notifications arrive group first": 82, - "cold Wiki confirmation read preserves newer learner chat": 83, - "cold Wiki confirmation read preserves newer learner edit": 77, - "cold Wiki confirmation read preserves newer learner selection": 84, - "cold Wiki confirmation read retains ordinary text through accepted allocation": 79, - "cold Wiki first measurement preserves newer learner chat": 74, - "cold Wiki first measurement preserves newer learner edit": 82, - "cold Wiki first measurement preserves newer learner selection": 75, - "cold Wiki first measurement retains ordinary text through accepted allocation": 80, - "cold Wiki from chat keeps its intentional focus handoff during main measurement": 74, - "cold Wiki from chat keeps its intentional focus handoff during primary response": 84, - "cold Wiki from chat remembers learner selection roundtrip during main measurement": 68, - "cold Wiki from chat remembers learner selection roundtrip during primary response": 75, - "cold Wiki from chat remembers learner tab roundtrip during main measurement": 81, - "cold Wiki from chat remembers learner tab roundtrip during primary response": 109, - "cold Wiki from the learner's file in the second group beside another editor part measures without borrowing the first group, and that file keeps the keyboard without being shown again": 85, - "cold Wiki from the learner's file in the second group beside another editor part remembers a learner selection roundtrip during its only measurement, and that file keeps the keyboard without being shown again": 98, - "cold Wiki from the learner's file in the second group beside another editor part remembers a learner tab roundtrip during its only measurement, and that file keeps the keyboard without being shown again": 108, - "cold Wiki from the learner's file in the second group remembers learner chat during its only measurement": 85, - "cold Wiki from the learner's file in the second group remembers learner chat roundtrip during its only measurement": 69, - "cold Wiki split response preserves newer learner chat": 80, - "cold Wiki split response preserves newer learner edit": 79, - "cold Wiki split response preserves newer learner selection": 80, - "cold Wiki split response retains ordinary text through accepted allocation": 80, - "compact Study opens a readable explanation when native minimum widths prevent the requested split": 1768, - "compact Study remains open when its optional first explanation read loses window focus": 1784, - "every tab of the fake editor has the label its editor names it with, as both editors' tab models give one to every tab": 75, - "first configured Study pause keeps captured source visible beside the application without manual Arrange": 304, - "keyboard moved into the Wiki still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 195, - "moving focus to chat during the cold Wiki measurement preserves both parts without a late layout mutation": 77, - "opening the Repository Wiki right after Study Close beside Cursor's chat arranges without a refusal when the editor returns to the Wiki's group beside the unchanged text editor while the main grid is measured": 192, - "reading every group's front tab, its label and its input in the fake editor changes no group, no tab, no focus and runs no command": 75, - "selecting the Study workspace right after Study Close beside Cursor's chat opens it when the editor returns to the Wiki's group beside the unchanged text editor while the main grid is measured": 576, + "cold Wiki accepts the intended primary transition when native notifications arrive group first": 79, + "cold Wiki confirmation read preserves newer learner chat": 80, + "cold Wiki confirmation read preserves newer learner edit": 72, + "cold Wiki confirmation read preserves newer learner selection": 61, + "cold Wiki confirmation read retains ordinary text through accepted allocation": 84, + "cold Wiki first measurement preserves newer learner chat": 83, + "cold Wiki first measurement preserves newer learner edit": 81, + "cold Wiki first measurement preserves newer learner selection": 81, + "cold Wiki first measurement retains ordinary text through accepted allocation": 73, + "cold Wiki from chat keeps its intentional focus handoff during main measurement": 72, + "cold Wiki from chat keeps its intentional focus handoff during primary response": 83, + "cold Wiki from chat remembers learner selection roundtrip during main measurement": 100, + "cold Wiki from chat remembers learner selection roundtrip during primary response": 65, + "cold Wiki from chat remembers learner tab roundtrip during main measurement": 84, + "cold Wiki from chat remembers learner tab roundtrip during primary response": 124, + "cold Wiki from the learner's file in the second group beside another editor part measures without borrowing the first group, and that file keeps the keyboard without being shown again": 79, + "cold Wiki from the learner's file in the second group beside another editor part remembers a learner selection roundtrip during its only measurement, and that file keeps the keyboard without being shown again": 66, + "cold Wiki from the learner's file in the second group beside another editor part remembers a learner tab roundtrip during its only measurement, and that file keeps the keyboard without being shown again": 85, + "cold Wiki from the learner's file in the second group remembers learner chat during its only measurement": 72, + "cold Wiki from the learner's file in the second group remembers learner chat roundtrip during its only measurement": 89, + "cold Wiki split response preserves newer learner chat": 75, + "cold Wiki split response preserves newer learner edit": 77, + "cold Wiki split response preserves newer learner selection": 75, + "cold Wiki split response retains ordinary text through accepted allocation": 79, + "compact Study opens a readable explanation when native minimum widths prevent the requested split": 1713, + "compact Study remains open when its optional first explanation read loses window focus": 1743, + "every tab of the fake editor has the label its editor names it with, as both editors' tab models give one to every tab": 67, + "first configured Study pause keeps captured source visible beside the application without manual Arrange": 331, + "keyboard moved into the Wiki still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 188, + "moving focus to chat during the cold Wiki measurement preserves both parts without a late layout mutation": 88, + "opening the Repository Wiki right after Study Close beside Cursor's chat arranges without a refusal when the editor returns to the Wiki's group beside the unchanged text editor while the main grid is measured": 187, + "reading every group's front tab, its label and its input in the fake editor changes no group, no tab, no focus and runs no command": 72, + "selecting the Study workspace right after Study Close beside Cursor's chat opens it when the editor returns to the Wiki's group beside the unchanged text editor while the main grid is measured": 548, "the chat's group beside the unchanged text editor still refuses the Repository Wiki's arrangement right after Study Close beside Cursor's chat": 192, - "the fake Cursor counts the chat input's late keyboard after Focus Agent among its pending timers, and a closed harness drops it: the chat does not take the keyboard after the harness's close": 112, - "the fake Cursor keeps its chat part the active editor part after a click into the terminal or a view: layout reads answer for the chat part, no text editor is active, and the active group's focus gives the chat input the keyboard": 110, - "the fake Cursor reports a text editor shown with the keyboard beside the chat as the active text editor and keeps naming the chat's group": 74, - "the fake Cursor reports no focus of a pane in the first group while the chat input has the keyboard and the editor names the captured source's group": 87, - "the fake Cursor reports the first group's text editor as the active text editor and keeps naming the chat's group after the command that focuses the first editor group": 74, - "the fake VS Code makes its main editor the active part again after a click from the floating chat window into the terminal: layout reads answer for the main editor": 82, - "the fake editor answers Focus Agent from a file and from the chat and a tab close beside Cursor's chat part as Cursor did on C61": 69, - "the fake editor disposes the panel of a webview tab when a whole group that holds it is closed, as both editors do: its onDidDispose fires and the harness holds one panel less": 72, - "the fake editor goes on naming Cursor's chat group after the first group took the keyboard when the learner's file there turns dirty, and names the first group after a whole tab-model rebuild": 72, - "the fake editor hides both side bars for the maximize command, shows neither when the maximization ends, and reads the columns of the editor area in the pixels the bars leave": 70, - "the fake editor leaves the keyboard on the page body when a disposed pane's tab closes after a group focus command, until such a command runs after that close": 130, - "the fake editor names Cursor's chat part's group after a tab opened without the keyboard in the main editor while Focus Agent left the chat input the keyboard": 79, - "the fake editor names Cursor's groups beside its chat part as the native probe read them through a borrow, a lock, Focus Agent, a first-group focus and a new group": 66, - "the fake editor of Cursor replaces every tab group object at a whole tab-model event, as Cursor does": 63, - "the fake editor of VS Code keeps every tab group object at a whole tab-model event, as VS Code does": 72, - "the fake editor of a closed harness does not finish showing its Variables view late: the first rows of its tree, 60 ms later, is dropped with the harness's close": 81, - "the fake editor of a closed harness does not finish showing its Variables view late: the refresh that loads the stop it missed, 400 ms later, is dropped with the harness's close": 69, - "the fake editor of a closed harness does not name the focused group again after a maximization ended: no group event arrives after the harness's close": 429, - "the fake editor of a closed harness does not report its active text editor late after a leftover tab closed: no active-editor event arrives after the harness's close": 249, - "the fake editor of a closed harness runs none of the tab closes it still owed: its tabs stay and no listener is called after the harness's close": 137, - "the fake editor opens a new empty group for the focus command of the column after the main editor's last group, and Cursor's Focus Agent command gives the chat the keyboard without changing a group": 69, - "the fake editor reports a learner diff editor’s text editors without a view column, as both editors do": 61, - "the fake editor takes the keyboard from the page body again with a pane revealed with the focus": 89, - "the fake editor takes the keyboard from the page body again with a text document shown with the focus": 106, - "the fake editor takes the keyboard from the page body again with the chat's tab focused": 75, - "the fake editor takes the keyboard from the page body again with the learner's file focused": 83, + "the fake Cursor counts the chat input's late keyboard after Focus Agent among its pending timers, and a closed harness drops it: the chat does not take the keyboard after the harness's close": 90, + "the fake Cursor keeps its chat part the active editor part after a click into the terminal or a view: layout reads answer for the chat part, no text editor is active, and the active group's focus gives the chat input the keyboard": 64, + "the fake Cursor reports a text editor shown with the keyboard beside the chat as the active text editor and keeps naming the chat's group": 90, + "the fake Cursor reports no focus of a pane in the first group while the chat input has the keyboard and the editor names the captured source's group": 61, + "the fake Cursor reports the first group's text editor as the active text editor and keeps naming the chat's group after the command that focuses the first editor group": 76, + "the fake VS Code makes its main editor the active part again after a click from the floating chat window into the terminal: layout reads answer for the main editor": 68, + "the fake editor answers Focus Agent from a file and from the chat and a tab close beside Cursor's chat part as Cursor did on C61": 59, + "the fake editor disposes the panel of a webview tab when a whole group that holds it is closed, as both editors do: its onDidDispose fires and the harness holds one panel less": 78, + "the fake editor goes on naming Cursor's chat group after the first group took the keyboard when the learner's file there turns dirty, and names the first group after a whole tab-model rebuild": 65, + "the fake editor hides both side bars for the maximize command, shows neither when the maximization ends, and reads the columns of the editor area in the pixels the bars leave": 62, + "the fake editor leaves the keyboard on the page body when a disposed pane's tab closes after a group focus command, until such a command runs after that close": 136, + "the fake editor names Cursor's chat part's group after a tab opened without the keyboard in the main editor while Focus Agent left the chat input the keyboard": 74, + "the fake editor names Cursor's groups beside its chat part as the native probe read them through a borrow, a lock, Focus Agent, a first-group focus and a new group": 63, + "the fake editor of Cursor replaces every tab group object at a whole tab-model event, as Cursor does": 65, + "the fake editor of VS Code keeps every tab group object at a whole tab-model event, as VS Code does": 77, + "the fake editor of a closed harness does not finish showing its Variables view late: the first rows of its tree, 60 ms later, is dropped with the harness's close": 59, + "the fake editor of a closed harness does not finish showing its Variables view late: the refresh that loads the stop it missed, 400 ms later, is dropped with the harness's close": 63, + "the fake editor of a closed harness does not name the focused group again after a maximization ended: no group event arrives after the harness's close": 414, + "the fake editor of a closed harness does not report its active text editor late after a leftover tab closed: no active-editor event arrives after the harness's close": 250, + "the fake editor of a closed harness runs none of the tab closes it still owed: its tabs stay and no listener is called after the harness's close": 148, + "the fake editor opens a new empty group for the focus command of the column after the main editor's last group, and Cursor's Focus Agent command gives the chat the keyboard without changing a group": 76, + "the fake editor reports a learner diff editor’s text editors without a view column, as both editors do": 66, + "the fake editor takes the keyboard from the page body again with a pane revealed with the focus": 75, + "the fake editor takes the keyboard from the page body again with a text document shown with the focus": 93, + "the fake editor takes the keyboard from the page body again with the chat's tab focused": 71, + "the fake editor takes the keyboard from the page body again with the learner's file focused": 79, "the fake editor's secondary side bar focus command keeps the keyboard in VS Code's chat view in front of that bar": 64, - "the fake editor's side bar focus commands take the keyboard from the terminal and from a view that had it and give it to the bar, as both editors do": 85 + "the fake editor's side bar focus commands take the keyboard from the terminal and from a view that had it and give it to the bar, as both editors do": 63 } }, "studyWorkspaceLayout.test.js": { - "totalMs": 93892, + "totalMs": 91212, "tests": { - "Arrange Study Workspace gives a collapsed Application group its normal height, in a recording": 320, - "Arrange Study Workspace gives a collapsed Application group its normal height, in the Study layout": 632, - "Close after interrupted main-part reservation preserves the original article, chat and draft": 355, - "Close drains an accepted article Return without retaining a layout origin or reopening owned panes": 470, - "Close during observation source loading prevents a late application reveal over the article": 277, - "Close during the accepted reentry layout read cannot acquire a new receipt or reopen owned panes": 355, - "Cursor Wiki and recording round trips preserve the separate chat part and original two-row article with ordered API groups": 516, - "Cursor Wiki and recording round trips preserve the separate chat part and original two-row article with reordered API groups": 476, - "Cursor article Return retains input when the Application itself was focused": 624, - "Cursor explicit observation reentry reveals its captured application over the retained article tab": 489, - "Cursor group contraction preserves pre-merge identities so the next evidence visit restores all three pane columns": 305, - "Cursor group creation cannot make a fourth learner group eligible for article Return contraction": 247, - "Cursor group creation preserves the article origin so actual Return restores its two stacked rows": 285, - "Cursor preserves a uniquely added learner text tab while returning to the saved article grid": 440, - "Cursor recording reentry after a source-derived observation keeps original drafts and reserves its own Application again": 714, - "Cursor two-event contraction preserves error-free Return and correct main panes and summary on observation reentry": 230, - "Cursor two-event contraction preserves error-free Return and correct main panes and summary on recording reentry": 379, - "Cursor: Close during the accepted reentry layout read cannot acquire a new receipt or reopen owned panes": 368, - "Cursor: a newer article visit drains accepted reentry effects without adopting the temporary grid as its return origin": 470, - "Cursor: cancelling an accepted known Study grid restoration retains the original pane locations for Return and retry": 403, - "Cursor: observation reentry can restore the source column accepted by Study before the article Return contracted its group": 283, - "Living book to Guided walkthrough retains evidence and focus when native moves emit a late focus echo": 755, - "Open Study Workspace gives a collapsed Application group its normal height, in a recording": 315, - "Open Study Workspace gives a collapsed Application group its normal height, in the Study layout": 220, - "Restore in Recording is confirmed when Cursor reports another active group for one event while the layout is applied": 338, - "Restore layout after enlarging the app waits for Study focus without losing recorded evidence": 439, - "Restore layout keeps the original Study panes when Cursor focuses Application during its layout read": 459, - "Restore layout repairs changed native proportions instead of certifying the enlarged receipt": 442, - "Restore waits for an active layout transaction before confirming an enlarged Study": 432, - "Return after interrupted main-part reservation preserves the original article, chat and draft": 605, - "VS Code Wiki and recording round trips preserve the separate chat part and original two-row article with ordered API groups": 506, - "VS Code Wiki and recording round trips preserve the separate chat part and original two-row article with reordered API groups": 491, - "VS Code article Return retains input when the Application itself was focused": 597, - "VS Code explicit observation reentry reveals its captured application over the retained article tab": 430, - "VS Code recording reentry after a source-derived observation keeps original drafts and reserves its own Application again": 716, - "Wiki observation reentry restores Study after an empty chat wrapper refresh following actual Return": 337, - "Wiki recording reentry preserves the reading grid after an empty other-part ambiguous following actual Return": 425, - "Wiki recording reentry preserves the reading grid after an empty other-part move following actual Return": 243, - "Wiki recording reentry preserves the reading grid after an empty other-part replace following actual Return": 378, - "Wiki recording reentry preserves the reading grid after an empty other-part unannounced following actual Return": 381, - "Wiki recording reentry restores Study after an empty chat wrapper refresh following actual Return": 402, - "a Repository Wiki recording visit refused because the learner typed in the focused file during its placement leaves no Application group behind": 235, - "a Repository Wiki recording visit whose Application preparation fails after it created the pane refuses the recording with the preparation’s reason and leaves no Application group behind": 177, - "a Return to Wiki that ends while an agent’s presentation change places its panes leaves that placement counted as Codebook’s own until the change ends, and nothing counted after both": 418, - "a Study layout the editor did not keep is reported with the command that applies it again, and that command clears the report": 957, - "a captured source that failed to show twice in a row is left to Retry storage / refresh instead of being tried again at every refresh": 122, - "a cold evidence navigation whose native debugger takes 4 s and whose frame paints in 2 s still presents": 1039, - "a group emptied by a moved pane in a two-row layout leaves the same layout as one emptied by a disposed pane": 94, - "a group emptied by a tab close in a two-row layout leaves the same layout as one emptied by a disposed pane": 148, - "a manual application move during the restored-layout receipt remains authoritative on the next evidence visit": 471, - "a manual application move while a returning article observation loads preserves the learner layout": 344, - "a manual context move while a returning article observation loads preserves the learner layout": 349, - "a manual grid change during reentry certification is never adopted as a Codebook arrangement": 350, - "a manual pane move during a cancelled reentry layout read never becomes a Codebook-owned effect": 350, - "a manual resize while the next evidence source loads is preserved after actual article Return": 472, - "a manual source move while a returning article observation loads preserves the learner layout": 428, - "a new evidence visit drains a cancelled Return layout before restoring its two main replay panes": 1158, - "a newer article visit drains accepted reentry effects without adopting the temporary grid as its return origin": 422, - "a newer frame painted during an evidence navigation gets its own paint bound": 1049, - "a normal Wiki open after cancelled reentry does not consume the previous article Return layout": 356, + "Arrange Study Workspace gives a collapsed Application group its normal height, in a recording": 274, + "Arrange Study Workspace gives a collapsed Application group its normal height, in the Study layout": 593, + "Close after interrupted main-part reservation preserves the original article, chat and draft": 339, + "Close drains an accepted article Return without retaining a layout origin or reopening owned panes": 373, + "Close during observation source loading prevents a late application reveal over the article": 249, + "Close during the accepted reentry layout read cannot acquire a new receipt or reopen owned panes": 342, + "Cursor Wiki and recording round trips preserve the separate chat part and original two-row article with ordered API groups": 492, + "Cursor Wiki and recording round trips preserve the separate chat part and original two-row article with reordered API groups": 464, + "Cursor article Return retains input when the Application itself was focused": 562, + "Cursor explicit observation reentry reveals its captured application over the retained article tab": 451, + "Cursor group contraction preserves pre-merge identities so the next evidence visit restores all three pane columns": 284, + "Cursor group creation cannot make a fourth learner group eligible for article Return contraction": 243, + "Cursor group creation preserves the article origin so actual Return restores its two stacked rows": 276, + "Cursor preserves a uniquely added learner text tab while returning to the saved article grid": 381, + "Cursor recording reentry after a source-derived observation keeps original drafts and reserves its own Application again": 704, + "Cursor two-event contraction preserves error-free Return and correct main panes and summary on observation reentry": 275, + "Cursor two-event contraction preserves error-free Return and correct main panes and summary on recording reentry": 378, + "Cursor: Close during the accepted reentry layout read cannot acquire a new receipt or reopen owned panes": 355, + "Cursor: a newer article visit drains accepted reentry effects without adopting the temporary grid as its return origin": 436, + "Cursor: cancelling an accepted known Study grid restoration retains the original pane locations for Return and retry": 455, + "Cursor: observation reentry can restore the source column accepted by Study before the article Return contracted its group": 246, + "Living book to Guided walkthrough retains evidence and focus when native moves emit a late focus echo": 774, + "Open Study Workspace gives a collapsed Application group its normal height, in a recording": 327, + "Open Study Workspace gives a collapsed Application group its normal height, in the Study layout": 217, + "Restore in Recording is confirmed when Cursor reports another active group for one event while the layout is applied": 286, + "Restore layout after enlarging the app waits for Study focus without losing recorded evidence": 437, + "Restore layout keeps the original Study panes when Cursor focuses Application during its layout read": 507, + "Restore layout repairs changed native proportions instead of certifying the enlarged receipt": 361, + "Restore waits for an active layout transaction before confirming an enlarged Study": 417, + "Return after interrupted main-part reservation preserves the original article, chat and draft": 579, + "VS Code Wiki and recording round trips preserve the separate chat part and original two-row article with ordered API groups": 492, + "VS Code Wiki and recording round trips preserve the separate chat part and original two-row article with reordered API groups": 480, + "VS Code article Return retains input when the Application itself was focused": 577, + "VS Code explicit observation reentry reveals its captured application over the retained article tab": 358, + "VS Code recording reentry after a source-derived observation keeps original drafts and reserves its own Application again": 728, + "Wiki observation reentry restores Study after an empty chat wrapper refresh following actual Return": 306, + "Wiki recording reentry preserves the reading grid after an empty other-part ambiguous following actual Return": 430, + "Wiki recording reentry preserves the reading grid after an empty other-part move following actual Return": 254, + "Wiki recording reentry preserves the reading grid after an empty other-part replace following actual Return": 387, + "Wiki recording reentry preserves the reading grid after an empty other-part unannounced following actual Return": 374, + "Wiki recording reentry restores Study after an empty chat wrapper refresh following actual Return": 384, + "a Repository Wiki recording visit refused because the learner typed in the focused file during its placement leaves no Application group behind": 221, + "a Repository Wiki recording visit whose Application preparation fails after it created the pane refuses the recording with the preparation’s reason and leaves no Application group behind": 181, + "a Return to Wiki that ends while an agent’s presentation change places its panes leaves that placement counted as Codebook’s own until the change ends, and nothing counted after both": 404, + "a Study layout the editor did not keep is reported with the command that applies it again, and that command clears the report": 949, + "a captured source that failed to show twice in a row is left to Retry storage / refresh instead of being tried again at every refresh": 107, + "a cold evidence navigation whose native debugger takes 4 s and whose frame paints in 2 s still presents": 968, + "a group emptied by a moved pane in a two-row layout leaves the same layout as one emptied by a disposed pane": 62, + "a group emptied by a tab close in a two-row layout leaves the same layout as one emptied by a disposed pane": 145, + "a manual application move during the restored-layout receipt remains authoritative on the next evidence visit": 513, + "a manual application move while a returning article observation loads preserves the learner layout": 379, + "a manual context move while a returning article observation loads preserves the learner layout": 403, + "a manual grid change during reentry certification is never adopted as a Codebook arrangement": 371, + "a manual pane move during a cancelled reentry layout read never becomes a Codebook-owned effect": 328, + "a manual resize while the next evidence source loads is preserved after actual article Return": 535, + "a manual source move while a returning article observation loads preserves the learner layout": 443, + "a new evidence visit drains a cancelled Return layout before restoring its two main replay panes": 496, + "a newer article visit drains accepted reentry effects without adopting the temporary grid as its return origin": 431, + "a newer frame painted during an evidence navigation gets its own paint bound": 944, + "a normal Wiki open after cancelled reentry does not consume the previous article Return layout": 391, "a proportional learner resize after Wiki Return remains authoritative on the next observation": 213, - "a queued actual article Return preserves a later learner draft focus without changing the Study layout": 286, - "a recorded seek in Cursor keeps its source input and confirmed layout through native group-wrapper refresh": 390, - "a recorded seek made in Cursor while the bottom panel is maximized leaves the Application group at its normal height and the layout confirmed": 358, - "a recorded seek made while the bottom panel is maximized gives a collapsed Application group its height back also when the layout was no longer confirmed": 354, - "a recorded seek made while the bottom panel is maximized leaves the Application group at its normal height and the layout confirmed": 414, - "a saved study chosen with the bottom panel maximized is shown when the panel is restored ten minutes later": 228, - "a status read after an editor group was replaced says which part of the confirmed layout differs": 71, - "a status read after the grid changed says which part of the confirmed layout differs": 77, + "a queued actual article Return preserves a later learner draft focus without changing the Study layout": 724, + "a recorded seek in Cursor keeps its source input and confirmed layout through native group-wrapper refresh": 347, + "a recorded seek made in Cursor while the bottom panel is maximized leaves the Application group at its normal height and the layout confirmed": 360, + "a recorded seek made while the bottom panel is maximized gives a collapsed Application group its height back also when the layout was no longer confirmed": 371, + "a recorded seek made while the bottom panel is maximized leaves the Application group at its normal height and the layout confirmed": 400, + "a saved study chosen with the bottom panel maximized is shown when the panel is restored ten minutes later": 211, + "a status read after an editor group was replaced says which part of the confirmed layout differs": 67, + "a status read after the grid changed says which part of the confirmed layout differs": 76, "a status read made while the chat has the focus answers that the layout is not confirmed after a group changed since the last arrangement (keyboard in the chat input)": 68, - "a status read made while the chat has the focus answers that the layout is not confirmed after a group changed since the last arrangement (keyboard on the chat's tab)": 70, - "a status read made while the chat has the focus answers the confirmation of the last arrangement when nothing changed since (keyboard in the chat input)": 115, - "a status read made while the chat has the focus answers the confirmation of the last arrangement when nothing changed since (keyboard on the chat's tab)": 75, - "a tab that is closed while the reader restores its layout makes the reader post nothing at that moment, and the Study pane is told how the layout stands once the restore has ended": 283, - "actual Return after cancelled reentry preserves a foreign draft added to the expanded group": 357, - "actual Return cannot consume another article origin when its native layout is still owned": 472, - "actual article Return preserves a learner's application move after opening recording evidence": 330, - "actual article Return preserves a learner's foreign group after opening recording evidence": 325, - "actual article Return preserves a learner's foreign tab after opening recording evidence": 329, - "actual article Return preserves a learner's replaced group after opening recording evidence": 330, - "actual article Return preserves a learner's resize after opening recording evidence": 348, - "actual article Return preserves a learner's source move after opening recording evidence": 350, - "after a Wiki observation visit and its Return to Wiki, the Study left open says it is set aside and names View observation to bring it back": 205, - "after a Wiki recording visit and its Return to Wiki, View recording in the Wiki brings the set-aside Study back with its layout confirmed": 460, + "a status read made while the chat has the focus answers that the layout is not confirmed after a group changed since the last arrangement (keyboard on the chat's tab)": 78, + "a status read made while the chat has the focus answers the confirmation of the last arrangement when nothing changed since (keyboard in the chat input)": 75, + "a status read made while the chat has the focus answers the confirmation of the last arrangement when nothing changed since (keyboard on the chat's tab)": 60, + "a tab that is closed while the reader restores its layout makes the reader post nothing at that moment, and the Study pane is told how the layout stands once the restore has ended": 313, + "actual Return after cancelled reentry preserves a foreign draft added to the expanded group": 343, + "actual Return cannot consume another article origin when its native layout is still owned": 409, + "actual article Return preserves a learner's application move after opening recording evidence": 328, + "actual article Return preserves a learner's foreign group after opening recording evidence": 334, + "actual article Return preserves a learner's foreign tab after opening recording evidence": 318, + "actual article Return preserves a learner's replaced group after opening recording evidence": 329, + "actual article Return preserves a learner's resize after opening recording evidence": 318, + "actual article Return preserves a learner's source move after opening recording evidence": 331, + "after a Wiki observation visit and its Return to Wiki, the Study left open says it is set aside and names View observation to bring it back": 222, + "after a Wiki recording visit and its Return to Wiki, View recording in the Wiki brings the set-aside Study back with its layout confirmed": 457, "after a Wiki recording visit and its Return to Wiki, the Study left open behind the article says it is set aside and names View recording to bring it back, not a wait (Cursor)": 359, - "after a Wiki recording visit and its Return to Wiki, the Study left open behind the article says it is set aside and names View recording to bring it back, not a wait (VS Code)": 340, - "after a saved study was chosen with the bottom panel maximized, restoring the panel shows that study with the Application group at its normal height and the layout confirmed": 239, - "after the learner closes the captured source’s tab by hand beside a saved study, Focus source, which its reason names, shows the source again and confirms the layout": 200, - "after the learner closes the captured source’s tab by hand on the Recording tab, Reload saved recording, which its reason names, shows the source again and confirms the layout": 402, + "after a Wiki recording visit and its Return to Wiki, the Study left open behind the article says it is set aside and names View recording to bring it back, not a wait (VS Code)": 342, + "after a saved study was chosen with the bottom panel maximized, restoring the panel shows that study with the Application group at its normal height and the layout confirmed": 218, + "after the learner closes the captured source’s tab by hand beside a saved study, Focus source, which its reason names, shows the source again and confirms the layout": 209, + "after the learner closes the captured source’s tab by hand on the Recording tab, Reload saved recording, which its reason names, shows the source again and confirms the layout": 425, "all three presentation modes preserve source, learning item and learner decisions across pane handoffs": 1087, - "an evidence navigation cancelled while its frame paints ends with the cancellation, and the next recording open presents": 430, - "an evidence navigation stuck before painting fails at the settle ceiling and the next recording open presents": 3306, - "an evidence navigation that gives up never cancels a newer learner seek": 995, - "an evidence navigation whose native debugger needs a pending startup, a retirement, the next startup and the inspection grace (15.7 s) before a 4.9 s paint still presents": 2956, - "application-focused mode transfers keep the scrolled context visible without repeated upward drift": 1019, - "application-focused mode transfers keep the selected statement visible without repeated upward drift": 1000, - "article Return drains its accepted App group close after Close and preserves the retained renderer or newer input": 353, - "article Return drains its accepted App group close after cancellation and preserves the retained renderer or newer input": 345, - "article Return drains its accepted App group close after newer source and preserves the retained renderer or newer input": 349, - "article Return drains its accepted App move after Close and preserves the retained renderer or newer input": 369, - "article Return drains its accepted App move after cancellation and preserves the retained renderer or newer input": 384, - "article Return drains its accepted App move after newer source and preserves the retained renderer or newer input": 387, - "article Return in an inactive window refuses before moving its retained Application or closing a group": 374, - "article Return preserves a dirty draft that adopted the newly allocated App group": 439, - "background acquisition preserves a manual App move made after Wiki Return until explicit Study reentry": 703, - "cancel during observation source loading prevents a late application reveal over the article": 248, - "cancelling a later article evidence visit keeps the previous actual Return layout and reading origin": 422, - "cancelling actual Return during its ownership read preserves Study and permits a later explicit Return": 495, - "cancelling an accepted known Study grid restoration retains the original pane locations for Return and retry": 364, - "cancelling during the accepted reentry layout read still lets actual Return restore the article groups": 356, - "cancelling observation reentry after actual Return preserves the original article layout for another Return": 340, - "choosing another saved study while the bottom panel is maximized leaves the panel maximized and shows the chosen study in it": 223, - "enlarging a recorded application targets its owned pane and retains the paused evidence": 498, - "explicit Study after actual Wiki Return preserves a learner's shape edit to the reading grid": 352, - "explicit Study after actual Wiki Return preserves a learner's size edit to the reading grid": 363, - "explicit Study after actual Wiki Return restores its verified 2-group origin following observation entry": 228, - "explicit Study after actual Wiki Return restores its verified 2-group origin following recording entry": 405, - "explicit Study after actual Wiki Return restores its verified 3-group origin following observation entry": 236, - "explicit Study after actual Wiki Return restores its verified 3-group origin following recording entry": 424, - "explicit observation entry preserves a manually moved application in its current column": 275, - "explicit observation entry preserves a manually moved application sharing the context group with Return visible": 279, - "in Cursor, View recording pressed again in the Wiki after the article Return brings the set-aside Study back confirmed with its captured source in front": 485, - "in Cursor, the article Return of a Wiki recording visit leaves the Wiki’s cited copy in front of the learner’s first group with the captured source right behind it, and the parked Application right behind the Wiki in front of the active group, as Cursor did natively": 538, - "in Cursor, the recording's Application pane retitled by the reader is labelled codebook · Recorded application in front of its group during a Wiki recording visit and parked after the article Return, as Cursor labelled it": 353, - "in VS Code, View recording pressed again in the Wiki after the article Return in the learner’s uneven stack brings the set-aside Study back confirmed, and its Return gives both rows back": 484, - "in VS Code, View recording pressed in the Wiki of the second group while VS Code still names the first group’s text editor as active shows the recording in its own group and gives the Wiki its keyboard back": 356, - "in VS Code, a Wiki recording visit in the learner’s grid with a column split into rows stays confirmed, and the article Return gives the grid back at its sizes": 362, - "in VS Code, a Wiki recording visit in the learner’s grid with a row split into columns stays confirmed, and the article Return gives the grid back at its sizes": 350, - "in VS Code, a Wiki recording visit in the learner’s uneven stack of two rows stays confirmed, and the article Return gives both rows back at their sizes": 350, - "in VS Code, a Wiki recording visit with recorded values ends with the learner’s first group active, and the article Return parks the Application right behind the Wiki in the article’s group, as VS Code did natively": 538, - "in VS Code, an agent’s replay open while another extension’s webview in the second group has the keyboard and VS Code still names the first group’s text editor as active shows the recording in its own group and gives the webview its keyboard back": 282, - "in VS Code, the recording's Application pane retitled by the reader is labelled codebook · Recorded application in front of its group during a Wiki recording visit and parked after the article Return, as VS Code labelled it": 349, - "later source input during the accepted App reservation read prevents obsolete entry effects": 344, - "later window input during the accepted App reservation read prevents obsolete entry effects": 10355, - "mode transfer waits for delayed app activity after its own native tab and document receive focus": 963, - "mode transfer waits for delayed contextPanel activity after its own native tab and document receive focus": 1049, - "mode transfers retain native destination groups with application only and a separate chat part": 1384, - "mode transfers retain native destination groups with application only and one editor part": 1422, - "mode transfers retain native destination groups with unrelated draft and a separate chat part": 1427, - "mode transfers retain native destination groups with unrelated draft and one editor part": 1420, - "native minimum-width expansion keeps Wiki Return successful and the next observation in three visible panes": 213, - "observation a source move during reentry loading overrides the previously planned source restoration": 229, - "observation reentry can restore the source column accepted by Study before the article Return contracted its group": 241, - "observation source placement accepted before cancellation survives Return and the next evidence visit": 301, - "paused replay preserves manually scrolled source context through repeated application-focused layout restoration": 354, - "paused replay preserves manually scrolled source context through repeated source-focused layout restoration": 361, - "paused replay preserves manually scrolled source context through repeated summary-focused layout restoration": 351, - "periodic study refresh preserves a learner text tab selected over the captured application": 227, - "reading the sidebar beside an enlarged application preserves replay and restores the same source": 462, - "reentry restores the verified Study grid once without evening its saved split sizes": 398, - "reopening an enlarged Study does not claim its three-pane layout was confirmed": 171, - "repeating article Return preserves its borrowed App group without draining the retained renderer again": 343, - "replay readiness after explicit reentry cannot confirm later learner groups": 343, - "replay readiness after explicit reentry cannot confirm later learner layout": 357, + "an evidence navigation cancelled while its frame paints ends with the cancellation, and the next recording open presents": 408, + "an evidence navigation stuck before painting fails at the settle ceiling and the next recording open presents": 2927, + "an evidence navigation that gives up never cancels a newer learner seek": 927, + "an evidence navigation whose native debugger needs a pending startup, a retirement, the next startup and the inspection grace (15.7 s) before a 4.9 s paint still presents": 2637, + "application-focused mode transfers keep the scrolled context visible without repeated upward drift": 997, + "application-focused mode transfers keep the selected statement visible without repeated upward drift": 986, + "article Return drains its accepted App group close after Close and preserves the retained renderer or newer input": 348, + "article Return drains its accepted App group close after cancellation and preserves the retained renderer or newer input": 342, + "article Return drains its accepted App group close after newer source and preserves the retained renderer or newer input": 334, + "article Return drains its accepted App move after Close and preserves the retained renderer or newer input": 343, + "article Return drains its accepted App move after cancellation and preserves the retained renderer or newer input": 342, + "article Return drains its accepted App move after newer source and preserves the retained renderer or newer input": 358, + "article Return in an inactive window refuses before moving its retained Application or closing a group": 353, + "article Return preserves a dirty draft that adopted the newly allocated App group": 352, + "background acquisition preserves a manual App move made after Wiki Return until explicit Study reentry": 635, + "cancel during observation source loading prevents a late application reveal over the article": 249, + "cancelling a later article evidence visit keeps the previous actual Return layout and reading origin": 325, + "cancelling actual Return during its ownership read preserves Study and permits a later explicit Return": 634, + "cancelling an accepted known Study grid restoration retains the original pane locations for Return and retry": 431, + "cancelling during the accepted reentry layout read still lets actual Return restore the article groups": 343, + "cancelling observation reentry after actual Return preserves the original article layout for another Return": 342, + "choosing another saved study while the bottom panel is maximized leaves the panel maximized and shows the chosen study in it": 200, + "enlarging a recorded application targets its owned pane and retains the paused evidence": 440, + "explicit Study after actual Wiki Return preserves a learner's shape edit to the reading grid": 365, + "explicit Study after actual Wiki Return preserves a learner's size edit to the reading grid": 374, + "explicit Study after actual Wiki Return restores its verified 2-group origin following observation entry": 245, + "explicit Study after actual Wiki Return restores its verified 2-group origin following recording entry": 419, + "explicit Study after actual Wiki Return restores its verified 3-group origin following observation entry": 218, + "explicit Study after actual Wiki Return restores its verified 3-group origin following recording entry": 414, + "explicit observation entry preserves a manually moved application in its current column": 276, + "explicit observation entry preserves a manually moved application sharing the context group with Return visible": 261, + "in Cursor, View recording pressed again in the Wiki after the article Return brings the set-aside Study back confirmed with its captured source in front": 466, + "in Cursor, the article Return of a Wiki recording visit leaves the Wiki’s cited copy in front of the learner’s first group with the captured source right behind it, and the parked Application right behind the Wiki in front of the active group, as Cursor did natively": 519, + "in Cursor, the recording's Application pane retitled by the reader is labelled codebook · Recorded application in front of its group during a Wiki recording visit and parked after the article Return, as Cursor labelled it": 328, + "in VS Code, View recording pressed again in the Wiki after the article Return in the learner’s uneven stack brings the set-aside Study back confirmed, and its Return gives both rows back": 465, + "in VS Code, View recording pressed in the Wiki of the second group while VS Code still names the first group’s text editor as active shows the recording in its own group and gives the Wiki its keyboard back": 320, + "in VS Code, a Wiki recording visit in the learner’s grid with a column split into rows stays confirmed, and the article Return gives the grid back at its sizes": 357, + "in VS Code, a Wiki recording visit in the learner’s grid with a row split into columns stays confirmed, and the article Return gives the grid back at its sizes": 359, + "in VS Code, a Wiki recording visit in the learner’s uneven stack of two rows stays confirmed, and the article Return gives both rows back at their sizes": 336, + "in VS Code, a Wiki recording visit with recorded values ends with the learner’s first group active, and the article Return parks the Application right behind the Wiki in the article’s group, as VS Code did natively": 518, + "in VS Code, an agent’s replay open while another extension’s webview in the second group has the keyboard and VS Code still names the first group’s text editor as active shows the recording in its own group and gives the webview its keyboard back": 316, + "in VS Code, the recording's Application pane retitled by the reader is labelled codebook · Recorded application in front of its group during a Wiki recording visit and parked after the article Return, as VS Code labelled it": 326, + "later source input during the accepted App reservation read prevents obsolete entry effects": 329, + "later window input during the accepted App reservation read prevents obsolete entry effects": 10367, + "mode transfer waits for delayed app activity after its own native tab and document receive focus": 773, + "mode transfer waits for delayed contextPanel activity after its own native tab and document receive focus": 778, + "mode transfers retain native destination groups with application only and a separate chat part": 1380, + "mode transfers retain native destination groups with application only and one editor part": 1418, + "mode transfers retain native destination groups with unrelated draft and a separate chat part": 1370, + "mode transfers retain native destination groups with unrelated draft and one editor part": 1391, + "native minimum-width expansion keeps Wiki Return successful and the next observation in three visible panes": 209, + "observation a source move during reentry loading overrides the previously planned source restoration": 240, + "observation reentry can restore the source column accepted by Study before the article Return contracted its group": 264, + "observation source placement accepted before cancellation survives Return and the next evidence visit": 251, + "paused replay preserves manually scrolled source context through repeated application-focused layout restoration": 459, + "paused replay preserves manually scrolled source context through repeated source-focused layout restoration": 377, + "paused replay preserves manually scrolled source context through repeated summary-focused layout restoration": 664, + "periodic study refresh preserves a learner text tab selected over the captured application": 233, + "reading the sidebar beside an enlarged application preserves replay and restores the same source": 421, + "reentry restores the verified Study grid once without evening its saved split sizes": 451, + "reopening an enlarged Study does not claim its three-pane layout was confirmed": 190, + "repeating article Return preserves its borrowed App group without draining the retained renderer again": 326, + "replay readiness after explicit reentry cannot confirm later learner groups": 328, + "replay readiness after explicit reentry cannot confirm later learner layout": 383, "replay reentry after guided-walkthrough request confirms only the current layout when its source becomes ready": 344, - "replay reentry after living-book request confirms only the current layout when its source becomes ready": 360, - "replay reentry after study-workspace request confirms only the current layout when its source becomes ready": 358, - "replay refuses retired explanation enlargement without changing native layout or evidence": 302, - "repository evidence whose recorded frame never paints fails within its bound and the next recording open presents its frame": 999, - "restoring a settled recording retains its application pane and confirmed playhead": 309, - "retry after interrupted main-part reservation preserves the original article, chat and draft": 507, - "retrying a cancelled observation reentry retains the article layout from before Codebook expanded its groups": 369, - "returning from a failed recording restores the article's two stacked groups and permits another evidence visit": 525, - "returning from a healthy recording restores the article's two stacked groups and permits another evidence visit": 507, - "source-derived reentry drains its retained live renderer outside the layout queue after Close": 455, - "source-derived reentry drains its retained live renderer outside the layout queue after finish": 428, - "source-derived reentry drains its retained live renderer outside the layout queue after newer source": 406, - "source-derived reentry drains its retained live renderer outside the layout queue after queued source": 436, - "source-focused mode transfers keep the scrolled context visible without repeated upward drift": 716, - "source-focused mode transfers keep the selected statement visible without repeated upward drift": 695, - "the Study header Restore exits a maximized pane while keeping the settled recording in its original panes": 466, - "the Study pane leaves 'Loading the selected observation…' at the next refresh after showing the captured source failed once": 89, - "the fake Cursor removes every group that dead panes leave empty in one close, although each removal gives the remaining groups new objects": 94, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: a close request for the tab a group shows": 68, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: a text document shown in a group": 96, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: a webview panel created with the keyboard focus": 72, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: a webview panel created without the keyboard focus": 72, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: a webview panel revealed with the keyboard focus": 74, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: an editor layout of another shape": 93, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: an editor layout of the same shape": 65, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: the Close Editor command": 71, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: the command that focuses the active editor group": 65, - "the fake editor brings the editor area back for every trigger VS Code brings it back for: the command that focuses the first editor group": 103, - "the fake editor of Cursor adds a group above a learner's stack of rows in pixels and removes it with the grids Cursor gives natively": 145, - "the fake editor of VS Code adds a group above a learner's stack of rows in pixels and removes it with the grids VS Code gives natively": 183, - "the fake editor sizes and expands a learner’s nested grid as VS Code 1.140.0’s split view and grid do": 131, - "the fake editor sizes and expands a learner’s stacked rows as VS Code 1.140.0 was recorded to": 130, - "the next evidence visit preserves a manual application move made after actual article Return": 463, - "the next evidence visit preserves a manual source move made after actual article Return": 471, - "two quick Return to Wiki presses from a recording leave Codebook placing nothing, so the next visit’s replay hides behind a file the learner opens over its Application pane": 515, - "when the learner closes the Application pane’s tab by hand beside a saved study whose layout is confirmed, the Study pane is told in the same turn that the layout is not confirmed, with the reason": 254, - "when the learner closes the captured source’s tab by hand beside a saved study whose layout is confirmed, the Study pane is told in the same turn that the layout is not confirmed, with the reason": 215, - "when the learner closes the captured source’s tab by hand on the Recording tab, the Study pane is told in the same turn that the layout is not confirmed, with the reason, and tab events that change nothing afterwards post nothing more": 342, - "while a saved study waits for the hidden editor area, a refresh that finds a layout request unanswered sends no second one": 198 + "replay reentry after living-book request confirms only the current layout when its source becomes ready": 392, + "replay reentry after study-workspace request confirms only the current layout when its source becomes ready": 381, + "replay refuses retired explanation enlargement without changing native layout or evidence": 337, + "repository evidence whose recorded frame never paints fails within its bound and the next recording open presents its frame": 929, + "restoring a settled recording retains its application pane and confirmed playhead": 258, + "retry after interrupted main-part reservation preserves the original article, chat and draft": 473, + "retrying a cancelled observation reentry retains the article layout from before Codebook expanded its groups": 363, + "returning from a failed recording restores the article's two stacked groups and permits another evidence visit": 555, + "returning from a healthy recording restores the article's two stacked groups and permits another evidence visit": 521, + "source-derived reentry drains its retained live renderer outside the layout queue after Close": 441, + "source-derived reentry drains its retained live renderer outside the layout queue after finish": 474, + "source-derived reentry drains its retained live renderer outside the layout queue after newer source": 409, + "source-derived reentry drains its retained live renderer outside the layout queue after queued source": 410, + "source-focused mode transfers keep the scrolled context visible without repeated upward drift": 708, + "source-focused mode transfers keep the selected statement visible without repeated upward drift": 691, + "the Study header Restore exits a maximized pane while keeping the settled recording in its original panes": 464, + "the Study pane leaves 'Loading the selected observation…' at the next refresh after showing the captured source failed once": 96, + "the fake Cursor removes every group that dead panes leave empty in one close, although each removal gives the remaining groups new objects": 83, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: a close request for the tab a group shows": 58, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: a text document shown in a group": 78, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: a webview panel created with the keyboard focus": 75, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: a webview panel created without the keyboard focus": 64, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: a webview panel revealed with the keyboard focus": 85, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: an editor layout of another shape": 84, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: an editor layout of the same shape": 72, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: the Close Editor command": 66, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: the command that focuses the active editor group": 64, + "the fake editor brings the editor area back for every trigger VS Code brings it back for: the command that focuses the first editor group": 82, + "the fake editor of Cursor adds a group above a learner's stack of rows in pixels and removes it with the grids Cursor gives natively": 131, + "the fake editor of VS Code adds a group above a learner's stack of rows in pixels and removes it with the grids VS Code gives natively": 140, + "the fake editor sizes and expands a learner’s nested grid as VS Code 1.140.0’s split view and grid do": 140, + "the fake editor sizes and expands a learner’s stacked rows as VS Code 1.140.0 was recorded to": 134, + "the next evidence visit preserves a manual application move made after actual article Return": 475, + "the next evidence visit preserves a manual source move made after actual article Return": 469, + "two quick Return to Wiki presses from a recording leave Codebook placing nothing, so the next visit’s replay hides behind a file the learner opens over its Application pane": 517, + "when the learner closes the Application pane’s tab by hand beside a saved study whose layout is confirmed, the Study pane is told in the same turn that the layout is not confirmed, with the reason": 171, + "when the learner closes the captured source’s tab by hand beside a saved study whose layout is confirmed, the Study pane is told in the same turn that the layout is not confirmed, with the reason": 203, + "when the learner closes the captured source’s tab by hand on the Recording tab, the Study pane is told in the same turn that the layout is not confirmed, with the reason, and tab events that change nothing afterwards post nothing more": 317, + "while a saved study waits for the hidden editor area, a refresh that finds a layout request unanswered sends no second one": 210 } }, "studyWorkspaceLifecycle.test.js": { - "totalMs": 50048, + "totalMs": 49180, "tests": { - "A disposal of the reader that ends a Read in a window without the focus shows the side bars the Read hid again, leaves the keyboard in the active editor group and tells the learner where it is": 311, - "Close Study Workspace during a Read, with a Wiki citation copy in each group Codebook created, leaves the end of the maximization to the editor and runs no command that resizes a group": 221, - "Close Study Workspace from the Command Palette with the keyboard in the Study pane gives the active editor group the keyboard and says so": 79, - "Close Study Workspace from the Command Palette with the keyboard in the terminal gives the active editor group the keyboard and says so": 74, - "Close Study Workspace made while Cursor's chat tab has the keyboard leaves the keyboard in the chat and tells nothing": 115, - "Close Study Workspace made while the editor names its Settings page beside Cursor's chat tab runs no focus command and tells nothing": 84, - "Close Study Workspace made with the editor's Settings page active gives the active editor group the keyboard once the panes' groups closed, and says where it is": 202, - "Close Study Workspace made with the keyboard in the Study pane leaves the keyboard in the editor group that remains": 103, - "Close Study Workspace made with the keyboard in the captured source leaves the keyboard in the editor group that remains": 68, - "Close Study Workspace made with the keyboard in the captured source leaves the keyboard in the editor group that remains when the editor closes the panes' tabs a moment later": 169, - "Close Study Workspace made with the learner's own file active gives the active editor group the keyboard once the panes' groups closed, and says where it is once in an editor session": 332, - "Close Study Workspace made with the learner's own file active runs no focus command and tells nothing when the Study workspace is not open": 95, - "Close Study Workspace made with the learner's own file active runs no focus command and tells nothing when the work window does not have the focus": 80, - "Close Study Workspace that ends a Read in a window without the focus shows the side bars the Read hid again, leaves the keyboard in the active editor group and tells the learner where it is": 222, - "Close Study Workspace that ends a Read while Cursor's chat tab has the keyboard shows the side bars the Read hid again, gives the keyboard back to the chat and says so once": 85, - "Close Study Workspace that ends a Read while VS Code's chat editor tab has the keyboard shows the side bar the Read hid again, gives that chat tab's group, the active one, the keyboard back and says once where the keyboard is": 91, - "Close Study Workspace that ends a Read while VS Code's chat editor tab in a floating window has the keyboard gives that chat the keyboard back and says once that the Close's side bars took it, naming no pause": 88, - "Close Study Workspace that ends a Read while the editor names its Settings page beside Cursor's chat tab gives the active editor group the keyboard and says where it is": 70, - "Close cancels stalled capture-presentation-pose delivery without waiting for the renderer transport": 199, - "Close cancels stalled restore-presentation-pose delivery without waiting for the renderer transport": 340, - "a Close of the Live arrangement whose empty Application group the editor refuses to close still ends, reports the refusal and leaves no layout receipt or source behind": 74, - "a Wiki citation copy in the group the editor gave the captured source leaves with that group at Close Study Workspace": 81, - "a Wiki citation copy the learner pinned in the recording Application’s own group stays at Close Study Workspace, with that group": 388, - "a application pane replacement retains a native group containing an unchanged settings tab": 403, - "a changed settings tab during pane replacement cannot inherit native group ownership": 297, - "a context pane replacement retains a native group containing an unchanged settings tab": 377, - "a learner close of the first replacement before the second registers prevents lease adoption": 313, - "a learner move of the first replacement before the second registers prevents lease adoption": 205, - "a learner replacement during the post-reservation layout read cannot be claimed as the created Context group": 520, - "a learner replacement of the pending created Context group cannot inherit its receipt after failed placement and retry": 509, - "a live run ending preserves side-view typing even while its Application remains the native active tab": 371, - "a live run that ends while its Application pane has the keyboard and the Study workspace is closed leaves the keyboard in the active editor group and says once in an editor session where it is": 213, - "a live run that ends while its Application pane has the keyboard, and whose empty group the editor refuses to close, reports the refusal and still leaves the keyboard in the active editor group": 153, - "a live run that ends with the Study workspace closed runs no focus command and tells nothing when the learner works in a file of their own and the pane is not the active editor": 263, - "a live run that ends with the Study workspace closed runs no focus command and tells nothing when the work window does not have the focus": 295, - "a new run that opens the Application pane again retires the line about the closed one": 91, - "a reader that is disposed during a Read shows the side bars the Read hid again, and tells the learner that the keyboard is in the active editor group now": 95, - "a reader that is disposed while its Study pane is the active editor leaves the keyboard in the active editor group and tells the learner where it is": 66, - "a reader that is disposed while its Study workspace is open beside the learner's own file runs no focus command and tells nothing": 83, - "a reader whose dispose fails while it closes its panes releases what it registered with the editor all the same, and tells the failure": 76, - "a replacement settings tab with the same title cannot inherit native group ownership": 285, - "a run that ends with its Application pane active sends no keyboard command or notice when the window loses focus while the disposed tab waits to close": 157, - "a second replacement that creation throws preserves the prior panes and live lease without saving the mode": 309, - "a second replacement that unretained tab preserves the prior panes and live lease without saving the mode": 5300, - "an empty chat move during pane replacement cannot inherit presentation ownership": 282, - "an empty chat opened during pane replacement cannot inherit presentation ownership": 281, - "an empty chat unannounced during pane replacement cannot inherit presentation ownership": 305, - "an empty learner third group added after the first Open note remains after retry and recording reentry": 468, - "an ended run preserves a newer cold presentation while its initialization is pending": 116, - "an ended run preserves a newer cold presentation while its progress read is pending": 134, - "an ended run preserves its Application when a newer live lease arrives during keyboard inspection": 265, - "an ended run preserves its Application when a replacement document arrives during keyboard inspection": 296, - "an unchanged empty chat wrapper during application replacement preserves all three presentation destinations": 397, - "an unchanged empty chat wrapper during context replacement preserves all three presentation destinations": 389, - "closing the Study workspace during a run whose checkpoint write never returns ends within the close bound and the workspace opens again": 856, - "closing the adopted application during native layout rejects the transition and fails its live lease exactly once": 148, - "closing the reader finishes after the storage bound while a library write is still held, and that write still lands": 794, - "explicit presentation focus returns from Wiki without changing layout, learning or execution": 290, - "explicit same-mode restoration recovers inner-focus delivery without replacing the current viewport lease": 394, - "following the current run after its Application pane was closed says that the run ended and how to see the application again, in a line that stays": 77, - "in Cursor, a Wiki citation copy shown into the recording Application's own group leaves with that group at Close Study Workspace, so no Codebook group stays": 421, - "in VS Code, a Wiki citation copy shown into the recording Application's own group leaves with that group at Close Study Workspace, so no Codebook group stays": 399, - "learner input after reading capture cancels placement without saving or restoring the obsolete pose": 181, - "native disposal leaves a refused owned pane and learner tabs intact without forcing panel disposal": 86, - "native disposal leaves the sidebar chat keyboard outside the editor while auth remains the reported active editor": 92, - "native disposal leaves the terminal keyboard outside the editor while auth remains the reported active editor": 82, - "native disposal of a captured-source-only ending group preserves the actual learner editor keyboard": 76, - "native disposal preserves a rebuilt inherited pane while a current owned Study pane remains open after an earlier close": 63, - "native disposal preserves the learner's actual auth keyboard and original file beside both owned panes with group wrapper refresh false": 69, - "native disposal preserves the learner's actual auth keyboard and original file beside both owned panes with group wrapper refresh true": 121, - "native disposal refuses indistinguishable rebuilt same-kind panes in its current panel group and preserves both tabs": 101, - "native disposal rereads the current tab groups after an earlier close answer waits for learner tab": 85, - "native disposal rereads the current tab groups after an earlier close answer waits for new tab objects": 75, - "native disposal rereads the current tab groups after an earlier close answer waits for reordered groups": 95, - "native disposal rereads the current tab groups after an earlier close answer waits for window focus lost": 102, - "native disposal retains another reader source and inherited pane instead of treating their group as ending": 75, - "native tab disposal callbacks do not erase the once-only keyboard notice when the reader closes its active Study pane": 64, - "not delivered capture-presentation-pose delivery refuses the presentation within its existing deadline": 188, - "not delivered restore-presentation-pose delivery refuses the presentation within its existing deadline": 388, - "ordinary chat can recover Study focus from Wiki through the public MCP presentation tool": 229, - "presentation focus preserves newer intent after learner draft during native handoff": 247, - "presentation focus preserves newer intent after window roundtrip during native handoff": 207, - "presentation focus rejects closed without revealing a pane": 97, - "presentation focus rejects different mode without revealing a pane": 896, - "presentation focus rejects unfocused window without revealing a pane": 202, - "recording keeps a reader-created source group after the learner adds a dirty draft": 364, - "recording keeps a reader-created source group after the learner adds a pinned capture": 493, - "recording keeps a reader-created source group after the learner adds a replacement group": 508, - "recording reentry retires the reader-created Context group after wrapper refresh when 1 learner groups existed before Open": 485, - "recording reentry retires the reader-created Context group after wrapper refresh when 2 learner groups existed before Open": 520, - "recording retry retires its created Context group after newer input interrupts native scope measurement": 1084, - "recording retry retires its created Context group after newer input interrupts native scope measurement and the native close is refused once": 1137, - "recording source-group retirement stops after Close while its native copy waits": 319, - "recording source-group retirement stops after new source while its native copy waits": 413, - "recording source-group retirement stops after new source with chat while its native copy waits": 467, - "rejected capture-presentation-pose delivery refuses the presentation within its existing deadline": 197, - "rejected restore-presentation-pose delivery refuses the presentation within its existing deadline": 402, - "replay retains its renderer after native layout failure and restores layout only on explicit retry": 352, - "replay retains its renderer after newer learner tab and restores layout only on explicit retry": 707, - "restoring replay keeps the live renderer attached without requesting a pane handoff": 536, - "restoring replay preserves both live history and replay leases at the confirmed captured-frame position": 368, - "restoring replay preserves both live history and replay leases at the confirmed missing-frame position": 378, - "retired application notifications after reopening cannot change the current replay or learner understanding": 561, - "same-column App handoff preserves the old lease when the predecessor preview state changes during registration": 308, - "same-column App handoff preserves the old lease when the replacement preview state changes during registration": 278, - "same-column codebook.scopedBrowser handoff survives a group-wrapper refresh while both owned tabs coexist": 414, - "same-column codebook.studyContext handoff survives a group-wrapper refresh while both owned tabs coexist": 432, - "same-column handoff preserves its current lease when the host refreshes the previous codebook.scopedBrowser tab wrapper": 405, - "same-column handoff preserves its current lease when the host refreshes the previous codebook.studyContext tab wrapper": 387, - "same-column handoff refuses a moved-group during owned tab overlap": 290, - "same-column handoff refuses a opened during owned tab overlap": 285, - "same-column handoff refuses a third-tab during owned tab overlap": 290, - "same-column handoff refuses a unannounced during owned tab overlap": 284, - "same-column mode changes recover native inner-focus delivery while preserving the current viewport lease": 704, - "same-layout selection repairs proportions while preserving an unchanged source preview": 79, - "same-layout selection repairs proportions while preserving an unsaved source preview": 130, - "stalled capture-presentation-pose delivery refuses the presentation within its existing deadline": 5191, - "stalled restore-presentation-pose delivery refuses the presentation within its existing deadline": 5350, - "the Open replay entry keeps its command while the reader publishes again without a change, so a click between two publishes still opens the recording": 245, - "the notice of Close Study Workspace is not told again in the same editor session by the reader that replaces a disposed one after the workspace folders changed": 108, - "the reader does not take the learner's Settings page for its own active editor while it has shown no captured source": 74, - "the workspace harness historical debugger ends a wait for native Variables when its session ends, and the view refreshing later no longer answers one, like the real owner": 850, - "the workspace harness historical debugger ends a wait for native Variables when the reader is closed, like the real owner": 379, - "while a run records the status bar offers Save learning replay and no second recording control, and after the save the same item offers Open replay": 196 + "A disposal of the reader that ends a Read in a window without the focus shows the side bars the Read hid again, leaves the keyboard in the active editor group and tells the learner where it is": 196, + "Close Study Workspace during a Read, with a Wiki citation copy in each group Codebook created, leaves the end of the maximization to the editor and runs no command that resizes a group": 242, + "Close Study Workspace from the Command Palette with the keyboard in the Study pane gives the active editor group the keyboard and says so": 75, + "Close Study Workspace from the Command Palette with the keyboard in the terminal gives the active editor group the keyboard and says so": 69, + "Close Study Workspace made while Cursor's chat tab has the keyboard leaves the keyboard in the chat and tells nothing": 80, + "Close Study Workspace made while the editor names its Settings page beside Cursor's chat tab runs no focus command and tells nothing": 101, + "Close Study Workspace made with the editor's Settings page active gives the active editor group the keyboard once the panes' groups closed, and says where it is": 262, + "Close Study Workspace made with the keyboard in the Study pane leaves the keyboard in the editor group that remains": 100, + "Close Study Workspace made with the keyboard in the captured source leaves the keyboard in the editor group that remains": 89, + "Close Study Workspace made with the keyboard in the captured source leaves the keyboard in the editor group that remains when the editor closes the panes' tabs a moment later": 136, + "Close Study Workspace made with the learner's own file active gives the active editor group the keyboard once the panes' groups closed, and says where it is once in an editor session": 331, + "Close Study Workspace made with the learner's own file active runs no focus command and tells nothing when the Study workspace is not open": 76, + "Close Study Workspace made with the learner's own file active runs no focus command and tells nothing when the work window does not have the focus": 75, + "Close Study Workspace that ends a Read in a window without the focus shows the side bars the Read hid again, leaves the keyboard in the active editor group and tells the learner where it is": 214, + "Close Study Workspace that ends a Read while Cursor's chat tab has the keyboard shows the side bars the Read hid again, gives the keyboard back to the chat and says so once": 90, + "Close Study Workspace that ends a Read while VS Code's chat editor tab has the keyboard shows the side bar the Read hid again, gives that chat tab's group, the active one, the keyboard back and says once where the keyboard is": 81, + "Close Study Workspace that ends a Read while VS Code's chat editor tab in a floating window has the keyboard gives that chat the keyboard back and says once that the Close's side bars took it, naming no pause": 81, + "Close Study Workspace that ends a Read while the editor names its Settings page beside Cursor's chat tab gives the active editor group the keyboard and says where it is": 81, + "Close cancels stalled capture-presentation-pose delivery without waiting for the renderer transport": 177, + "Close cancels stalled restore-presentation-pose delivery without waiting for the renderer transport": 331, + "a Close of the Live arrangement whose empty Application group the editor refuses to close still ends, reports the refusal and leaves no layout receipt or source behind": 81, + "a Wiki citation copy in the group the editor gave the captured source leaves with that group at Close Study Workspace": 67, + "a Wiki citation copy the learner pinned in the recording Application’s own group stays at Close Study Workspace, with that group": 358, + "a application pane replacement retains a native group containing an unchanged settings tab": 386, + "a changed settings tab during pane replacement cannot inherit native group ownership": 284, + "a context pane replacement retains a native group containing an unchanged settings tab": 404, + "a learner close of the first replacement before the second registers prevents lease adoption": 293, + "a learner move of the first replacement before the second registers prevents lease adoption": 231, + "a learner replacement during the post-reservation layout read cannot be claimed as the created Context group": 469, + "a learner replacement of the pending created Context group cannot inherit its receipt after failed placement and retry": 497, + "a live run ending preserves side-view typing even while its Application remains the native active tab": 329, + "a live run that ends while its Application pane has the keyboard and the Study workspace is closed leaves the keyboard in the active editor group and says once in an editor session where it is": 239, + "a live run that ends while its Application pane has the keyboard, and whose empty group the editor refuses to close, reports the refusal and still leaves the keyboard in the active editor group": 169, + "a live run that ends with the Study workspace closed runs no focus command and tells nothing when the learner works in a file of their own and the pane is not the active editor": 268, + "a live run that ends with the Study workspace closed runs no focus command and tells nothing when the work window does not have the focus": 292, + "a new run that opens the Application pane again retires the line about the closed one": 80, + "a reader that is disposed during a Read shows the side bars the Read hid again, and tells the learner that the keyboard is in the active editor group now": 78, + "a reader that is disposed while its Study pane is the active editor leaves the keyboard in the active editor group and tells the learner where it is": 71, + "a reader that is disposed while its Study workspace is open beside the learner's own file runs no focus command and tells nothing": 64, + "a reader whose dispose fails while it closes its panes releases what it registered with the editor all the same, and tells the failure": 86, + "a replacement settings tab with the same title cannot inherit native group ownership": 277, + "a run that ends with its Application pane active sends no keyboard command or notice when the window loses focus while the disposed tab waits to close": 191, + "a second replacement that creation throws preserves the prior panes and live lease without saving the mode": 289, + "a second replacement that unretained tab preserves the prior panes and live lease without saving the mode": 5316, + "an empty chat move during pane replacement cannot inherit presentation ownership": 284, + "an empty chat opened during pane replacement cannot inherit presentation ownership": 282, + "an empty chat unannounced during pane replacement cannot inherit presentation ownership": 278, + "an empty learner third group added after the first Open note remains after retry and recording reentry": 458, + "an ended run preserves a newer cold presentation while its initialization is pending": 164, + "an ended run preserves a newer cold presentation while its progress read is pending": 172, + "an ended run preserves its Application when a newer live lease arrives during keyboard inspection": 302, + "an ended run preserves its Application when a replacement document arrives during keyboard inspection": 322, + "an unchanged empty chat wrapper during application replacement preserves all three presentation destinations": 383, + "an unchanged empty chat wrapper during context replacement preserves all three presentation destinations": 391, + "closing the Study workspace during a run whose checkpoint write never returns ends within the close bound and the workspace opens again": 792, + "closing the adopted application during native layout rejects the transition and fails its live lease exactly once": 126, + "closing the reader finishes after the storage bound while a library write is still held, and that write still lands": 727, + "explicit presentation focus returns from Wiki without changing layout, learning or execution": 254, + "explicit same-mode restoration recovers inner-focus delivery without replacing the current viewport lease": 372, + "following the current run after its Application pane was closed says that the run ended and how to see the application again, in a line that stays": 141, + "in Cursor, a Wiki citation copy shown into the recording Application's own group leaves with that group at Close Study Workspace, so no Codebook group stays": 392, + "in VS Code, a Wiki citation copy shown into the recording Application's own group leaves with that group at Close Study Workspace, so no Codebook group stays": 323, + "learner input after reading capture cancels placement without saving or restoring the obsolete pose": 200, + "native disposal leaves a refused owned pane and learner tabs intact without forcing panel disposal": 94, + "native disposal leaves the sidebar chat keyboard outside the editor while auth remains the reported active editor": 76, + "native disposal leaves the terminal keyboard outside the editor while auth remains the reported active editor": 79, + "native disposal of a captured-source-only ending group preserves the actual learner editor keyboard": 94, + "native disposal preserves a rebuilt inherited pane while a current owned Study pane remains open after an earlier close": 79, + "native disposal preserves the learner's actual auth keyboard and original file beside both owned panes with group wrapper refresh false": 70, + "native disposal preserves the learner's actual auth keyboard and original file beside both owned panes with group wrapper refresh true": 93, + "native disposal refuses indistinguishable rebuilt same-kind panes in its current panel group and preserves both tabs": 95, + "native disposal rereads the current tab groups after an earlier close answer waits for learner tab": 64, + "native disposal rereads the current tab groups after an earlier close answer waits for new tab objects": 86, + "native disposal rereads the current tab groups after an earlier close answer waits for reordered groups": 83, + "native disposal rereads the current tab groups after an earlier close answer waits for window focus lost": 98, + "native disposal retains another reader source and inherited pane instead of treating their group as ending": 63, + "native tab disposal callbacks do not erase the once-only keyboard notice when the reader closes its active Study pane": 66, + "not delivered capture-presentation-pose delivery refuses the presentation within its existing deadline": 217, + "not delivered restore-presentation-pose delivery refuses the presentation within its existing deadline": 427, + "ordinary chat can recover Study focus from Wiki through the public MCP presentation tool": 245, + "presentation focus preserves newer intent after learner draft during native handoff": 263, + "presentation focus preserves newer intent after window roundtrip during native handoff": 208, + "presentation focus rejects closed without revealing a pane": 114, + "presentation focus rejects different mode without revealing a pane": 166, + "presentation focus rejects unfocused window without revealing a pane": 148, + "recording keeps a reader-created source group after the learner adds a dirty draft": 436, + "recording keeps a reader-created source group after the learner adds a pinned capture": 496, + "recording keeps a reader-created source group after the learner adds a replacement group": 485, + "recording reentry retires the reader-created Context group after wrapper refresh when 1 learner groups existed before Open": 505, + "recording reentry retires the reader-created Context group after wrapper refresh when 2 learner groups existed before Open": 514, + "recording retry retires its created Context group after newer input interrupts native scope measurement": 1013, + "recording retry retires its created Context group after newer input interrupts native scope measurement and the native close is refused once": 1109, + "recording source-group retirement stops after Close while its native copy waits": 278, + "recording source-group retirement stops after new source while its native copy waits": 478, + "recording source-group retirement stops after new source with chat while its native copy waits": 481, + "rejected capture-presentation-pose delivery refuses the presentation within its existing deadline": 180, + "rejected restore-presentation-pose delivery refuses the presentation within its existing deadline": 385, + "replay retains its renderer after native layout failure and restores layout only on explicit retry": 375, + "replay retains its renderer after newer learner tab and restores layout only on explicit retry": 657, + "restoring replay keeps the live renderer attached without requesting a pane handoff": 1025, + "restoring replay preserves both live history and replay leases at the confirmed captured-frame position": 365, + "restoring replay preserves both live history and replay leases at the confirmed missing-frame position": 368, + "retired application notifications after reopening cannot change the current replay or learner understanding": 566, + "same-column App handoff preserves the old lease when the predecessor preview state changes during registration": 276, + "same-column App handoff preserves the old lease when the replacement preview state changes during registration": 280, + "same-column codebook.scopedBrowser handoff survives a group-wrapper refresh while both owned tabs coexist": 388, + "same-column codebook.studyContext handoff survives a group-wrapper refresh while both owned tabs coexist": 381, + "same-column handoff preserves its current lease when the host refreshes the previous codebook.scopedBrowser tab wrapper": 372, + "same-column handoff preserves its current lease when the host refreshes the previous codebook.studyContext tab wrapper": 405, + "same-column handoff refuses a moved-group during owned tab overlap": 286, + "same-column handoff refuses a opened during owned tab overlap": 290, + "same-column handoff refuses a third-tab during owned tab overlap": 305, + "same-column handoff refuses a unannounced during owned tab overlap": 275, + "same-column mode changes recover native inner-focus delivery while preserving the current viewport lease": 692, + "same-layout selection repairs proportions while preserving an unchanged source preview": 71, + "same-layout selection repairs proportions while preserving an unsaved source preview": 74, + "stalled capture-presentation-pose delivery refuses the presentation within its existing deadline": 5174, + "stalled restore-presentation-pose delivery refuses the presentation within its existing deadline": 5399, + "the Open replay entry keeps its command while the reader publishes again without a change, so a click between two publishes still opens the recording": 208, + "the notice of Close Study Workspace is not told again in the same editor session by the reader that replaces a disposed one after the workspace folders changed": 85, + "the reader does not take the learner's Settings page for its own active editor while it has shown no captured source": 63, + "the workspace harness historical debugger ends a wait for native Variables when its session ends, and the view refreshing later no longer answers one, like the real owner": 858, + "the workspace harness historical debugger ends a wait for native Variables when the reader is closed, like the real owner": 403, + "while a run records the status bar offers Save learning replay and no second recording control, and after the save the same item offers Open replay": 184 } }, "studyWorkspaceNavigation.test.js": { - "totalMs": 21413, + "totalMs": 20953, "tests": { - "Arrange reports interrupted source placement and a later explicit retry restores the three regions": 504, - "Arrange retains its source region after replay visibility cancels rendering and respects a later manual move": 467, - "Arrange retains its source region after replay visibility cancels rendering and respects an immediate manual move": 414, - "Cursor ambiguous webview inputs cannot acquire Codebook layout ownership during resync": 83, - "Cursor duplicate webview inputs cannot acquire Codebook layout ownership during resync": 124, - "Cursor empty webview inputs cannot acquire Codebook layout ownership during resync": 103, - "Cursor known webview inputs retain layout ownership across application title changes": 73, - "Cursor unknown webview inputs cannot acquire Codebook layout ownership during resync": 103, - "Cursor wrapper-only tab resync preserves Wiki and Study layout switching during an in-flight ownership read": 72, - "Restore separates a Study explanation from source after its third native group closes": 382, - "Source follows a learner move after Arrange while preserving the earlier duplicate and dirty draft": 383, - "Study reports why a captured source prevents layout confirmation after failed execution": 105, - "Wiki observation and explicit Study entry keep hidden navigation panes hidden until requested": 193, - "Wiki reading layout cannot report the selected Study presentation as confirmed": 92, - "Wiki recording and explicit Study entry keep hidden navigation panes hidden until requested": 325, - "a Wiki observation link opens its exact earlier same-item pause after host restart and newer history choices retire that reading point": 320, - "a Wiki observation link opens its exact earlier same-item pause beside the active archive and newer history choices retire that reading point": 287, - "a host tab resync cannot disguise a learner group move as Codebook ownership": 83, - "a host tab resync cannot disguise a learner group remove as Codebook ownership": 78, - "a host tab resync cannot disguise a learner group reorder as Codebook ownership": 65, - "a host tab resync cannot disguise a learner group replace as Codebook ownership": 99, - "a host tab resync cannot disguise a learner group unannounced as Codebook ownership": 77, - "a manual shape change during the host layout receipt never becomes Codebook-owned on the next Wiki return": 5341, - "a manual size change during the host layout receipt never becomes Codebook-owned on the next Wiki return": 5303, - "a pending recording Return keeps a newer refused connection error when the Wiki handoff completes": 1203, - "a retired renderer cannot select another layout while replay opens its summary sidebar": 320, - "a successful recording Summary Return removes its earlier navigation error from the published Summary": 550, - "an MCP mode request before replay readiness clears its warning when the first position becomes ready": 455, - "an empty other-part ambiguous cannot authorize Study to replace the reading layout": 75, - "an empty other-part move cannot authorize Study to replace the reading layout": 69, - "an empty other-part replace cannot authorize Study to replace the reading layout": 88, - "an empty other-part unannounced cannot authorize Study to replace the reading layout": 99, - "an unchanged empty chat part cannot block Study reentry after Wiki tab resync": 75, - "book evidence opens the exact historical observation and retains a restart-safe Return to Wiki target": 206, - "book evidence rejects a changed captured observation before selecting history or opening replay": 169, - "book recording links seek the exact captured observation time while playback stays paused and runtime input stays unchanged": 321, - "cancelling Wiki navigation while checking native layout ownership cannot rearrange the editor later": 85, - "cancelling a first reader entry drains its accepted workbench layout batch without dispatching another mutation": 72, - "cancelling observation navigation during native source acquisition prevents its later source reveal and focus commands": 188, - "cancelling recording navigation during native source acquisition prevents its later source reveal and focus commands": 189, - "closing the article during a pending checkpoint prevents the later evidence read from opening study panes": 160, - "evidence entry preserves a learner resize made while reading the Wiki": 74, - "explicit Arrange separates moved application, source and context while preserving unrelated tabs": 400, - "explicit Open Study preserves hidden navigation while a Wiki observation entry waits for source": 192, - "explicit Open Study preserves hidden navigation while a Wiki recording entry waits for source": 312, - "explicit Study reentry reveals its application and captured source over retained reading tabs": 68, - "returning from recording to Wiki keeps background study refresh from covering the article with captured source": 502, - "returning to Wiki during a cancelled Study layout waits for the accepted host effect then restores side-by-side reading": 98, - "returning to Wiki places source beside article without merging tabs and the next evidence entry restores Study panes": 75, - "returning to Wiki preserves a learner's extra-group change to the native editor layout": 76, - "returning to Wiki preserves a learner's identity change to the native editor layout": 79, - "returning to Wiki preserves a learner's shape change to the native editor layout": 69, - "returning to Wiki preserves a learner's size change to the native editor layout": 70 + "Arrange reports interrupted source placement and a later explicit retry restores the three regions": 481, + "Arrange retains its source region after replay visibility cancels rendering and respects a later manual move": 387, + "Arrange retains its source region after replay visibility cancels rendering and respects an immediate manual move": 382, + "Cursor ambiguous webview inputs cannot acquire Codebook layout ownership during resync": 87, + "Cursor duplicate webview inputs cannot acquire Codebook layout ownership during resync": 64, + "Cursor empty webview inputs cannot acquire Codebook layout ownership during resync": 68, + "Cursor known webview inputs retain layout ownership across application title changes": 64, + "Cursor unknown webview inputs cannot acquire Codebook layout ownership during resync": 76, + "Cursor wrapper-only tab resync preserves Wiki and Study layout switching during an in-flight ownership read": 86, + "Restore separates a Study explanation from source after its third native group closes": 409, + "Source follows a learner move after Arrange while preserving the earlier duplicate and dirty draft": 391, + "Study reports why a captured source prevents layout confirmation after failed execution": 75, + "Wiki observation and explicit Study entry keep hidden navigation panes hidden until requested": 198, + "Wiki reading layout cannot report the selected Study presentation as confirmed": 68, + "Wiki recording and explicit Study entry keep hidden navigation panes hidden until requested": 322, + "a Wiki observation link opens its exact earlier same-item pause after host restart and newer history choices retire that reading point": 334, + "a Wiki observation link opens its exact earlier same-item pause beside the active archive and newer history choices retire that reading point": 278, + "a host tab resync cannot disguise a learner group move as Codebook ownership": 87, + "a host tab resync cannot disguise a learner group remove as Codebook ownership": 74, + "a host tab resync cannot disguise a learner group reorder as Codebook ownership": 60, + "a host tab resync cannot disguise a learner group replace as Codebook ownership": 85, + "a host tab resync cannot disguise a learner group unannounced as Codebook ownership": 100, + "a manual shape change during the host layout receipt never becomes Codebook-owned on the next Wiki return": 5328, + "a manual size change during the host layout receipt never becomes Codebook-owned on the next Wiki return": 5284, + "a pending recording Return keeps a newer refused connection error when the Wiki handoff completes": 438, + "a retired renderer cannot select another layout while replay opens its summary sidebar": 294, + "a successful recording Summary Return removes its earlier navigation error from the published Summary": 1216, + "an MCP mode request before replay readiness clears its warning when the first position becomes ready": 329, + "an empty other-part ambiguous cannot authorize Study to replace the reading layout": 90, + "an empty other-part move cannot authorize Study to replace the reading layout": 73, + "an empty other-part replace cannot authorize Study to replace the reading layout": 62, + "an empty other-part unannounced cannot authorize Study to replace the reading layout": 71, + "an unchanged empty chat part cannot block Study reentry after Wiki tab resync": 69, + "book evidence opens the exact historical observation and retains a restart-safe Return to Wiki target": 227, + "book evidence rejects a changed captured observation before selecting history or opening replay": 175, + "book recording links seek the exact captured observation time while playback stays paused and runtime input stays unchanged": 342, + "cancelling Wiki navigation while checking native layout ownership cannot rearrange the editor later": 72, + "cancelling a first reader entry drains its accepted workbench layout batch without dispatching another mutation": 66, + "cancelling observation navigation during native source acquisition prevents its later source reveal and focus commands": 215, + "cancelling recording navigation during native source acquisition prevents its later source reveal and focus commands": 187, + "closing the article during a pending checkpoint prevents the later evidence read from opening study panes": 173, + "evidence entry preserves a learner resize made while reading the Wiki": 111, + "explicit Arrange separates moved application, source and context while preserving unrelated tabs": 434, + "explicit Open Study preserves hidden navigation while a Wiki observation entry waits for source": 206, + "explicit Open Study preserves hidden navigation while a Wiki recording entry waits for source": 379, + "explicit Study reentry reveals its application and captured source over retained reading tabs": 62, + "returning from recording to Wiki keeps background study refresh from covering the article with captured source": 434, + "returning to Wiki during a cancelled Study layout waits for the accepted host effect then restores side-by-side reading": 73, + "returning to Wiki places source beside article without merging tabs and the next evidence entry restores Study panes": 73, + "returning to Wiki preserves a learner's extra-group change to the native editor layout": 69, + "returning to Wiki preserves a learner's identity change to the native editor layout": 82, + "returning to Wiki preserves a learner's shape change to the native editor layout": 66, + "returning to Wiki preserves a learner's size change to the native editor layout": 78 } }, "studyWorkspaceNodeHistoryAdmission.test.js": { - "totalMs": 226 + "totalMs": 203 }, "studyWorkspacePixelRetry.test.js": { - "totalMs": 6003 + "totalMs": 6036 }, "studyWorkspacePresentation.test.js": { - "totalMs": 71932, + "totalMs": 72181, "tests": { - "Close cancels pending focus recovery after a native layout failure without losing the draft or original failure": 287, - "Close during MCP-first stale-pane retirement prevents a later Application allocation": 140, - "Close retires the reader identity immediately and waits for an already accepted presentation preference write": 385, - "Guided walkthrough returns to Study without an unnecessary kept-tab focus handoff": 747, - "MCP-first acquisition preserves a refused stale pane without allocating another Application": 78, - "Return to current pause pressed in the Observed moments view in Cursor gives that view its keyboard back and tells nothing": 87, - "Return to current pause pressed in the Observed moments view in VS Code gives that view its keyboard back and tells nothing": 80, - "Return to current pause pressed in the Study pane in Cursor and refused after it closed that pane gives the active editor group the keyboard and says so once": 98, - "Return to current pause pressed in the Study pane in Cursor gives the Application's group the keyboard the closed Study pane had and says so once": 77, - "Return to current pause pressed in the Study pane in VS Code and refused after it closed that pane gives the active editor group the keyboard and says so once": 84, - "Return to current pause pressed in the Study pane in VS Code gives the Application's group the keyboard the closed Study pane had and says so once": 97, - "Study restoration preserves the prior source until delayed text focus clear follows codebook.scopedBrowser activation": 793, - "Study restoration preserves the prior source until delayed text focus clear follows codebook.studyContext activation": 796, - "a Read in a recording and Close Study Workspace leave a side bar the learner had closed as it was": 345, - "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar closed and the secondary one closed": 129, - "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar closed and the secondary one open": 119, - "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar open and the secondary one closed": 148, - "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar open and the secondary one open": 137, - "a Restore after a Read in a live run is confirmed when the editor names another group for a moment while the maximization ends": 211, - "a Restore after a Read in the three-pane Study layout is confirmed when the editor names another group for a moment while the maximization ends": 191, - "a background work window refuses a mode change before native effects": 74, - "a captured-source tab the learner pinned stays open when another run of the same file is shown": 369, - "a close request the editor rejects leaves every tab in place and the selection tells that a dead pane is still open": 75, - "a closed reader behind a focused non-text page of the editor opens when an earlier extension session left a dead Study pane in another group, and that page stays open": 306, - "a closed reader behind a focused non-text page of the editor opens, closes the leftover captured-source tab and keeps that page open behind the Application pane": 291, + "Close cancels pending focus recovery after a native layout failure without losing the draft or original failure": 288, + "Close during MCP-first stale-pane retirement prevents a later Application allocation": 129, + "Close retires the reader identity immediately and waits for an already accepted presentation preference write": 372, + "Guided walkthrough returns to Study without an unnecessary kept-tab focus handoff": 712, + "MCP-first acquisition preserves a refused stale pane without allocating another Application": 84, + "Return to current pause pressed in the Observed moments view in Cursor gives that view its keyboard back and tells nothing": 89, + "Return to current pause pressed in the Observed moments view in VS Code gives that view its keyboard back and tells nothing": 105, + "Return to current pause pressed in the Study pane in Cursor and refused after it closed that pane gives the active editor group the keyboard and says so once": 79, + "Return to current pause pressed in the Study pane in Cursor gives the Application's group the keyboard the closed Study pane had and says so once": 93, + "Return to current pause pressed in the Study pane in VS Code and refused after it closed that pane gives the active editor group the keyboard and says so once": 91, + "Return to current pause pressed in the Study pane in VS Code gives the Application's group the keyboard the closed Study pane had and says so once": 83, + "Study restoration preserves the prior source until delayed text focus clear follows codebook.scopedBrowser activation": 841, + "Study restoration preserves the prior source until delayed text focus clear follows codebook.studyContext activation": 785, + "a Read in a recording and Close Study Workspace leave a side bar the learner had closed as it was": 307, + "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar closed and the secondary one closed": 160, + "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar closed and the secondary one open": 109, + "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar open and the secondary one closed": 113, + "a Read in the live arrangement and its Restore leave the side bars as the learner has them, with the primary side bar open and the secondary one open": 154, + "a Restore after a Read in a live run is confirmed when the editor names another group for a moment while the maximization ends": 179, + "a Restore after a Read in the three-pane Study layout is confirmed when the editor names another group for a moment while the maximization ends": 124, + "a background work window refuses a mode change before native effects": 105, + "a captured-source tab the learner pinned stays open when another run of the same file is shown": 410, + "a close request the editor rejects leaves every tab in place and the selection tells that a dead pane is still open": 108, + "a closed reader behind a focused non-text page of the editor opens when an earlier extension session left a dead Study pane in another group, and that page stays open": 275, + "a closed reader behind a focused non-text page of the editor opens, closes the leftover captured-source tab and keeps that page open behind the Application pane": 290, "a closed reader opens when closing its focused dead Study pane leaves a non-text page of the editor active in the same group": 294, - "a closed reader opens when closing its focused leftover captured-source tab leaves a non-text page of the editor active": 279, - "a dead Codebook pane the editor refuses to close stays in its group while the dead pane of another group closes, and the selection tells why it could not start": 78, - "a draft edited before focus restoration rejects its obsolete reading pose without overwriting the new text": 74, - "a draft edited during native source display rejects its obsolete reading pose without overwriting the new text": 79, - "a draft edited during reading reveal rejects its obsolete reading pose without overwriting the new text": 97, - "a failed mode preference keeps the applied layout and save-only recovery does not move any editor": 419, - "a foreign preview is preserved without Keep Editor or relocation when selecting another presentation": 208, - "a foreign preview opened during the layout read survives without relocation or a saved presentation": 170, - "a learner draft chosen before text focus clear for codebook.scopedBrowser survives the refused Study restoration": 530, - "a learner draft chosen before text focus clear for codebook.studyContext survives the refused Study restoration": 508, - "a learner draft focus during app placement stops later layout work and preserves that focus": 504, - "a learner draft focus during contextPanel placement stops later layout work and preserves that focus": 483, + "a closed reader opens when closing its focused leftover captured-source tab leaves a non-text page of the editor active": 273, + "a dead Codebook pane the editor refuses to close stays in its group while the dead pane of another group closes, and the selection tells why it could not start": 71, + "a draft edited before focus restoration rejects its obsolete reading pose without overwriting the new text": 80, + "a draft edited during native source display rejects its obsolete reading pose without overwriting the new text": 90, + "a draft edited during reading reveal rejects its obsolete reading pose without overwriting the new text": 90, + "a failed mode preference keeps the applied layout and save-only recovery does not move any editor": 377, + "a foreign preview is preserved without Keep Editor or relocation when selecting another presentation": 181, + "a foreign preview opened during the layout read survives without relocation or a saved presentation": 165, + "a learner draft chosen before text focus clear for codebook.scopedBrowser survives the refused Study restoration": 534, + "a learner draft chosen before text focus clear for codebook.studyContext survives the refused Study restoration": 498, + "a learner draft focus during app placement stops later layout work and preserves that focus": 519, + "a learner draft focus during contextPanel placement stops later layout work and preserves that focus": 502, "a learner draft focus while codebook.scopedBrowser activity is delayed stops the transfer and preserves the prior preference": 658, - "a learner draft focus while codebook.studyContext activity is delayed stops the transfer and preserves the prior preference": 635, - "a learner source selection during delayed placement is preserved without later movement or preference changes": 529, - "a learner source selection during final reading restoration survives without a later focus restore": 187, - "a learner who selects another tab while a Restore in a live run ends the maximization keeps that tab and the Restore says so": 434, - "a learner’s Arrange Study Workspace command right after an agent’s Return Current from Cursor’s chat reaches the confirmed live arrangement and gives the chat its keyboard back": 472, - "a learner’s own Study selection gives the keyboard back to the learner’s active file as before and tells nothing": 304, - "a learner’s own Study selection that fails after its placement gives the learner’s file its keyboard back and tells nothing": 189, - "a leftover captured-source tab the editor refuses to close leaves every tab in place and reports why the selection could not start": 111, - "a live selection refused because a tab covers the captured source names that tab": 172, - "a missing explicit replay-focus receipt rejects once without retrying focus or losing retained evidence": 5458, - "a presentation restore during a paused live run, made while the agent chat's tab has the focus in Cursor, confirms the live panes and gives the chat the focus back, with the reader open": 167, - "a presentation restore during a paused live run, made while the chat input has the focus and the editor names a text tab without an active text editor, confirms the live panes and gives the chat the keyboard back, with the reader open": 132, - "a presentation select during a paused live run, made while the agent chat's tab has the focus in Cursor, confirms the live panes and gives the chat the focus back, with the reader closed": 172, - "a presentation select during a paused live run, made while the chat input has the focus and the editor names a text tab without an active text editor, confirms the live panes and gives the chat the keyboard back, with the reader closed": 151, - "a presentation selection keeps the learner’s unedited file preview by pinning it in place and is confirmed": 398, - "a presentation selection made while a tab that is not a text editor has the focus in a group the Study panes use keeps that tab open behind the placed pane": 301, - "a presentation selection made while a tab that is not a text editor has the focus in another group arranges the Study panes and gives that group the focus back, also when the editor replaces every tab group object with each tab change as Cursor does": 292, - "a presentation selection made while a tab that is not a text editor has the focus in another group arranges the Study panes and gives that group the focus back, in an editor that keeps its tab group objects": 314, - "a presentation selection on a closed reader that already owns a live Application panel closes no Codebook pane": 386, - "a presentation selection refused for a preview tab that cannot be pinned names that tab and the step that keeps it": 175, - "a presentation selection refused over a dead Codebook pane is confirmed when it is repeated once the editor lets the pane close": 288, - "a recording opened from Cursor's chat while the Study workspace is open is arranged and confirmed, and the chat gets the keyboard back, while the editor names the captured source": 542, - "a recording opened from Cursor's chat while the Study workspace is open is arranged and confirmed, and the chat gets the keyboard back, while the editor names the chat's group": 329, - "a repeated selection on the confirmed layout of a recording answers confirmed and runs no layout or focus command": 322, - "a restore made from Cursor's chat after the learner resized the panes arranges them again while the editor names the reader's captured source without an active text editor": 499, - "a restore made from Cursor's chat right after its own selection answers the confirmed layout and leaves the keyboard in the chat": 290, - "a restore made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, also when the editor replaces every tab group object with each tab change as Cursor does": 297, - "a restore made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, in an editor that keeps its tab group objects": 279, - "a restore of the live panes that the editor fails after the arrangement took the keyboard, made while the agent chat's tab has the focus in Cursor, gives the chat the keyboard back": 143, - "a run started while the reader shows a saved study is refused before any input and names the return to the current run": 457, - "a second presentation control sent while the leftover captured-source tabs are closing is refused": 408, - "a second selection made from Cursor's chat right after its own selection answers the confirmed layout and leaves the keyboard in the chat": 289, - "a selection after Close Study Workspace during a paused run opens the reader instead of refusing the live layout": 512, - "a selection after a first entry that was refused during a paused run opens the reader in the live arrangement": 143, - "a selection after the learner closed the Application pane does not close this host’s live Study pane": 197, - "a selection behind another workspace’s captured-source tab is refused without the five-second editor wait": 125, - "a selection is confirmed when the editor closes the focused dead pane and keeps a leftover captured-source tab of another group": 386, - "a selection is confirmed when the editor still reports the closed captured source as its text editor for a moment after its Settings page took the tab’s place": 410, - "a selection made from Cursor's chat is arranged when the editor reports the first group's text editor without naming its group, and the chat gets the keyboard back without a new editor group": 312, - "a selection made from the chat beside the debugger's leftover preview tab arranges the Study panes and keeps that tab open": 286, - "a selection made on a closed reader that holds a recording arranges the recording's panes and answers confirmed once the recorded source is shown": 409, - "a selection made on a closed reader whose recording was closed while it was loading reads the recording again and answers confirmed": 368, - "a selection made while another editor part holds the keyboard, in an editor without a command that focuses that part, leaves the focus where the arrangement ended and opens no editor group": 286, - "a selection made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, also when the editor replaces every tab group object with each tab change as Cursor does": 288, - "a selection made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, in an editor that keeps its tab group objects": 292, - "a selection on a closed reader does not close a focused captured-source tab that has a text editor": 400, - "a selection on a reader that opened beside a dead pane the editor kept names that pane, and closes it once the editor lets it": 124, - "a selection refused because the main editor reports no keyboard focus closes the Application pane it opened and gives the chat the keyboard back": 738, - "a selection refused behind another workspace’s captured-source tab closes none of this workspace’s leftover tabs": 96, - "a selection refused for a focused preview tab that is no text editor closes neither the dead pane nor the leftover captured-source tab of an earlier session": 90, - "a selection refused for a preview tab opens no pane and leaves the keyboard focus where it was": 81, - "a selection refused while an image preview has the focus names that tab and how to clear it, on a closed reader": 86, - "a selection refused while an image preview has the focus names that tab and how to clear it, on an open reader": 100, - "a selection still succeeds when the editor reports the next text editor a moment after the leftover tab closed": 504, - "after a cold selection the Application pane is in front of the learner's own file that shares its group, holds the keyboard focus, and that file is still open": 391, - "an agent’s Restore right after its own Return Current from Cursor’s chat reaches the confirmed live arrangement and gives the chat its keyboard back": 292, - "an agent’s Restore right after its own Return Current from VS Code’s chat view reaches the confirmed live arrangement and leaves the keyboard in that view": 498, - "an agent’s Return Current after its Study selection beside two learner groups shows the captured source once, below the Application, and gives the second group its own front tab back (Cursor)": 296, - "an agent’s Return Current after its Study selection beside two learner groups shows the captured source once, below the Application, and gives the second group its own front tab back (VS Code)": 289, - "an agent’s Return Current after its Study selection left the keyboard on the captured source shows the source once and gives the second learner group its front tab back, with the keyboard in the Application’s new group (VS Code)": 300, - "an agent’s Return Current after its Study selection left the keyboard on the captured source shows the source once and gives the second learner group its front tab back, with the keyboard in the captured source below the Application (Cursor)": 312, - "an agent’s Return Current after its own Study selection, made while the chat view has the keyboard, gives no file the keyboard and says once that the Application’s group has it": 294, - "an agent’s Return Current keeps the Study’s copy of the captured source the learner clicked into after the selection, with its keyboard": 274, - "an agent’s Return Current keeps the Study’s copy of the captured source the learner reached by its group’s numbered focus command after going to the chat, with its keyboard": 283, - "an agent’s Return Current that meets a run the reader has not entered yet enters it as the agent’s, giving no file the chat view’s keyboard and saying once that the Application’s group has it": 374, - "an agent’s Return Current while VS Code’s chat editor tab has the keyboard gives that chat tab its keyboard back without saying that the Application’s group has it": 281, - "an agent’s Return Current while the Study workspace is closed answers the closed reader following the current run, and the agent’s select then opens the Study following it": 283, - "an agent’s Return Current whose live arrangement covers the group of VS Code’s chat editor tab says once that the Application’s group has the keyboard": 289, - "an agent’s Study selection made from VS Code’s chat editor tab in a floating window gives that chat its keyboard back and says once that a file of the main editor had it for a moment": 277, - "an agent’s Study selection made while the chat view has the keyboard gives no learner’s file the keyboard and says once that the captured source has it": 275, - "an agent’s Study selection right after a reload while the chat view has the keyboard focuses no editor group afterwards and says once that the captured source has it": 283, - "an agent’s Study selection that covers the group of VS Code’s chat editor tab says once that the captured source has the keyboard": 306, - "an agent’s Study selection that fails after its placement while the Application pane has the keyboard gives no learner’s file the keyboard and says once that the Application pane has it": 198, - "an agent’s Study selection that fails after its placement while the Study pane has the keyboard gives no learner’s file the keyboard and says once that the Study pane has it": 191, - "an agent’s Study selection that fails after its placement while the captured source has the keyboard gives no learner’s file the keyboard and says once that the captured source has it": 179, - "an agent’s cold Study selection during a paused live run made while Cursor’s chat tab has the keyboard confirms the live panes and gives the chat its keyboard back": 130, - "an agent’s cold Study selection made while Cursor’s chat tab has the keyboard shows no learner file with the keyboard, borrows the first group for one measurement only and says once that the chat got the keyboard back": 119, - "an agent’s run started right after its own Study selection, while the chat view has the keyboard, enters Live with no file given the keyboard and says once that the Application’s group has it": 334, - "an unchanged learner draft restores its reading pose and remains dirty": 86, - "an unknown presentation preference survives opening until an explicit replacement": 384, - "beside VS Code’s floating window, an agent’s Study selection refused right after its borrow while the Application pane had the keyboard gives the Application pane its keyboard back and names that pane, not a file": 597, - "beside VS Code’s floating window, an agent’s Study selection refused right after its borrow while the Study pane had the keyboard gives the Study pane its keyboard back and names that pane, not a file": 604, - "beside VS Code’s floating window, an agent’s cold Study selection refused for the learner’s change of the first group’s file after its borrow gives no keyboard back and tells nothing": 125, - "clearing the last text editor during codebook.scopedBrowser reading restoration preserves confirmed native focus": 701, - "clearing the last text editor during codebook.studyContext reading restoration preserves confirmed native focus": 699, - "closing the reader while a selection waits for the editor after closing a leftover tab ends the selection at once and opens no pane": 103, - "cold prepared Study preserves Close while its preference write drains": 72, - "cold prepared Study preserves new source while its preference write drains": 83, - "editor AI can return a saved recording to its current run without repeating application input or losing history": 448, - "in Cursor beside its chat part, an agent’s Study selection made while a learner’s file is the active text editor gives that file nothing back and says once that the captured source has the keyboard": 293, - "in Cursor beside its chat part, an agent’s cold Study selection during a paused run, made while the learner types in a file of the second group under the chat part’s group name, inserts the Application’s group and gives that file its keyboard back": 136, - "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab after the learner’s click into the first group’s file after its borrow is confirmed, keeps the keyboard there, gives the chat nothing and tells nothing": 138, - "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused after its borrow and the Application group’s insertion gives the chat its keyboard back and says that nothing was arranged": 122, - "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused after the learner chose another tab of the first group leaves that tab the keyboard and gives the chat none": 152, - "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused for the learner’s change of the first group’s file during its layout read gives the chat no keyboard and tells nothing": 136, - "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused for the learner’s tab of the first group chosen during its layout read leaves that tab the keyboard and gives the chat none": 177, - "in Cursor beside its chat part, an agent’s cold Study selection made while the learner types in a file of the second group under the chat part’s group name completes and leaves the keyboard on no page body": 293, - "in Cursor beside its chat part, an agent’s cold Study selection refused after its borrow and the Application group’s insertion gives the file the editor reported its keyboard back and says so once, when the learner was not known to type there": 120, - "in Cursor beside its chat part, an agent’s cold Study selection refused after its borrow and the Application group’s insertion gives the file the learner typed in its keyboard back": 112, - "in Cursor beside its chat part, an agent’s cold Study selection refused after its borrow and the Application group’s insertion leaves the keyboard in the first group’s tab the learner chose meanwhile": 139, - "in Cursor beside its chat part, an agent’s restore of the confirmed live arrangement from the chat tab borrows through the captured source, is confirmed and gives the chat its keyboard back": 138, - "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab confirmed after the learner clicked into the captured source after its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 148, - "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab refused for the learner’s click in the captured source during its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 127, - "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab refused for the learner’s file opened in the first group after its borrow gives the chat no keyboard and tells nothing": 143, - "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab refused right after its borrow gives the chat its keyboard back and says that nothing was arranged": 157, - "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab that fails after the learner clicked into the captured source after its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 136, - "in Cursor, a learner’s cold Study selection after a reload is still refused when the learner closes the file it would give its focus back to while its layout command waits": 211, - "in Cursor, an agent’s cold Study selection after a reload whose learner had the keyboard in the group behind the earlier window’s leftover retires the leftover and confirms the Study layout": 287, - "in VS Code, an agent’s cold Study selection after a reload whose learner had the keyboard in the group behind the earlier window’s leftover retires the leftover and confirms the Study layout": 288, - "leaving the native work window during presentation preserves the prior preference without recovering focus": 77, - "manual resume during presentation layout application cannot certify or save a different live state": 169, - "manual resume during presentation layout read cannot certify or save a different live state": 147, - "mode selection rejects missing inner focus instead of treating native tab activation as success": 5215, - "mode transfer confirms codebook.scopedBrowser focus while VS Code retains its most recent text editor": 488, - "mode transfer confirms codebook.studyContext focus while VS Code retains its most recent text editor": 498, - "mode transfer waits for replacement-pane registration before treating the new grid as a stable learner arrangement": 508, - "moving a presentation retains both measured axes when native pane creation flattens the grid": 388, - "native activation preparation completes while ownership remains held": 705, - "native activation preparation preserves learner departure and reentry without a late focus commit": 543, - "native activation preparation preserves learner original source without a late focus commit": 552, - "native activation preparation preserves learner same-group tab roundtrip without a late focus commit": 568, - "ordinary chat opens a closed guided-walkthrough through MCP without starting execution or changing learner work": 311, - "ordinary chat opens a closed living-book through MCP without starting execution or changing learner work": 317, - "ordinary chat opens a closed study-workspace through MCP without starting execution or changing learner work": 364, - "presentation cannot save its mode from a stale reading restoration receipt": 394, - "presentation layout read preserves a later learner focus change without saving the mode": 187, - "presentation layout read preserves a later learner pane movement without saving the mode": 184, - "presentation post-move layout response completes the unchanged reading pose": 379, - "presentation post-move layout response preserves a newer source selection and viewport before further effects": 187, - "presentation source acquisition continues after unchanged native display": 274, - "presentation source acquisition preserves a newer selection before the display response": 206, - "presentation source acquisition restores every original selection after the owned native response": 319, - "presentation source acquisition with a closed source tab continues after unchanged native display": 386, - "presentation source acquisition with a closed source tab preserves a newer selection before the display response": 190, - "real MCP presentation discovery and control preserve identities across response loss and reject stale clients": 326, - "reselecting a confirmed presentation clears a stale control warning and keeps the selector usable": 487, - "restoring layout during a late replay image retains the current frame and lets the requested seek finish": 489, - "restoring replay preserves a learner draft opened over historical source during layout measurement": 369, - "same-mode selection keeps its revision only while the actual native layout is still confirmed": 698, - "selecting a presentation on a closed reader closes a leftover captured-source tab that has no text editor and keeps the learner’s own tab": 380, - "selecting a presentation on an open reader whose focused captured-source tab has no text editor closes none of its captured-source tabs": 104, - "source-group opened replacement during pane movement invalidates presentation ownership": 591, - "source-group unannounced replacement during pane movement invalidates presentation ownership": 629, - "source-group wrapper replacement during pane movement retains presentation ownership": 786, - "switching presentation waits for restored application focus before confirming the new mode": 420, - "the answer to a selection made from Cursor's chat input reads the layout as confirmed and says that the grid was not measured again": 281, - "the extension README gives the refusal for a dead pane that stays open and both causes word for word": 1, - "the first presentation select during a paused live run with the reader closed arranges the live panes and answers a confirmed layout": 131, - "the first presentation selection after an extension-host restart asks the editor to close the old host’s dead Study pane and no other tab": 399, - "the first presentation selection after an extension-host restart closes the old host’s dead Application and Study panes and is confirmed": 331, - "the first presentation selection after an extension-host restart closes the old host’s dead Repository Wiki pane that had focus": 399, - "the first presentation selection closes a dead Application pane together with the focused leftover captured-source tab": 338, + "a learner draft focus while codebook.studyContext activity is delayed stops the transfer and preserves the prior preference": 616, + "a learner source selection during delayed placement is preserved without later movement or preference changes": 513, + "a learner source selection during final reading restoration survives without a later focus restore": 214, + "a learner who selects another tab while a Restore in a live run ends the maximization keeps that tab and the Restore says so": 422, + "a learner’s Arrange Study Workspace command right after an agent’s Return Current from Cursor’s chat reaches the confirmed live arrangement and gives the chat its keyboard back": 290, + "a learner’s own Study selection gives the keyboard back to the learner’s active file as before and tells nothing": 289, + "a learner’s own Study selection that fails after its placement gives the learner’s file its keyboard back and tells nothing": 181, + "a leftover captured-source tab the editor refuses to close leaves every tab in place and reports why the selection could not start": 63, + "a live selection refused because a tab covers the captured source names that tab": 161, + "a missing explicit replay-focus receipt rejects once without retrying focus or losing retained evidence": 5466, + "a presentation restore during a paused live run, made while the agent chat's tab has the focus in Cursor, confirms the live panes and gives the chat the focus back, with the reader open": 127, + "a presentation restore during a paused live run, made while the chat input has the focus and the editor names a text tab without an active text editor, confirms the live panes and gives the chat the keyboard back, with the reader open": 115, + "a presentation select during a paused live run, made while the agent chat's tab has the focus in Cursor, confirms the live panes and gives the chat the focus back, with the reader closed": 221, + "a presentation select during a paused live run, made while the chat input has the focus and the editor names a text tab without an active text editor, confirms the live panes and gives the chat the keyboard back, with the reader closed": 128, + "a presentation selection keeps the learner’s unedited file preview by pinning it in place and is confirmed": 372, + "a presentation selection made while a tab that is not a text editor has the focus in a group the Study panes use keeps that tab open behind the placed pane": 339, + "a presentation selection made while a tab that is not a text editor has the focus in another group arranges the Study panes and gives that group the focus back, also when the editor replaces every tab group object with each tab change as Cursor does": 282, + "a presentation selection made while a tab that is not a text editor has the focus in another group arranges the Study panes and gives that group the focus back, in an editor that keeps its tab group objects": 282, + "a presentation selection on a closed reader that already owns a live Application panel closes no Codebook pane": 408, + "a presentation selection refused for a preview tab that cannot be pinned names that tab and the step that keeps it": 174, + "a presentation selection refused over a dead Codebook pane is confirmed when it is repeated once the editor lets the pane close": 270, + "a recording opened from Cursor's chat while the Study workspace is open is arranged and confirmed, and the chat gets the keyboard back, while the editor names the captured source": 507, + "a recording opened from Cursor's chat while the Study workspace is open is arranged and confirmed, and the chat gets the keyboard back, while the editor names the chat's group": 391, + "a repeated selection on the confirmed layout of a recording answers confirmed and runs no layout or focus command": 277, + "a restore made from Cursor's chat after the learner resized the panes arranges them again while the editor names the reader's captured source without an active text editor": 529, + "a restore made from Cursor's chat right after its own selection answers the confirmed layout and leaves the keyboard in the chat": 324, + "a restore made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, also when the editor replaces every tab group object with each tab change as Cursor does": 286, + "a restore made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, in an editor that keeps its tab group objects": 293, + "a restore of the live panes that the editor fails after the arrangement took the keyboard, made while the agent chat's tab has the focus in Cursor, gives the chat the keyboard back": 147, + "a run started while the reader shows a saved study is refused before any input and names the return to the current run": 489, + "a second presentation control sent while the leftover captured-source tabs are closing is refused": 396, + "a second selection made from Cursor's chat right after its own selection answers the confirmed layout and leaves the keyboard in the chat": 307, + "a selection after Close Study Workspace during a paused run opens the reader instead of refusing the live layout": 491, + "a selection after a first entry that was refused during a paused run opens the reader in the live arrangement": 122, + "a selection after the learner closed the Application pane does not close this host’s live Study pane": 173, + "a selection behind another workspace’s captured-source tab is refused without the five-second editor wait": 70, + "a selection is confirmed when the editor closes the focused dead pane and keeps a leftover captured-source tab of another group": 419, + "a selection is confirmed when the editor still reports the closed captured source as its text editor for a moment after its Settings page took the tab’s place": 387, + "a selection made from Cursor's chat is arranged when the editor reports the first group's text editor without naming its group, and the chat gets the keyboard back without a new editor group": 310, + "a selection made from the chat beside the debugger's leftover preview tab arranges the Study panes and keeps that tab open": 279, + "a selection made on a closed reader that holds a recording arranges the recording's panes and answers confirmed once the recorded source is shown": 536, + "a selection made on a closed reader whose recording was closed while it was loading reads the recording again and answers confirmed": 348, + "a selection made while another editor part holds the keyboard, in an editor without a command that focuses that part, leaves the focus where the arrangement ended and opens no editor group": 310, + "a selection made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, also when the editor replaces every tab group object with each tab change as Cursor does": 296, + "a selection made while the chat input has the focus and the editor names a text tab without an active text editor arranges the Study panes and closes or moves no tab, in an editor that keeps its tab group objects": 270, + "a selection on a closed reader does not close a focused captured-source tab that has a text editor": 393, + "a selection on a reader that opened beside a dead pane the editor kept names that pane, and closes it once the editor lets it": 74, + "a selection refused because the main editor reports no keyboard focus closes the Application pane it opened and gives the chat the keyboard back": 649, + "a selection refused behind another workspace’s captured-source tab closes none of this workspace’s leftover tabs": 98, + "a selection refused for a focused preview tab that is no text editor closes neither the dead pane nor the leftover captured-source tab of an earlier session": 92, + "a selection refused for a preview tab opens no pane and leaves the keyboard focus where it was": 67, + "a selection refused while an image preview has the focus names that tab and how to clear it, on a closed reader": 105, + "a selection refused while an image preview has the focus names that tab and how to clear it, on an open reader": 97, + "a selection still succeeds when the editor reports the next text editor a moment after the leftover tab closed": 492, + "after a cold selection the Application pane is in front of the learner's own file that shares its group, holds the keyboard focus, and that file is still open": 375, + "an agent’s Restore right after its own Return Current from Cursor’s chat reaches the confirmed live arrangement and gives the chat its keyboard back": 300, + "an agent’s Restore right after its own Return Current from VS Code’s chat view reaches the confirmed live arrangement and leaves the keyboard in that view": 294, + "an agent’s Return Current after its Study selection beside two learner groups shows the captured source once, below the Application, and gives the second group its own front tab back (Cursor)": 426, + "an agent’s Return Current after its Study selection beside two learner groups shows the captured source once, below the Application, and gives the second group its own front tab back (VS Code)": 316, + "an agent’s Return Current after its Study selection left the keyboard on the captured source shows the source once and gives the second learner group its front tab back, with the keyboard in the Application’s new group (VS Code)": 330, + "an agent’s Return Current after its Study selection left the keyboard on the captured source shows the source once and gives the second learner group its front tab back, with the keyboard in the captured source below the Application (Cursor)": 806, + "an agent’s Return Current after its own Study selection, made while the chat view has the keyboard, gives no file the keyboard and says once that the Application’s group has it": 297, + "an agent’s Return Current keeps the Study’s copy of the captured source the learner clicked into after the selection, with its keyboard": 281, + "an agent’s Return Current keeps the Study’s copy of the captured source the learner reached by its group’s numbered focus command after going to the chat, with its keyboard": 339, + "an agent’s Return Current that meets a run the reader has not entered yet enters it as the agent’s, giving no file the chat view’s keyboard and saying once that the Application’s group has it": 326, + "an agent’s Return Current while VS Code’s chat editor tab has the keyboard gives that chat tab its keyboard back without saying that the Application’s group has it": 286, + "an agent’s Return Current while the Study workspace is closed answers the closed reader following the current run, and the agent’s select then opens the Study following it": 288, + "an agent’s Return Current whose live arrangement covers the group of VS Code’s chat editor tab says once that the Application’s group has the keyboard": 312, + "an agent’s Study selection made from VS Code’s chat editor tab in a floating window gives that chat its keyboard back and says once that a file of the main editor had it for a moment": 290, + "an agent’s Study selection made while the chat view has the keyboard gives no learner’s file the keyboard and says once that the captured source has it": 279, + "an agent’s Study selection right after a reload while the chat view has the keyboard focuses no editor group afterwards and says once that the captured source has it": 297, + "an agent’s Study selection that covers the group of VS Code’s chat editor tab says once that the captured source has the keyboard": 269, + "an agent’s Study selection that fails after its placement while the Application pane has the keyboard gives no learner’s file the keyboard and says once that the Application pane has it": 184, + "an agent’s Study selection that fails after its placement while the Study pane has the keyboard gives no learner’s file the keyboard and says once that the Study pane has it": 171, + "an agent’s Study selection that fails after its placement while the captured source has the keyboard gives no learner’s file the keyboard and says once that the captured source has it": 166, + "an agent’s cold Study selection during a paused live run made while Cursor’s chat tab has the keyboard confirms the live panes and gives the chat its keyboard back": 122, + "an agent’s cold Study selection made while Cursor’s chat tab has the keyboard shows no learner file with the keyboard, borrows the first group for one measurement only and says once that the chat got the keyboard back": 139, + "an agent’s run started right after its own Study selection, while the chat view has the keyboard, enters Live with no file given the keyboard and says once that the Application’s group has it": 336, + "an unchanged learner draft restores its reading pose and remains dirty": 69, + "an unknown presentation preference survives opening until an explicit replacement": 370, + "beside VS Code’s floating window, an agent’s Study selection refused right after its borrow while the Application pane had the keyboard gives the Application pane its keyboard back and names that pane, not a file": 600, + "beside VS Code’s floating window, an agent’s Study selection refused right after its borrow while the Study pane had the keyboard gives the Study pane its keyboard back and names that pane, not a file": 602, + "beside VS Code’s floating window, an agent’s cold Study selection refused for the learner’s change of the first group’s file after its borrow gives no keyboard back and tells nothing": 123, + "clearing the last text editor during codebook.scopedBrowser reading restoration preserves confirmed native focus": 718, + "clearing the last text editor during codebook.studyContext reading restoration preserves confirmed native focus": 722, + "closing the reader while a selection waits for the editor after closing a leftover tab ends the selection at once and opens no pane": 130, + "cold prepared Study preserves Close while its preference write drains": 115, + "cold prepared Study preserves new source while its preference write drains": 75, + "editor AI can return a saved recording to its current run without repeating application input or losing history": 392, + "in Cursor beside its chat part, an agent’s Study selection made while a learner’s file is the active text editor gives that file nothing back and says once that the captured source has the keyboard": 287, + "in Cursor beside its chat part, an agent’s cold Study selection during a paused run, made while the learner types in a file of the second group under the chat part’s group name, inserts the Application’s group and gives that file its keyboard back": 130, + "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab after the learner’s click into the first group’s file after its borrow is confirmed, keeps the keyboard there, gives the chat nothing and tells nothing": 125, + "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused after its borrow and the Application group’s insertion gives the chat its keyboard back and says that nothing was arranged": 132, + "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused after the learner chose another tab of the first group leaves that tab the keyboard and gives the chat none": 107, + "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused for the learner’s change of the first group’s file during its layout read gives the chat no keyboard and tells nothing": 126, + "in Cursor beside its chat part, an agent’s cold Study selection from the chat tab refused for the learner’s tab of the first group chosen during its layout read leaves that tab the keyboard and gives the chat none": 130, + "in Cursor beside its chat part, an agent’s cold Study selection made while the learner types in a file of the second group under the chat part’s group name completes and leaves the keyboard on no page body": 288, + "in Cursor beside its chat part, an agent’s cold Study selection refused after its borrow and the Application group’s insertion gives the file the editor reported its keyboard back and says so once, when the learner was not known to type there": 112, + "in Cursor beside its chat part, an agent’s cold Study selection refused after its borrow and the Application group’s insertion gives the file the learner typed in its keyboard back": 161, + "in Cursor beside its chat part, an agent’s cold Study selection refused after its borrow and the Application group’s insertion leaves the keyboard in the first group’s tab the learner chose meanwhile": 147, + "in Cursor beside its chat part, an agent’s restore of the confirmed live arrangement from the chat tab borrows through the captured source, is confirmed and gives the chat its keyboard back": 142, + "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab confirmed after the learner clicked into the captured source after its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 123, + "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab refused for the learner’s click in the captured source during its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 114, + "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab refused for the learner’s file opened in the first group after its borrow gives the chat no keyboard and tells nothing": 109, + "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab refused right after its borrow gives the chat its keyboard back and says that nothing was arranged": 133, + "in Cursor beside its chat part, an agent’s restore of the live arrangement from the chat tab that fails after the learner clicked into the captured source after its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 144, + "in Cursor, a learner’s cold Study selection after a reload is still refused when the learner closes the file it would give its focus back to while its layout command waits": 178, + "in Cursor, an agent’s cold Study selection after a reload whose learner had the keyboard in the group behind the earlier window’s leftover retires the leftover and confirms the Study layout": 284, + "in VS Code, an agent’s cold Study selection after a reload whose learner had the keyboard in the group behind the earlier window’s leftover retires the leftover and confirms the Study layout": 281, + "leaving the native work window during presentation preserves the prior preference without recovering focus": 90, + "manual resume during presentation layout application cannot certify or save a different live state": 154, + "manual resume during presentation layout read cannot certify or save a different live state": 138, + "mode selection rejects missing inner focus instead of treating native tab activation as success": 5229, + "mode transfer confirms codebook.scopedBrowser focus while VS Code retains its most recent text editor": 516, + "mode transfer confirms codebook.studyContext focus while VS Code retains its most recent text editor": 477, + "mode transfer waits for replacement-pane registration before treating the new grid as a stable learner arrangement": 524, + "moving a presentation retains both measured axes when native pane creation flattens the grid": 380, + "native activation preparation completes while ownership remains held": 1007, + "native activation preparation preserves learner departure and reentry without a late focus commit": 582, + "native activation preparation preserves learner original source without a late focus commit": 583, + "native activation preparation preserves learner same-group tab roundtrip without a late focus commit": 668, + "ordinary chat opens a closed guided-walkthrough through MCP without starting execution or changing learner work": 307, + "ordinary chat opens a closed living-book through MCP without starting execution or changing learner work": 322, + "ordinary chat opens a closed study-workspace through MCP without starting execution or changing learner work": 362, + "presentation cannot save its mode from a stale reading restoration receipt": 435, + "presentation layout read preserves a later learner focus change without saving the mode": 172, + "presentation layout read preserves a later learner pane movement without saving the mode": 196, + "presentation post-move layout response completes the unchanged reading pose": 377, + "presentation post-move layout response preserves a newer source selection and viewport before further effects": 173, + "presentation source acquisition continues after unchanged native display": 280, + "presentation source acquisition preserves a newer selection before the display response": 176, + "presentation source acquisition restores every original selection after the owned native response": 285, + "presentation source acquisition with a closed source tab continues after unchanged native display": 372, + "presentation source acquisition with a closed source tab preserves a newer selection before the display response": 180, + "real MCP presentation discovery and control preserve identities across response loss and reject stale clients": 312, + "reselecting a confirmed presentation clears a stale control warning and keeps the selector usable": 441, + "restoring layout during a late replay image retains the current frame and lets the requested seek finish": 463, + "restoring replay preserves a learner draft opened over historical source during layout measurement": 412, + "same-mode selection keeps its revision only while the actual native layout is still confirmed": 690, + "selecting a presentation on a closed reader closes a leftover captured-source tab that has no text editor and keeps the learner’s own tab": 385, + "selecting a presentation on an open reader whose focused captured-source tab has no text editor closes none of its captured-source tabs": 114, + "source-group opened replacement during pane movement invalidates presentation ownership": 571, + "source-group unannounced replacement during pane movement invalidates presentation ownership": 593, + "source-group wrapper replacement during pane movement retains presentation ownership": 818, + "switching presentation waits for restored application focus before confirming the new mode": 404, + "the answer to a selection made from Cursor's chat input reads the layout as confirmed and says that the grid was not measured again": 286, + "the extension README gives the refusal for a dead pane that stays open and both causes word for word": 0, + "the first presentation select during a paused live run with the reader closed arranges the live panes and answers a confirmed layout": 108, + "the first presentation selection after an extension-host restart asks the editor to close the old host’s dead Study pane and no other tab": 396, + "the first presentation selection after an extension-host restart closes the old host’s dead Application and Study panes and is confirmed": 327, + "the first presentation selection after an extension-host restart closes the old host’s dead Repository Wiki pane that had focus": 452, + "the first presentation selection closes a dead Application pane together with the focused leftover captured-source tab": 322, "the first presentation selection closes the dead Application panes that two earlier extension hosts left in one window": 285, - "the first presentation selection closes the old host’s dead panes when a run created this host’s Application panel before the reader was opened": 87, - "the first presentation selection is confirmed when the old host’s dead Study pane had focus and no text editor was active": 290, - "the first presentation selection keeps this host’s live Repository Wiki pane while it closes the old host’s dead Application pane": 317, - "the first presentation selection on a closed reader is confirmed when the learner’s focused file is in the source column, and that file stays open behind the captured source": 281, - "the first presentation selection on an open reader is confirmed when the learner’s focused file is in the source column, and that file stays open behind the captured source": 291, - "the first presentation selection places its panes after closing the dead Application pane removed the first editor group": 400, + "the first presentation selection closes the old host’s dead panes when a run created this host’s Application panel before the reader was opened": 73, + "the first presentation selection is confirmed when the old host’s dead Study pane had focus and no text editor was active": 275, + "the first presentation selection keeps this host’s live Repository Wiki pane while it closes the old host’s dead Application pane": 281, + "the first presentation selection on a closed reader is confirmed when the learner’s focused file is in the source column, and that file stays open behind the captured source": 297, + "the first presentation selection on an open reader is confirmed when the learner’s focused file is in the source column, and that file stays open behind the captured source": 278, + "the first presentation selection places its panes after closing the dead Application pane removed the first editor group": 413, "the learner’s Arrange Study Workspace command run from VS Code’s chat view right after an agent’s Return Current reaches the confirmed live arrangement and leaves the keyboard in that view": 289, - "the learner’s Open Study Workspace after an agent’s Study selection left the keyboard on the captured source and a run started shows the run’s source once, below the Application, and gives the second learner group its front tab back (Cursor)": 325, - "the learner’s Open Study Workspace after an agent’s Study selection left the keyboard on the captured source and a run started shows the run’s source once, below the Application, and gives the second learner group its front tab back (VS Code)": 325, - "the learner’s Restore run beside Cursor’s chat part from a Study view right after an agent’s Return Current reaches the confirmed live arrangement, gives the chat its keyboard back and has told once where the keyboard is": 313, - "the learner’s Restore run beside Cursor’s chat part from the terminal right after an agent’s Return Current reaches the confirmed live arrangement, gives the chat its keyboard back and has told once where the keyboard is": 282, - "the learner’s Return to current pause from the Study pane that meets a run the reader has not entered yet enters it as the learner’s and tells only the learner’s sentence": 181, - "the leftover captured-source tab is closed on a reader that has not loaded its library yet": 401, - "the presentation resource offers only layouts a select accepts: Study workspace, and a retired layout only while the reader is in it (reader in living-book)": 70, - "the presentation resource offers only layouts a select accepts: Study workspace, and a retired layout only while the reader is in it (reader in study-workspace)": 77, - "the reader’s own Live entry of the agent’s run after an agent’s Study selection left the keyboard on the captured source and a run started shows the run’s source once, below the Application, and gives the second learner group its front tab back (Cursor)": 338, - "the reason of a refused selection is gone from the presentation state once the layout is confirmed": 83, - "the reentry's focus of the captured source below the Application, in place of the copy it retires, is no learner's move, so an agent's next request reads the learner's place as unknown": 338, - "the refusal of a selection on a reader whose recording failed to load names that failure and the step that loads the recording again": 263 + "the learner’s Open Study Workspace after an agent’s Study selection left the keyboard on the captured source and a run started shows the run’s source once, below the Application, and gives the second learner group its front tab back (Cursor)": 385, + "the learner’s Open Study Workspace after an agent’s Study selection left the keyboard on the captured source and a run started shows the run’s source once, below the Application, and gives the second learner group its front tab back (VS Code)": 385, + "the learner’s Restore run beside Cursor’s chat part from a Study view right after an agent’s Return Current reaches the confirmed live arrangement, gives the chat its keyboard back and has told once where the keyboard is": 284, + "the learner’s Restore run beside Cursor’s chat part from the terminal right after an agent’s Return Current reaches the confirmed live arrangement, gives the chat its keyboard back and has told once where the keyboard is": 304, + "the learner’s Return to current pause from the Study pane that meets a run the reader has not entered yet enters it as the learner’s and tells only the learner’s sentence": 177, + "the leftover captured-source tab is closed on a reader that has not loaded its library yet": 369, + "the presentation resource offers only layouts a select accepts: Study workspace, and a retired layout only while the reader is in it (reader in living-book)": 82, + "the presentation resource offers only layouts a select accepts: Study workspace, and a retired layout only while the reader is in it (reader in study-workspace)": 79, + "the reader’s own Live entry of the agent’s run after an agent’s Study selection left the keyboard on the captured source and a run started shows the run’s source once, below the Application, and gives the second learner group its front tab back (Cursor)": 367, + "the reason of a refused selection is gone from the presentation state once the layout is confirmed": 81, + "the reentry's focus of the captured source below the Application, in place of the copy it retires, is no learner's move, so an agent's next request reads the learner's place as unknown": 359, + "the refusal of a selection on a reader whose recording failed to load names that failure and the step that loads the recording again": 266 } }, "studyWorkspaceRemoval.test.js": { - "totalMs": 49781, + "totalMs": 48594, "tests": { - "Cancel in the dialog about a listed run’s recording that names another host moves nothing, and the entry stays listed": 118, - "Cancel in the dialog about a recording that a live process of this computer begun after it may still write moves nothing and leaves the study as it was": 172, - "Cancel in the dialog about a recording that names another host moves nothing and leaves the study as it was": 116, - "Save learning replay pressed while its study is being moved to the Trash is refused and the removal completes": 191, - "a Node test history chosen and shown while a removal moves files stays shown, and the neighbour is never read": 200, - "a Node test history chosen during Recording is refused with its sentence and its pane is told that the request ended": 475, - "a Node test history opened while the neighbour of a removed study is being read keeps the source it showed": 257, - "a Node test history that is still opening when a removal settles is shown instead of the neighbour": 227, - "a Retry storage / refresh pressed while a study whose archive still waits is on its way to the Trash does not retire the line during the move, and when the Trash refuses the move the line and Retry are there for the archive that still waits": 387, - "a Retry storage / refresh that saved the earlier study keeps the line “History not saved: …” and Retry beside it when a run that started during the Retry could not be saved": 343, - "a Retry storage / refresh that writes one of two studies whose saves failed leaves the line and Retry for the other, and the Retry that writes that one leaves no line": 244, + "Cancel in the dialog about a listed run’s recording that names another host moves nothing, and the entry stays listed": 117, + "Cancel in the dialog about a recording that a live process of this computer begun after it may still write moves nothing and leaves the study as it was": 143, + "Cancel in the dialog about a recording that names another host moves nothing and leaves the study as it was": 166, + "Save learning replay pressed while its study is being moved to the Trash is refused and the removal completes": 223, + "a Node test history chosen and shown while a removal moves files stays shown, and the neighbour is never read": 193, + "a Node test history chosen during Recording is refused with its sentence and its pane is told that the request ended": 432, + "a Node test history opened while the neighbour of a removed study is being read keeps the source it showed": 221, + "a Node test history that is still opening when a removal settles is shown instead of the neighbour": 208, + "a Retry storage / refresh pressed while a study whose archive still waits is on its way to the Trash does not retire the line during the move, and when the Trash refuses the move the line and Retry are there for the archive that still waits": 350, + "a Retry storage / refresh that saved the earlier study keeps the line “History not saved: …” and Retry beside it when a run that started during the Retry could not be saved": 230, + "a Retry storage / refresh that writes one of two studies whose saves failed leaves the line and Retry for the other, and the Retry that writes that one leaves no line": 274, "a Retry storage / refresh whose selection names a study without an archive shows “Study archive is unavailable.” once and keeps Retry offered": 188, - "a Retry storage / refresh whose write of a waiting archive fails shows the line “History not saved: …” once, with its sentence": 184, - "a Save learning replay that is capturing its study when the removal is confirmed is answered as unavailable, and the removal moves the study without it being written back": 218, - "a Save learning replay that is still stopping the run when its study’s removal is confirmed is answered as unavailable, and the removal completes": 269, - "a Save learning replay that is writing its study when the removal is confirmed is answered as unavailable, and the removal completes after that write": 376, - "a Save learning replay that was capturing its study when a removal that moved nothing was confirmed is answered as unavailable, and its capture is written once that removal has ended": 287, - "a Stop whose last checkpoint cannot be written stops the run without failing and tells it once, in the line “History not saved: …” that Retry storage / refresh answers, and the Retry that saves the study leaves no line": 868, - "a Stop whose last checkpoint fails before anything is written stops the run without failing and tells it in the line “History not saved: …” that Retry storage / refresh answers, not in a control line": 146, - "a checkpoint taken while a recorded run’s stop is under way after the seal keeps the recording’s writer record, and the checkpoint taken after the stop gives it up": 327, - "a checkpoint that waited behind a write during a removal that moved nothing is written afterwards without another trigger": 287, - "a checkpoint that waits behind a write in flight is not written once the removal of its study is confirmed": 290, - "a checkpoint that was capturing a study when its removal was confirmed writes nothing for it afterwards": 279, - "a choice overtaken by a newer saved study adds no failure line when its own archive read fails afterwards, and the newer study stays shown": 207, - "a choice overtaken in the bottom panel of a closed Study workspace leaves the newer choice loading until that study is shown": 336, - "a choice whose request number is zero or a text is rejected as an unsupported message and is not answered": 263, - "a chosen Node test history whose open is discarded because the reader changed meanwhile stops loading": 319, - "a chosen saved study sent without a request number opens and no reply is posted": 256, - "a chosen saved study that opens is shown and its pane is told that the request ended": 194, - "a chosen saved study whose archive read fails after the Study workspace was closed adds no reading or storage line": 161, - "a chosen saved study whose archive read fails after the reader changed meanwhile leaves the earlier study shown without a storage failure line, and a delete request is asked": 288, - "a chosen saved study whose arrangement is refused after its archive was read stops loading and names the reason": 171, - "a chosen saved study whose open is discarded because the reader changed meanwhile leaves the earlier study shown and a delete request asked": 282, - "a confirmation dialog the editor cannot show moves nothing, and the next delete request is asked and carried out": 146, - "a confirmed removal also moves the raw evidence directory of the study’s run from the agent storage to the Trash": 85, - "a confirmed removal moves the study to the Trash, shows the next older study and reports the room in the library": 212, - "a delete request for another saved study while one is being moved to the Trash opens no dialog and leaves that study in place": 125, - "a delete request refused twice with the same sentence is answered with each request’s own number": 70, - "a delete request that carries the revision of an earlier view is rejected with the stale-view sentence, asks nothing and moves nothing": 212, - "a delete request while a chosen Node test history is still opening is refused with the same sentence, and is asked and carried out once the history has opened": 180, - "a delete request while a chosen saved study is still opening is refused with its own sentence and opens no dialog": 169, - "a delete request whose id is not a study identity is rejected as an unsupported message and moves nothing": 95, - "a dialog about a recording on another computer that the editor cannot show ends the removal with no line, and the study stays listed": 111, - "a forced checkpoint of a study whose files have moved ends while the study that follows is still being read": 277, - "a forced checkpoint that was capturing a study when its removal was confirmed is written once that removal moved nothing": 268, - "a newer choice that fails to open while the neighbour of a removed study is being read leaves the reader with no study selected": 183, - "a playback position save queued before a removal settles before the first move, and none is written for the removed study afterwards": 421, - "a playback position save queued while the dialog about a recording on another computer is open settles before the first move after Move to Trash Anyway": 391, - "a reader closed while the neighbour of the removed study of a finished live run is being read stays closed, and the neighbour is remembered": 203, - "a reader refresh while the admission of a run is still being read saves nothing and queues nothing": 130, - "a reader that is still closing when the neighbour of a removed study has been read remembers the neighbour": 160, - "a reader that starts with a study of a newer Codebook as its newest entry shows the newest study it can read, without a storage line": 114, - "a reader that starts with what is left of a study without its archive as its newest entry shows the newest study it can read, without a storage line": 133, - "a reader that starts with what is left of a study without its archive as its saved selection shows the newest study it can read, without a storage line": 152, - "a recorded run whose release fails after the seal gives up its recording’s writer record with the save of the checkpoint taken after that stop, and not with the save of one taken before the seal": 284, + "a Retry storage / refresh whose write of a waiting archive fails shows the line “History not saved: …” once, with its sentence": 218, + "a Save learning replay that is capturing its study when the removal is confirmed is answered as unavailable, and the removal moves the study without it being written back": 227, + "a Save learning replay that is still stopping the run when its study’s removal is confirmed is answered as unavailable, and the removal completes": 212, + "a Save learning replay that is writing its study when the removal is confirmed is answered as unavailable, and the removal completes after that write": 421, + "a Save learning replay that was capturing its study when a removal that moved nothing was confirmed is answered as unavailable, and its capture is written once that removal has ended": 274, + "a Stop whose last checkpoint cannot be written stops the run without failing and tells it once, in the line “History not saved: …” that Retry storage / refresh answers, and the Retry that saves the study leaves no line": 205, + "a Stop whose last checkpoint fails before anything is written stops the run without failing and tells it in the line “History not saved: …” that Retry storage / refresh answers, not in a control line": 133, + "a checkpoint taken while a recorded run’s stop is under way after the seal keeps the recording’s writer record, and the checkpoint taken after the stop gives it up": 336, + "a checkpoint that waited behind a write during a removal that moved nothing is written afterwards without another trigger": 274, + "a checkpoint that waits behind a write in flight is not written once the removal of its study is confirmed": 272, + "a checkpoint that was capturing a study when its removal was confirmed writes nothing for it afterwards": 285, + "a choice overtaken by a newer saved study adds no failure line when its own archive read fails afterwards, and the newer study stays shown": 155, + "a choice overtaken in the bottom panel of a closed Study workspace leaves the newer choice loading until that study is shown": 304, + "a choice whose request number is zero or a text is rejected as an unsupported message and is not answered": 248, + "a chosen Node test history whose open is discarded because the reader changed meanwhile stops loading": 327, + "a chosen saved study sent without a request number opens and no reply is posted": 224, + "a chosen saved study that opens is shown and its pane is told that the request ended": 201, + "a chosen saved study whose archive read fails after the Study workspace was closed adds no reading or storage line": 171, + "a chosen saved study whose archive read fails after the reader changed meanwhile leaves the earlier study shown without a storage failure line, and a delete request is asked": 276, + "a chosen saved study whose arrangement is refused after its archive was read stops loading and names the reason": 131, + "a chosen saved study whose open is discarded because the reader changed meanwhile leaves the earlier study shown and a delete request asked": 276, + "a confirmation dialog the editor cannot show moves nothing, and the next delete request is asked and carried out": 102, + "a confirmed removal also moves the raw evidence directory of the study’s run from the agent storage to the Trash": 83, + "a confirmed removal moves the study to the Trash, shows the next older study and reports the room in the library": 275, + "a delete request for another saved study while one is being moved to the Trash opens no dialog and leaves that study in place": 185, + "a delete request refused twice with the same sentence is answered with each request’s own number": 93, + "a delete request that carries the revision of an earlier view is rejected with the stale-view sentence, asks nothing and moves nothing": 166, + "a delete request while a chosen Node test history is still opening is refused with the same sentence, and is asked and carried out once the history has opened": 196, + "a delete request while a chosen saved study is still opening is refused with its own sentence and opens no dialog": 201, + "a delete request whose id is not a study identity is rejected as an unsupported message and moves nothing": 121, + "a dialog about a recording on another computer that the editor cannot show ends the removal with no line, and the study stays listed": 106, + "a forced checkpoint of a study whose files have moved ends while the study that follows is still being read": 273, + "a forced checkpoint that was capturing a study when its removal was confirmed is written once that removal moved nothing": 249, + "a newer choice that fails to open while the neighbour of a removed study is being read leaves the reader with no study selected": 184, + "a playback position save queued before a removal settles before the first move, and none is written for the removed study afterwards": 452, + "a playback position save queued while the dialog about a recording on another computer is open settles before the first move after Move to Trash Anyway": 372, + "a reader closed while the neighbour of the removed study of a finished live run is being read stays closed, and the neighbour is remembered": 191, + "a reader refresh while the admission of a run is still being read saves nothing and queues nothing": 121, + "a reader that is still closing when the neighbour of a removed study has been read remembers the neighbour": 148, + "a reader that starts with a study of a newer Codebook as its newest entry shows the newest study it can read, without a storage line": 138, + "a reader that starts with what is left of a study without its archive as its newest entry shows the newest study it can read, without a storage line": 156, + "a reader that starts with what is left of a study without its archive as its saved selection shows the newest study it can read, without a storage line": 142, + "a recorded run whose release fails after the seal gives up its recording’s writer record with the save of the checkpoint taken after that stop, and not with the save of one taken before the seal": 278, "a recorded run whose saves cannot look at its recording folder keeps its study, tells \"History not saved: …\", and Retry storage / refresh saves the study once the folder can be looked at": 215, - "a recording of another host that appears while the dialog is open keeps the study after Move to Trash Anyway, and the line names both recordings": 170, + "a recording of another host that appears while the dialog is open keeps the study after Move to Trash Anyway, and the line names both recordings": 107, "a recording opened while the dialog about a recording of another computer is open refuses the removal after Move to Trash Anyway, and nothing moves": 264, - "a refused delete request’s line stays when the learner changes between Overview and Live without having been in Recording": 169, - "a refused pane control is counted as not retryable and its line is gone once the learner’s next choice is handled": 255, - "a removal also moves the raw evidence of a crashed window whose connection descriptor names an ended process and no machine": 86, - "a removal confirmed while another saved study is still opening moves nothing and says to wait": 201, - "a removal is refused while Recording is open, also when Recording opens while the confirmation is waiting": 563, - "a removal is refused while a recording is still opening, also when the open is accepted while the confirmation is waiting": 464, - "a removal leaves the raw evidence in place and says so while another Codebook window’s connection descriptor exists": 92, - "a removal of this window’s run waits for an explanation that is being written and refuses another one while its files move": 332, - "a removal reports what it moved while the study that follows is still being read": 209, - "a removal that fails unexpectedly leaves the study listed and deletable again": 107, - "a removal that makes room for a refused run but cannot release the storage lock names no next step and keeps the refusal line": 664, - "a removal that makes room for a refused run names the next step and retires the refusal line although the next study cannot be arranged": 222, - "a removal that moved no file and cannot write the ledger back says that nothing was deleted and keeps the run saved and offered for Save learning replay": 210, - "a removal that moved nothing shows a saved study that appeared in the library meanwhile": 101, - "a removal that moved nothing tries the archive it held back by itself, and when that write still fails the line “History not saved: …” and Retry storage / refresh are there again, also when the line was retired during the move": 1230, - "a removal that settles after a chosen saved study was read and before it is shown leaves that study shown with its archive": 198, - "a removal the Trash refuses at its first move deletes nothing, and a later explanation of that run is still saved": 225, - "a removal the Trash refuses at the first file of a study the ledger names deletes nothing and keeps the run saved and offered for Save learning replay": 317, - "a removal the learner confirmed carries its request number while it is confirmed, while it moves and when it has moved": 121, - "a removal while another window holds the storage lock deletes nothing and names the lock": 118, - "a removal whose next study cannot be arranged still reports the study as moved, shows no study and names the arrangement failure": 166, - "a removal whose room read and list read fail after every file moved still reports the study as moved, without a count": 135, - "a removal whose storage lock cannot be released after every file moved reports the study as moved, names the lock in the reader and writes no waiting checkpoint": 1375, - "a removed study restored from the Trash and listed again by Retry storage has its playback position saved again": 327, - "a reply to an open request that reaches the application panel is recorded under that panel’s own kind, not as the Study pane": 106, - "a return to the current run made while the neighbour of a removed study is being read is not undone by that neighbour": 262, - "a run refused on a full study library is not saved by the open reader and shows no unsaved-history line": 226, - "a run whose runtime cannot be acquired is still saved as a not-demonstrated study": 200, + "a refused delete request’s line stays when the learner changes between Overview and Live without having been in Recording": 183, + "a refused pane control is counted as not retryable and its line is gone once the learner’s next choice is handled": 256, + "a removal also moves the raw evidence of a crashed window whose connection descriptor names an ended process and no machine": 84, + "a removal confirmed while another saved study is still opening moves nothing and says to wait": 211, + "a removal is refused while Recording is open, also when Recording opens while the confirmation is waiting": 509, + "a removal is refused while a recording is still opening, also when the open is accepted while the confirmation is waiting": 506, + "a removal leaves the raw evidence in place and says so while another Codebook window’s connection descriptor exists": 87, + "a removal of this window’s run waits for an explanation that is being written and refuses another one while its files move": 317, + "a removal reports what it moved while the study that follows is still being read": 213, + "a removal that fails unexpectedly leaves the study listed and deletable again": 143, + "a removal that makes room for a refused run but cannot release the storage lock names no next step and keeps the refusal line": 652, + "a removal that makes room for a refused run names the next step and retires the refusal line although the next study cannot be arranged": 197, + "a removal that moved no file and cannot write the ledger back says that nothing was deleted and keeps the run saved and offered for Save learning replay": 256, + "a removal that moved nothing shows a saved study that appeared in the library meanwhile": 99, + "a removal that moved nothing tries the archive it held back by itself, and when that write still fails the line “History not saved: …” and Retry storage / refresh are there again, also when the line was retired during the move": 1227, + "a removal that settles after a chosen saved study was read and before it is shown leaves that study shown with its archive": 219, + "a removal the Trash refuses at its first move deletes nothing, and a later explanation of that run is still saved": 231, + "a removal the Trash refuses at the first file of a study the ledger names deletes nothing and keeps the run saved and offered for Save learning replay": 275, + "a removal the learner confirmed carries its request number while it is confirmed, while it moves and when it has moved": 95, + "a removal while another window holds the storage lock deletes nothing and names the lock": 107, + "a removal whose next study cannot be arranged still reports the study as moved, shows no study and names the arrangement failure": 154, + "a removal whose room read and list read fail after every file moved still reports the study as moved, without a count": 132, + "a removal whose storage lock cannot be released after every file moved reports the study as moved, names the lock in the reader and writes no waiting checkpoint": 1307, + "a removed study restored from the Trash and listed again by Retry storage has its playback position saved again": 332, + "a reply to an open request that reaches the application panel is recorded under that panel’s own kind, not as the Study pane": 86, + "a return to the current run made while the neighbour of a removed study is being read is not undone by that neighbour": 230, + "a run refused on a full study library is not saved by the open reader and shows no unsaved-history line": 232, + "a run whose runtime cannot be acquired is still saved as a not-demonstrated study": 251, "a run’s crashed recording that names another host is listed in Saved studies, and Delete moves it after the learner chooses Move to Trash Anyway": 112, - "a run’s recording that a live window of this machine still writes is not listed in Saved studies": 138, - "a run’s recording whose writer record names another machine is listed in Saved studies, and Delete moves it after the learner chooses Move to Trash Anyway in a dialog that names the record’s host": 120, - "a saved study chosen and shown while a removal reads the ledger stays shown and saved, and the neighbour is never read": 186, - "a saved study chosen and shown while the neighbour of a removed study is being arranged stays shown and saved when that arrangement fails": 201, - "a saved study chosen during Recording is answered only once its recording load has ended": 414, - "a saved study chosen during Recording is not answered by a playback change in the middle of its recording load, only once that load has ended": 402, - "a saved study chosen during Recording with an outdated view is refused, answered at once and leaves the open recording as it is": 447, - "a saved study chosen in the bottom panel during Recording is answered when the Study workspace is closed before its recording has loaded": 405, - "a saved study chosen in the bottom panel of a closed Study workspace whose archive cannot be read stops loading and names the failure": 228, - "a saved study chosen in the bottom panel while the Study workspace is closed is shown there and stops loading": 198, - "a saved study chosen in the bottom panel while the Study workspace is opening stays loading until the open has rendered it, and is named before its pane is answered": 303, - "a saved study chosen while a presentation change is pending is refused and its pane is told that the request ended": 430, - "a saved study chosen while the neighbour of a removed study is being read is shown and saved, and the neighbour never is": 226, - "a saved study chosen with an outdated view while another recording load is in flight is answered at once": 410, - "a saved study in a newer format is listed with its note, adds no storage error and is refused when the learner asks to delete it": 133, - "a saved study that is still opening when a removal settles and then cannot be read leaves no removed study shown, and a delete request is asked": 196, - "a saved study that is still opening when a removal settles is shown, and the removal still reports what it moved": 185, - "a saved study whose crashed recording names another host is moved with its recording after the learner chooses Move to Trash Anyway in a dialog that names that host and the recording’s start": 126, - "a saved study whose recording a live window of this machine is still writing is refused, and no Move to Trash Anyway is offered": 153, - "a saved study whose recording names a live process of this computer begun after the recording reaches the dialog, and Move to Trash Anyway moves it": 142, - "a saved study whose recordings name two other hosts is moved with both after the learner chooses Move to Trash Anyway in a dialog that names both hosts and starts": 140, - "a saved study whose recording’s writer record names another machine is moved with its recording after the learner chooses Move to Trash Anyway in a dialog that names the record’s host": 155, - "a saved study with a recording a live window of this machine still writes and one that names another host is refused plainly, and no Move to Trash Anyway is offered": 172, - "a saved-study read that ends after a newer Node test history was chosen and shown leaves that Node test history shown": 239, - "a second delete request while the confirmation is waiting opens no second dialog": 190, - "a start that repeats the key of a refused run after a removal made room begins a new run that prepares": 194, - "a stopped and saved run whose study another window deletes with its recording does not write the study back at its next checkpoint, and its history ends as removed": 226, - "a study archive of another workspace’s library that a disposed reader hands over is not written into this library and shows no line, and the reader hands it on again when it is replaced": 188, - "a study the Trash took only partly stays listed and shown, and deleting it again finishes the removal": 187, - "a study whose recording folder could not be looked at after the Trash rejected it shows that Codebook could not tell whether it moved, and deleting it again finishes the removal": 191, - "a study whose save failed and that another window then deletes with its recording leaves no \"History not saved: …\" line once its next save is refused": 223, - "a study whose save failed and that another window then deletes with its recording leaves the line of a study list that cannot be read, and no \"History not saved: …\" line, once its next save is refused": 215, - "after Move to Trash Anyway the removal is shown as moving again while the files move, and ends as moved": 149, - "after a chosen saved study and a chosen Node test history each failed to open, a delete request is asked and carried out": 188, - "after a delete request was refused because Recording is open, choosing Live retires that line": 373, - "after a delete request was refused because Recording is open, choosing Overview retires that line": 369, - "after a recording open failed before Recording became active, the study can be removed": 224, - "after a recording open failed once Recording was active, a removal stays refused until Recording is left": 327, - "after a removal refused because another window of this machine still records the study, a run refused on the full library still offers to delete a saved study": 139, - "after a removal refused because nothing was left of the study, a run refused on the full library still offers to delete a saved study": 119, - "after a removal that moved nothing and could not write the ledger back, the reader reads the ledger again and reports that it cannot be read": 216, - "after a removal that moved the study although the Trash rejected a path that was already gone, a run refused on the full library still names deleting a saved study": 133, - "after a run was refused on a full library, removing a study makes room: the refusal line goes, and the same request prepares and clicks": 211, - "after the Trash refused a removal, a run refused on the full library names only the limit setting": 126, - "after the Trash refused a removal, a save and a recording refused by the reader’s full library name only the limit setting": 129, - "after the archive of a stopped run could not be saved, Retry storage / refresh writes it, lists the study and lets an agent read the run’s history and evidence; the study is not taken for one whose files were removed by hand": 263, - "after the archive of a stopped run could not be saved, a reader made again over the same service writes it at Retry storage / refresh without the archive the disposed reader held, and the study opens with the run’s history saved": 288, - "after the archive of a stopped run could not be saved, the one press on Retry storage / refresh that writes it leaves no storage line, not “Study archive is unavailable.” for the study it just saved": 238, - "after the archive of the study of this window’s own stopped run was removed by hand and Retry storage / refresh was pressed, an agent that reads the run or its evidence is told that the archive is no longer in the library, not that the study went to the Trash": 214, - "after the archive of the study of this window’s own stopped run was removed by hand, Retry storage / refresh does not write that archive again and lists what is left": 228, - "after the last save of the selected study failed, its archive on disk was lost and the workspace’s folders changed, the reader made again keeps the study selected with the archive it was handed, and Retry storage / refresh writes it and leaves it selected": 353, - "after the limit is raised, Retry storage leaves the library exactly as it was before the refused run": 177, - "after the listed files of a study were removed by hand, a refresh lists the library without it, leaves room for a run and drops the ledger’s reference to it": 247, - "after the server of a stopped run whose save had failed has ended and the workspace’s folders changed, the reader made again shows “History not saved: …” for it, writes its archive at Retry storage / refresh, and the study opens": 352, - "after the server of a stopped run whose write was still running has ended and the workspace’s folders changed, the reader made again shows “History not saved: …” for it, writes its archive at Retry storage / refresh, and the study opens": 241, - "after the shown study is removed the reader passes over a saved study that cannot be opened, and shows none when only that entry is left": 237, - "after the shown study is removed, a listed neighbour whose archive read fails is passed over and the next saved study is shown": 217, - "after the study of a failed save had its files removed by hand, Retry storage / refresh writes nothing for it and leaves no “History not saved: …” line": 234, - "after the study of a failed save had its files removed by hand, a Retry storage / refresh whose later step fails shows that failure and no “History not saved: …” line": 258, + "a run’s recording that a live window of this machine still writes is not listed in Saved studies": 139, + "a run’s recording whose writer record names another machine is listed in Saved studies, and Delete moves it after the learner chooses Move to Trash Anyway in a dialog that names the record’s host": 103, + "a saved study chosen and shown while a removal reads the ledger stays shown and saved, and the neighbour is never read": 192, + "a saved study chosen and shown while the neighbour of a removed study is being arranged stays shown and saved when that arrangement fails": 170, + "a saved study chosen during Recording is answered only once its recording load has ended": 435, + "a saved study chosen during Recording is not answered by a playback change in the middle of its recording load, only once that load has ended": 439, + "a saved study chosen during Recording with an outdated view is refused, answered at once and leaves the open recording as it is": 453, + "a saved study chosen in the bottom panel during Recording is answered when the Study workspace is closed before its recording has loaded": 415, + "a saved study chosen in the bottom panel of a closed Study workspace whose archive cannot be read stops loading and names the failure": 188, + "a saved study chosen in the bottom panel while the Study workspace is closed is shown there and stops loading": 192, + "a saved study chosen in the bottom panel while the Study workspace is opening stays loading until the open has rendered it, and is named before its pane is answered": 221, + "a saved study chosen while a presentation change is pending is refused and its pane is told that the request ended": 403, + "a saved study chosen while the neighbour of a removed study is being read is shown and saved, and the neighbour never is": 203, + "a saved study chosen with an outdated view while another recording load is in flight is answered at once": 425, + "a saved study in a newer format is listed with its note, adds no storage error and is refused when the learner asks to delete it": 138, + "a saved study that is still opening when a removal settles and then cannot be read leaves no removed study shown, and a delete request is asked": 221, + "a saved study that is still opening when a removal settles is shown, and the removal still reports what it moved": 214, + "a saved study whose crashed recording names another host is moved with its recording after the learner chooses Move to Trash Anyway in a dialog that names that host and the recording’s start": 153, + "a saved study whose recording a live window of this machine is still writing is refused, and no Move to Trash Anyway is offered": 137, + "a saved study whose recording names a live process of this computer begun after the recording reaches the dialog, and Move to Trash Anyway moves it": 186, + "a saved study whose recordings name two other hosts is moved with both after the learner chooses Move to Trash Anyway in a dialog that names both hosts and starts": 145, + "a saved study whose recording’s writer record names another machine is moved with its recording after the learner chooses Move to Trash Anyway in a dialog that names the record’s host": 122, + "a saved study with a recording a live window of this machine still writes and one that names another host is refused plainly, and no Move to Trash Anyway is offered": 117, + "a saved-study read that ends after a newer Node test history was chosen and shown leaves that Node test history shown": 179, + "a second delete request while the confirmation is waiting opens no second dialog": 182, + "a start that repeats the key of a refused run after a removal made room begins a new run that prepares": 193, + "a stopped and saved run whose study another window deletes with its recording does not write the study back at its next checkpoint, and its history ends as removed": 256, + "a study archive of another workspace’s library that a disposed reader hands over is not written into this library and shows no line, and the reader hands it on again when it is replaced": 189, + "a study the Trash took only partly stays listed and shown, and deleting it again finishes the removal": 174, + "a study whose recording folder could not be looked at after the Trash rejected it shows that Codebook could not tell whether it moved, and deleting it again finishes the removal": 179, + "a study whose save failed and that another window then deletes with its recording leaves no \"History not saved: …\" line once its next save is refused": 228, + "a study whose save failed and that another window then deletes with its recording leaves the line of a study list that cannot be read, and no \"History not saved: …\" line, once its next save is refused": 241, + "after Move to Trash Anyway the removal is shown as moving again while the files move, and ends as moved": 116, + "after a chosen saved study and a chosen Node test history each failed to open, a delete request is asked and carried out": 187, + "after a delete request was refused because Recording is open, choosing Live retires that line": 379, + "after a delete request was refused because Recording is open, choosing Overview retires that line": 407, + "after a recording open failed before Recording became active, the study can be removed": 284, + "after a recording open failed once Recording was active, a removal stays refused until Recording is left": 264, + "after a removal refused because another window of this machine still records the study, a run refused on the full library still offers to delete a saved study": 327, + "after a removal refused because nothing was left of the study, a run refused on the full library still offers to delete a saved study": 225, + "after a removal that moved nothing and could not write the ledger back, the reader reads the ledger again and reports that it cannot be read": 234, + "after a removal that moved the study although the Trash rejected a path that was already gone, a run refused on the full library still names deleting a saved study": 123, + "after a run was refused on a full library, removing a study makes room: the refusal line goes, and the same request prepares and clicks": 207, + "after the Trash refused a removal, a run refused on the full library names only the limit setting": 138, + "after the Trash refused a removal, a save and a recording refused by the reader’s full library name only the limit setting": 134, + "after the archive of a stopped run could not be saved, Retry storage / refresh writes it, lists the study and lets an agent read the run’s history and evidence; the study is not taken for one whose files were removed by hand": 218, + "after the archive of a stopped run could not be saved, a reader made again over the same service writes it at Retry storage / refresh without the archive the disposed reader held, and the study opens with the run’s history saved": 232, + "after the archive of a stopped run could not be saved, the one press on Retry storage / refresh that writes it leaves no storage line, not “Study archive is unavailable.” for the study it just saved": 247, + "after the archive of the study of this window’s own stopped run was removed by hand and Retry storage / refresh was pressed, an agent that reads the run or its evidence is told that the archive is no longer in the library, not that the study went to the Trash": 274, + "after the archive of the study of this window’s own stopped run was removed by hand, Retry storage / refresh does not write that archive again and lists what is left": 233, + "after the last save of the selected study failed, its archive on disk was lost and the workspace’s folders changed, the reader made again keeps the study selected with the archive it was handed, and Retry storage / refresh writes it and leaves it selected": 401, + "after the limit is raised, Retry storage leaves the library exactly as it was before the refused run": 137, + "after the listed files of a study were removed by hand, a refresh lists the library without it, leaves room for a run and drops the ledger’s reference to it": 687, + "after the server of a stopped run whose save had failed has ended and the workspace’s folders changed, the reader made again shows “History not saved: …” for it, writes its archive at Retry storage / refresh, and the study opens": 285, + "after the server of a stopped run whose write was still running has ended and the workspace’s folders changed, the reader made again shows “History not saved: …” for it, writes its archive at Retry storage / refresh, and the study opens": 275, + "after the shown study is removed the reader passes over a saved study that cannot be opened, and shows none when only that entry is left": 294, + "after the shown study is removed, a listed neighbour whose archive read fails is passed over and the next saved study is shown": 181, + "after the study of a failed save had its files removed by hand, Retry storage / refresh writes nothing for it and leaves no “History not saved: …” line": 200, + "after the study of a failed save had its files removed by hand, a Retry storage / refresh whose later step fails shows that failure and no “History not saved: …” line": 204, "an item selected while the neighbour of a removed study is being read leaves the neighbour shown": 201, - "an open request from a panel that is disposed while its message is handled ends without a disposal error": 126, - "an unknown entry, a Node test history and the study of a run that has not stopped are each refused with their own sentence and nothing moves": 234, - "asking to delete a saved study opens a native confirmation that names it, and cancelling moves nothing": 134, - "in a window with a Trash a delete request marked as sent by the pane keeps every check: under an old revision it is refused with its sentence, and no dialog opens": 160, - "in a window without a Trash a request for a study’s files that the pane sent by itself is answered although the reader has rendered since, without an error line, and the same request made by the learner on the old view keeps its sentence": 200, - "in a window without a Trash a request for a study’s files that the pane sent by itself is answered while a presentation changes, without an error line and without touching the change, and the same request made by the learner then keeps its sentence": 449, - "in a window without a Trash a request for a study’s files whose listing fails is answered with a refusal that carries the request’s number and the reason, without an error line, and the next request lists the files": 206, - "in a window without a Trash the reader answers a request for a study’s files, a refusal as well, and ends Retry storage / refresh with the Study workspace closed, all under the revision the request was sent with": 143, - "in a window without a Trash two panes that ask for the files of two studies at the same moment are both answered, each with the number it gave its request": 100, - "in a window without a Trash, Copy paths answers the asking pane with a failure when the clipboard refuses the write": 146, - "in a window without a Trash, Copy paths for a study whose files were never listed writes nothing and answers the asking pane with a failure": 149, - "in a window without a Trash, Copy paths writes the listed files one path a line and then answers the asking pane with their number": 182, - "in a window without a Trash, a request for the files of a Node test history or of the study of a run that has not stopped is refused with a sentence about removing by hand, not about deleting": 178, - "in a window without a Trash, after the archive alone of the chosen study was removed by hand, Retry storage / refresh selects no study and shows no storage line, and what is left stays listed with its files until it is removed too": 190, - "in a window without a Trash, after two of a study’s three listed files were removed by hand, Retry storage / refresh forgets the list and the next request lists the one file that is left": 90, - "in a window without a Trash, copying the listed files of a study puts the reader’s own list on the clipboard, one path a line": 94, - "in a window without a Trash, the files listed for one study stay listed and can be copied after another pane asked for another study": 125, - "raising the saved-study limit above the saved count retires the refusal line; a limit that leaves the library full keeps it": 220, - "refreshes after the background selection changed leave a selected test replay’s source and debugger on its stop": 235, - "removing a saved study that is not the shown one keeps the shown study": 231, - "removing the oldest shown study shows the one before it, and removing the last study shows none": 243, - "removing the shown study of a finished live run arranges the reader for the neighbour the way a chosen entry is arranged": 187, - "retiring the reader after a refused run on a still-full library completes": 193, - "retiring the reader during a removal that moves nothing waits for it and saves the final state of the run": 268, - "retiring the reader during a removal that moves the study waits for it and writes nothing for that study": 274, - "right after the study of this window’s stopped run was removed, the Save learning replay item is hidden and a Save is refused": 171, - "the browser-replay refusal of a Node test history disappears once that history opens after the learner left Recording": 444, - "the browser-replay refusal of a Node test history offers no Retry storage and is gone once the learner’s next pane choice is handled": 468, - "the dialog about a recording that a live process of this computer begun after it may still write says that another editor window may still be recording it, and what is lost": 133, - "the evidence of this window’s own stopped run moves with its study, and the run then answers that its evidence is unavailable": 170, - "the first Saved study choice after a canceled workspace close opens without refreshing the bottom panel": 197, - "the first Saved study choice after closing the workspace opens in the already visible bottom panel": 195, - "the line that says why the study after a removal could not be arranged is gone once the learner chooses a saved study that is shown": 216, - "the line “History not saved: …” goes with a study whose save failed when the learner moves it to the Trash, and no write waits": 242, - "the line “History not saved: …” of a study that still waits stays, with Retry storage / refresh beside it, when another study is saved meanwhile, and is gone once Retry wrote the waiting one": 251, - "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when Retry storage / refresh is pressed": 361, - "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when another study is saved": 377, - "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when another window deleted that study with its recording and Retry storage / refresh was pressed": 361, - "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when its files were removed by hand and Retry storage / refresh was pressed": 362, - "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when the learner moves that study to the Trash": 298, - "the line “History not saved: …” of a study whose capture failed before any write stays, with Retry storage / refresh beside it, when another study is saved meanwhile, and is gone once Retry saved that study": 235, - "the line “History not saved: …” of a study whose capture failed goes when another window deleted that study with its recording and the save of Retry storage / refresh is refused, and no Retry is offered": 364, - "the line “History not saved: …” of a study whose capture failed goes when its files were removed by hand and Retry storage / refresh was pressed, and that Retry writes nothing for it": 330, - "the line “History not saved: …” of a study whose capture failed goes when the learner moves that study to the Trash, and no Retry storage / refresh is offered": 300, - "the line “History not saved: …” of a study whose capture failed stays, with Retry storage / refresh beside it, when another study is deleted with its recording by another window, and is gone once Retry saved that study": 364, - "the line “History not saved: …” stays with Retry storage / refresh beside it when the learner moves a study to the Trash while another study still waits to be saved": 290, - "the outcome line of a removal gives way to the next delete request and to a run that starts": 227, - "the reader says in its own line that the last run did not start, and no longer once a later run is accepted": 282, - "the refusal line of a run that did not start is not shown while a recording is open": 386, - "the refusal line stays after a removal that leaves the library full or the limit setting invalid": 232, - "the retirement of a reader whose last write of a study fails leaves the line “History not saved: …” with its sentence": 200, - "the study of this window’s own stopped run stays removed through refreshes, Retry storage and retirement": 227, - "two delete requests started in the same turn open one dialog for the first study and the second is refused while the first holds the removal": 216, - "two overlapping choices from one pane are each answered once with their own number": 320, - "while a saved study is being moved to the Trash it cannot be opened or played and the pane says it is moving, and the removal then completes": 106, - "while a saved study is being moved to the Trash, choosing it in the pane and opening its recording through the playback controller both answer that the archive is unavailable": 253, - "while the dialog about a recording on another computer is open the removal waits for the learner’s confirmation, and Cancel ends it with no line": 144 + "an open request from a panel that is disposed while its message is handled ends without a disposal error": 123, + "an unknown entry, a Node test history and the study of a run that has not stopped are each refused with their own sentence and nothing moves": 192, + "asking to delete a saved study opens a native confirmation that names it, and cancelling moves nothing": 181, + "in a window with a Trash a delete request marked as sent by the pane keeps every check: under an old revision it is refused with its sentence, and no dialog opens": 165, + "in a window without a Trash a request for a study’s files that the pane sent by itself is answered although the reader has rendered since, without an error line, and the same request made by the learner on the old view keeps its sentence": 198, + "in a window without a Trash a request for a study’s files that the pane sent by itself is answered while a presentation changes, without an error line and without touching the change, and the same request made by the learner then keeps its sentence": 433, + "in a window without a Trash a request for a study’s files whose listing fails is answered with a refusal that carries the request’s number and the reason, without an error line, and the next request lists the files": 176, + "in a window without a Trash the reader answers a request for a study’s files, a refusal as well, and ends Retry storage / refresh with the Study workspace closed, all under the revision the request was sent with": 159, + "in a window without a Trash two panes that ask for the files of two studies at the same moment are both answered, each with the number it gave its request": 114, + "in a window without a Trash, Copy paths answers the asking pane with a failure when the clipboard refuses the write": 133, + "in a window without a Trash, Copy paths for a study whose files were never listed writes nothing and answers the asking pane with a failure": 138, + "in a window without a Trash, Copy paths writes the listed files one path a line and then answers the asking pane with their number": 143, + "in a window without a Trash, a request for the files of a Node test history or of the study of a run that has not stopped is refused with a sentence about removing by hand, not about deleting": 180, + "in a window without a Trash, after the archive alone of the chosen study was removed by hand, Retry storage / refresh selects no study and shows no storage line, and what is left stays listed with its files until it is removed too": 187, + "in a window without a Trash, after two of a study’s three listed files were removed by hand, Retry storage / refresh forgets the list and the next request lists the one file that is left": 97, + "in a window without a Trash, copying the listed files of a study puts the reader’s own list on the clipboard, one path a line": 83, + "in a window without a Trash, the files listed for one study stay listed and can be copied after another pane asked for another study": 127, + "raising the saved-study limit above the saved count retires the refusal line; a limit that leaves the library full keeps it": 242, + "refreshes after the background selection changed leave a selected test replay’s source and debugger on its stop": 227, + "removing a saved study that is not the shown one keeps the shown study": 175, + "removing the oldest shown study shows the one before it, and removing the last study shows none": 235, + "removing the shown study of a finished live run arranges the reader for the neighbour the way a chosen entry is arranged": 217, + "retiring the reader after a refused run on a still-full library completes": 227, + "retiring the reader during a removal that moves nothing waits for it and saves the final state of the run": 255, + "retiring the reader during a removal that moves the study waits for it and writes nothing for that study": 230, + "right after the study of this window’s stopped run was removed, the Save learning replay item is hidden and a Save is refused": 177, + "the browser-replay refusal of a Node test history disappears once that history opens after the learner left Recording": 422, + "the browser-replay refusal of a Node test history offers no Retry storage and is gone once the learner’s next pane choice is handled": 474, + "the dialog about a recording that a live process of this computer begun after it may still write says that another editor window may still be recording it, and what is lost": 163, + "the evidence of this window’s own stopped run moves with its study, and the run then answers that its evidence is unavailable": 167, + "the first Saved study choice after a canceled workspace close opens without refreshing the bottom panel": 179, + "the first Saved study choice after closing the workspace opens in the already visible bottom panel": 180, + "the line that says why the study after a removal could not be arranged is gone once the learner chooses a saved study that is shown": 192, + "the line “History not saved: …” goes with a study whose save failed when the learner moves it to the Trash, and no write waits": 188, + "the line “History not saved: …” of a study that still waits stays, with Retry storage / refresh beside it, when another study is saved meanwhile, and is gone once Retry wrote the waiting one": 305, + "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when Retry storage / refresh is pressed": 330, + "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when another study is saved": 351, + "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when another window deleted that study with its recording and Retry storage / refresh was pressed": 357, + "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when its files were removed by hand and Retry storage / refresh was pressed": 339, + "the line “History not saved: …” of a study whose capture failed and whose run this window no longer holds goes when the learner moves that study to the Trash": 300, + "the line “History not saved: …” of a study whose capture failed before any write stays, with Retry storage / refresh beside it, when another study is saved meanwhile, and is gone once Retry saved that study": 217, + "the line “History not saved: …” of a study whose capture failed goes when another window deleted that study with its recording and the save of Retry storage / refresh is refused, and no Retry is offered": 328, + "the line “History not saved: …” of a study whose capture failed goes when its files were removed by hand and Retry storage / refresh was pressed, and that Retry writes nothing for it": 321, + "the line “History not saved: …” of a study whose capture failed goes when the learner moves that study to the Trash, and no Retry storage / refresh is offered": 286, + "the line “History not saved: …” of a study whose capture failed stays, with Retry storage / refresh beside it, when another study is deleted with its recording by another window, and is gone once Retry saved that study": 347, + "the line “History not saved: …” stays with Retry storage / refresh beside it when the learner moves a study to the Trash while another study still waits to be saved": 259, + "the outcome line of a removal gives way to the next delete request and to a run that starts": 240, + "the reader says in its own line that the last run did not start, and no longer once a later run is accepted": 243, + "the refusal line of a run that did not start is not shown while a recording is open": 371, + "the refusal line stays after a removal that leaves the library full or the limit setting invalid": 229, + "the retirement of a reader whose last write of a study fails leaves the line “History not saved: …” with its sentence": 144, + "the study of this window’s own stopped run stays removed through refreshes, Retry storage and retirement": 231, + "two delete requests started in the same turn open one dialog for the first study and the second is refused while the first holds the removal": 160, + "two overlapping choices from one pane are each answered once with their own number": 255, + "while a saved study is being moved to the Trash it cannot be opened or played and the pane says it is moving, and the removal then completes": 110, + "while a saved study is being moved to the Trash, choosing it in the pane and opening its recording through the playback controller both answer that the archive is unavailable": 227, + "while the dialog about a recording on another computer is open the removal waits for the learner’s confirmation, and Cancel ends it with no line": 110 } }, "studyWorkspaceReplay.test.js": { - "totalMs": 77042, + "totalMs": 76395, "tests": { - "Open article stays offered during replay and opens the article without leaving or moving the replay": 329, - "Pause during a late recorded image restores the previous source and preserves only the confirmed position": 327, - "Play across an explanation’s saved time inside the stop’s recorded pause keeps the image and Run and Debug until the pause ends, and the Study pane drops the saved-while-held note at that time": 1321, - "Play across the end of a stop’s recorded pause on the same frame keeps the recorded image while Run and Debug, the stop’s session and its source highlight end": 1321, - "Play across the end of a stop’s recorded pause onto a newer frame keeps the stop’s image painted until the newer frame replaces it, while Run and Debug, the stop’s session and its source highlight end": 1352, - "Play across the time the stop on screen was explained leaves the recorded image and Run and Debug untouched, and the Study pane gains the explanation": 485, - "Read App preserves a newer tab choice when the previous source editor is still reported": 106, - "Read Source accepts an unchanged chat tab model refreshed while its captured editor is still reported": 93, - "Read Source enlarges the focused captured editor when Cursor still names its chat tab group": 82, - "Read Source preserves a newer chat choice while its focused captured editor has a stale named group": 74, - "Read Source preserves a newer opaque choice during its own source focus handoff": 91, - "Read Source preserves a newer opaque tab when the old source editor is still reported": 92, - "Read Source rejects a native group move instead of preserving its old chat fallback": 103, - "Read Source rejects a native group replace instead of preserving its old chat fallback": 83, - "Read captured source accepts an unchanged settings tab before focusing its owned source": 82, - "Read captured source keeps the learner cursor when the selected source is already displayed": 102, - "Read captured source preserves a newer draft choice while its existing document opens": 91, - "Reload in Learning summary keeps its recovery controls after a read failure and retries without reopening the summary": 501, - "Restore after focused reading recovers the confirmed Study layout when native space is available": 187, - "Restore beside a separate editor part keeps the selected explanation after borrowing primary focus": 2602, - "Restore beside a separate editor part preserves a learner tab chosen during its focus borrow": 1735, - "Restore does not rearrange Study after the learner selects a draft during native unmaximize": 498, - "Restore preserves a newer source choice made while it reveals the covered recording": 5387, - "Restore stops after the learner leaves the work window during its primary focus borrow": 1775, - "Restore uncovers the recorded application and recovers its source without changing history or running the target again": 415, - "Show Variables expands the first scope of Variables, never the first row of a list the learner clicked during its wait": 365, - "a configured article decision survives reader restart and secondary-file drift without changing its saved citation context": 425, - "a configured outline cannot write historical understanding after a secondary citation changes": 470, - "a corrupt configured recording keeps the real article return pose, learner ledger and input count intact": 262, - "a different recording opened while the editor is still stopping the replaced historical debugger commits as soon as the stop is released": 505, - "a failed panel message that is not a replay control stays reported after the recording is opened again, and a refused seek is listed once": 534, - "a failed renderer re-handshake after a recorded paint loss keeps the first attempt in Recording error details": 270, - "a fresh reader restores the saved recording position paused and a live-runtime retirement does not exit playback": 472, - "a future configured recording keeps the real article return pose, learner ledger and input count intact": 268, - "a handled native values notification clears an earlier notification failure while no Run and Debug hint is showing": 342, - "a hidden bottom pane never claims keyboard preservation for a later recording entry": 358, - "a historical debugger that failed to stop is reported without offering Retry storage": 270, - "a historical debugger that failed to stop stays reported after native values load": 274, - "a historical seek preserves pinned captured bytes when pinned before the seek and Unpin with Retry recovers the requested moment": 531, - "a historical seek preserves pinned captured bytes when pinned during native document I/O and Unpin with Retry recovers the requested moment": 460, - "a historical source update cannot publish after Close during delayed native delivery": 363, - "a historical source update waits for actual native bytes before committing the shared gap moment": 476, - "a learner draft chosen during historical source I/O stays visible and receives no obsolete quiet source replacement": 352, - "a learner seeking or playing from the Learning replay panel after the reader closed is refused, told why, and nothing opens": 411, - "a learner’s reopen of a recording an agent’s open found already shown is the learner’s own: the Learning summary comes to the front with the keyboard and no agent sentence is told": 350, - "a learner’s replay open after an agent’s open was refused for a stale revision is the learner’s own: the learner’s file gets the keyboard back, the Learning summary comes to the front, and no agent sentence is told": 290, - "a missing configured recording keeps the real article return pose, learner ledger and input count intact": 268, - "a native values notification the reader failed to handle is shown, and the next handled notification clears it": 374, - "a new historical seek refuses to recreate a learner-closed source until explicit Source restores its native input": 430, - "a newer historical seek supersedes withheld source I/O and keeps its own captured bytes and playhead": 416, - "a play sent from the Learning replay panel while the reader is closing is listed once and is gone after the recording is opened again": 465, - "a reader reopened after closing never shows the Run and Debug hint of the replay moment it showed before": 432, - "a recorded frame whose first paint fails with a timeout in other words is painted once more": 356, - "a recorded frame whose first paint fails with another error is not painted again although its text reads like the timeout": 296, - "a recording opened again after an abandoned first reader entry that never returns reports busy after the presentation bound": 797, + "Open article stays offered during replay and opens the article without leaving or moving the replay": 331, + "Pause during a late recorded image restores the previous source and preserves only the confirmed position": 373, + "Play across an explanation’s saved time inside the stop’s recorded pause keeps the image and Run and Debug until the pause ends, and the Study pane drops the saved-while-held note at that time": 1318, + "Play across the end of a stop’s recorded pause on the same frame keeps the recorded image while Run and Debug, the stop’s session and its source highlight end": 1499, + "Play across the end of a stop’s recorded pause onto a newer frame keeps the stop’s image painted until the newer frame replaces it, while Run and Debug, the stop’s session and its source highlight end": 1373, + "Play across the time the stop on screen was explained leaves the recorded image and Run and Debug untouched, and the Study pane gains the explanation": 572, + "Read App preserves a newer tab choice when the previous source editor is still reported": 81, + "Read Source accepts an unchanged chat tab model refreshed while its captured editor is still reported": 77, + "Read Source enlarges the focused captured editor when Cursor still names its chat tab group": 101, + "Read Source preserves a newer chat choice while its focused captured editor has a stale named group": 75, + "Read Source preserves a newer opaque choice during its own source focus handoff": 72, + "Read Source preserves a newer opaque tab when the old source editor is still reported": 80, + "Read Source rejects a native group move instead of preserving its old chat fallback": 115, + "Read Source rejects a native group replace instead of preserving its old chat fallback": 69, + "Read captured source accepts an unchanged settings tab before focusing its owned source": 85, + "Read captured source keeps the learner cursor when the selected source is already displayed": 107, + "Read captured source preserves a newer draft choice while its existing document opens": 70, + "Reload in Learning summary keeps its recovery controls after a read failure and retries without reopening the summary": 485, + "Restore after focused reading recovers the confirmed Study layout when native space is available": 202, + "Restore beside a separate editor part keeps the selected explanation after borrowing primary focus": 2518, + "Restore beside a separate editor part preserves a learner tab chosen during its focus borrow": 1704, + "Restore does not rearrange Study after the learner selects a draft during native unmaximize": 488, + "Restore preserves a newer source choice made while it reveals the covered recording": 5430, + "Restore stops after the learner leaves the work window during its primary focus borrow": 1732, + "Restore uncovers the recorded application and recovers its source without changing history or running the target again": 429, + "Show Variables expands the first scope of Variables, never the first row of a list the learner clicked during its wait": 468, + "a configured article decision survives reader restart and secondary-file drift without changing its saved citation context": 322, + "a configured outline cannot write historical understanding after a secondary citation changes": 432, + "a corrupt configured recording keeps the real article return pose, learner ledger and input count intact": 332, + "a different recording opened while the editor is still stopping the replaced historical debugger commits as soon as the stop is released": 482, + "a failed panel message that is not a replay control stays reported after the recording is opened again, and a refused seek is listed once": 508, + "a failed renderer re-handshake after a recorded paint loss keeps the first attempt in Recording error details": 335, + "a fresh reader restores the saved recording position paused and a live-runtime retirement does not exit playback": 465, + "a future configured recording keeps the real article return pose, learner ledger and input count intact": 254, + "a handled native values notification clears an earlier notification failure while no Run and Debug hint is showing": 343, + "a hidden bottom pane never claims keyboard preservation for a later recording entry": 346, + "a historical debugger that failed to stop is reported without offering Retry storage": 277, + "a historical debugger that failed to stop stays reported after native values load": 262, + "a historical seek preserves pinned captured bytes when pinned before the seek and Unpin with Retry recovers the requested moment": 489, + "a historical seek preserves pinned captured bytes when pinned during native document I/O and Unpin with Retry recovers the requested moment": 514, + "a historical source update cannot publish after Close during delayed native delivery": 379, + "a historical source update waits for actual native bytes before committing the shared gap moment": 430, + "a learner draft chosen during historical source I/O stays visible and receives no obsolete quiet source replacement": 400, + "a learner seeking or playing from the Learning replay panel after the reader closed is refused, told why, and nothing opens": 386, + "a learner’s reopen of a recording an agent’s open found already shown is the learner’s own: the Learning summary comes to the front with the keyboard and no agent sentence is told": 340, + "a learner’s replay open after an agent’s open was refused for a stale revision is the learner’s own: the learner’s file gets the keyboard back, the Learning summary comes to the front, and no agent sentence is told": 261, + "a missing configured recording keeps the real article return pose, learner ledger and input count intact": 402, + "a native values notification the reader failed to handle is shown, and the next handled notification clears it": 341, + "a new historical seek refuses to recreate a learner-closed source until explicit Source restores its native input": 422, + "a newer historical seek supersedes withheld source I/O and keeps its own captured bytes and playhead": 433, + "a play sent from the Learning replay panel while the reader is closing is listed once and is gone after the recording is opened again": 457, + "a reader reopened after closing never shows the Run and Debug hint of the replay moment it showed before": 430, + "a recorded frame whose first paint fails with a timeout in other words is painted once more": 1155, + "a recorded frame whose first paint fails with another error is not painted again although its text reads like the timeout": 328, + "a recording opened again after an abandoned first reader entry that never returns reports busy after the presentation bound": 742, "a recording opened again after its first reader entry was abandoned waits for that entry instead of reporting busy": 577, - "a recording opened again while its first recorded-application reveal is still queued keeps that viewport and paints the next frame": 423, - "a recording renderer created after the hidden Recorded application pane was closed reveals once and not again on the next seek": 413, - "a recording renderer whose first reveal fails without a cancellation is released by the renderer setup itself": 280, - "a recording whose recorded-application renderer never became ready opens again through a new renderer": 291, - "a repeated recorded paint loss names each attempt’s renderer progress in Recording error details": 276, - "a replay control refused for an outdated panel view is listed once and is gone after the next accepted replay control": 459, - "a replay control refused in the Learning replay panel is no longer shown once an agent seek is accepted": 426, - "a replay control refused on a closed reader is no longer shown in the Learning replay panel once a later live-run action succeeds": 440, - "a replay control refused on a closed reader is no longer shown in the Learning replay panel once an agent opens the recording again": 444, - "a replay control refused on a closed reader is no longer shown in the Learning replay panel once the recording is opened again": 439, - "a replay moment whose recorded values Run and Debug has not loaded tells the learner where to load them until they load": 347, - "a replay settle that starts while a frame is already painting fails 5 s after that paint began, not 5 s after the settle began": 1022, - "a saved study that stops in a file shown two studies earlier leaves one captured-source tab for that file": 311, - "a saved study that stops in another file of the same name keeps the earlier study’s captured-source tab open beside its own": 208, - "a second run stopping in the same source file replaces the first run captured-source tab instead of adding another": 319, - "a seek refused because the learner closed the recorded source names Codebook: Focus Captured Source, and that command reopens the source": 415, - "a study whose stop the debugger bound at column 7 of its declared line opens through Recording and presents that stop at the bound column": 321, - "a superseded frame that is still waiting to paint does not count against the newer frame, which settles once its own debugger wait and paint finish": 981, - "a workspace file opened over the recorded application is reported to Run and Debug and to the Learning summary as a covered recording, not as a missing or loading moment": 378, - "after the reader closed the playback state says the reader is closed and a refused seek tells the agent to send open": 268, - "after two abandoned recording reveals the next presentation still waits for the renderer handshake": 270, - "agent-configured input uses the shared reader and complete article understanding without opening or closing a raw target tab": 814, - "an agent opening the same recording after the reader closed opens the reader and presents the saved moment": 442, - "an agent seek that arrives while the reader is closing is refused": 369, - "an agent seeking or playing a recording after the reader closed is refused and nothing opens": 370, - "an agent’s Study selection while a replay stays loaded and the chat view has the keyboard gives no file the keyboard and keeps the Learning summary behind the chat with a word": 319, - "an agent’s replay open in Cursor while the learner types in the bottom panel’s terminal shows the Learning summary and keeps the terminal in front with its keyboard": 256, - "an agent’s replay open in VS Code while the learner types in the bottom panel’s terminal keeps the terminal in front with its keyboard and says where the replay controls wait": 218, - "an agent’s replay open while the chat view has the keyboard leaves the keyboard in the chat and keeps the Learning summary behind the chat with a word": 227, - "an explicit Summary entry still focuses Summary after a recording preserved the bottom keyboard": 278, - "another explicit open while the editor is still stopping the replaced historical debugger waits for it and then presents": 420, - "at a recorded stop the Study pane receives that stop’s explanation with when it was saved, and Later annotations hold only the revision saved after it": 409, - "closing the reader waits for a replaced historical debugger that the editor is still stopping, and the next open presents": 898, - "closing the reader waits for a replay position save that storage still holds": 654, - "closing the reader while a recorded frame never paints still finishes": 301, - "closing the reader while the native debugger never answers a recorded stop still finishes": 323, - "configured captured and current native readers accept unchanged BOM and mixed line endings without changing retained bytes": 246, - "configured history rejects learner Run and only a fresh agent request creates another run without dispatching input": 387, - "configured recording seeks actual facts through the shared reader after runtime exit with no future source or execution authority": 439, - "configured recording-context failure remains visible beside independently saved observation history": 293, - "constrained Restore keeps a later learner draft active while the native layout receipt settles": 2669, - "constrained Restore leaves the learner draft active when a later topology check completes": 2657, - "direct configured entry opens its article at the beginning while actual article origins restore their exact pose after restart": 313, + "a recording opened again while its first recorded-application reveal is still queued keeps that viewport and paints the next frame": 430, + "a recording renderer created after the hidden Recorded application pane was closed reveals once and not again on the next seek": 431, + "a recording renderer whose first reveal fails without a cancellation is released by the renderer setup itself": 266, + "a recording whose recorded-application renderer never became ready opens again through a new renderer": 273, + "a repeated recorded paint loss names each attempt’s renderer progress in Recording error details": 344, + "a replay control refused for an outdated panel view is listed once and is gone after the next accepted replay control": 440, + "a replay control refused in the Learning replay panel is no longer shown once an agent seek is accepted": 386, + "a replay control refused on a closed reader is no longer shown in the Learning replay panel once a later live-run action succeeds": 447, + "a replay control refused on a closed reader is no longer shown in the Learning replay panel once an agent opens the recording again": 442, + "a replay control refused on a closed reader is no longer shown in the Learning replay panel once the recording is opened again": 434, + "a replay moment whose recorded values Run and Debug has not loaded tells the learner where to load them until they load": 418, + "a replay settle that starts while a frame is already painting fails 5 s after that paint began, not 5 s after the settle began": 942, + "a saved study that stops in a file shown two studies earlier leaves one captured-source tab for that file": 253, + "a saved study that stops in another file of the same name keeps the earlier study’s captured-source tab open beside its own": 191, + "a second run stopping in the same source file replaces the first run captured-source tab instead of adding another": 333, + "a seek refused because the learner closed the recorded source names Codebook: Focus Captured Source, and that command reopens the source": 488, + "a study whose stop the debugger bound at column 7 of its declared line opens through Recording and presents that stop at the bound column": 324, + "a superseded frame that is still waiting to paint does not count against the newer frame, which settles once its own debugger wait and paint finish": 984, + "a workspace file opened over the recorded application is reported to Run and Debug and to the Learning summary as a covered recording, not as a missing or loading moment": 445, + "after the reader closed the playback state says the reader is closed and a refused seek tells the agent to send open": 273, + "after two abandoned recording reveals the next presentation still waits for the renderer handshake": 300, + "agent-configured input uses the shared reader and complete article understanding without opening or closing a raw target tab": 350, + "an agent opening the same recording after the reader closed opens the reader and presents the saved moment": 493, + "an agent seek that arrives while the reader is closing is refused": 340, + "an agent seeking or playing a recording after the reader closed is refused and nothing opens": 342, + "an agent’s Study selection while a replay stays loaded and the chat view has the keyboard gives no file the keyboard and keeps the Learning summary behind the chat with a word": 314, + "an agent’s replay open in Cursor while the learner types in the bottom panel’s terminal shows the Learning summary and keeps the terminal in front with its keyboard": 259, + "an agent’s replay open in VS Code while the learner types in the bottom panel’s terminal keeps the terminal in front with its keyboard and says where the replay controls wait": 226, + "an agent’s replay open while the chat view has the keyboard leaves the keyboard in the chat and keeps the Learning summary behind the chat with a word": 212, + "an explicit Summary entry still focuses Summary after a recording preserved the bottom keyboard": 270, + "another explicit open while the editor is still stopping the replaced historical debugger waits for it and then presents": 324, + "at a recorded stop the Study pane receives that stop’s explanation with when it was saved, and Later annotations hold only the revision saved after it": 493, + "closing the reader waits for a replaced historical debugger that the editor is still stopping, and the next open presents": 961, + "closing the reader waits for a replay position save that storage still holds": 551, + "closing the reader while a recorded frame never paints still finishes": 282, + "closing the reader while the native debugger never answers a recorded stop still finishes": 265, + "configured captured and current native readers accept unchanged BOM and mixed line endings without changing retained bytes": 237, + "configured history rejects learner Run and only a fresh agent request creates another run without dispatching input": 304, + "configured recording seeks actual facts through the shared reader after runtime exit with no future source or execution authority": 569, + "configured recording-context failure remains visible beside independently saved observation history": 374, + "constrained Restore keeps a later learner draft active while the native layout receipt settles": 2648, + "constrained Restore leaves the learner draft active when a later topology check completes": 2618, + "direct configured entry opens its article at the beginning while actual article origins restore their exact pose after restart": 310, "failed evidence navigation preserves the previous exact article return pose in memory and after restart": 302, - "failed initial pane reservation with 1 main panes and a separate part cannot create Context before an explicit retry": 715, - "failed initial pane reservation with 1 main panes and one part cannot create Context before an explicit retry": 709, - "failed initial pane reservation with 2 main panes and a separate part cannot create Context before an explicit retry": 708, - "historical source annotations identify the recorded file, time, hash and selected line and replace that identity inside a gap": 508, - "historical source capacity freezes every pinned display and permits explicit recovery after one older view is unpinned": 466, - "holding position saves in one workspace harness does not hold the saves of another, and a second hold while one is active is refused": 710, - "in Cursor beside its chat part, an agent’s Study selection that reopens a replay an agent opened earlier while the learner’s file has the keyboard gives that file nothing back and says once that the Application pane has the keyboard": 373, - "in Cursor, an agent’s Return Current from a replay after the learner’s click into the first group’s file during its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 262, - "in Cursor, an agent’s Return Current from a replay leaves the keyboard in Keyboard Shortcuts the learner opened in the Wiki’s group while the arrangement’s receipt was read, and the chat gets none back": 252, - "in Cursor, an agent’s Return Current from a replay leaves the keyboard in Settings the learner opened in the Wiki’s group while the arrangement’s receipt was read, and the chat gets none back": 263, - "in Cursor, an agent’s Return Current from a replay leaves the keyboard in the empty group the learner opened while the arrangement’s receipt was read, also while the editor still reports the first group’s file, and the chat gets none back": 258, - "in Cursor, an agent’s Return Current from a replay leaves the keyboard in the empty group the learner opened while the arrangement’s receipt was read, and the chat gets none back": 268, - "in Cursor, an agent’s Return Current from a replay leaves the keyboard in the terminal the learner opened in another group after the borrow of the first group, while the editor still reports the first group’s file": 274, - "in Cursor, an agent’s Return Current from a replay refused for the learner’s change of the first group’s file during its layout read gives the chat no keyboard and tells nothing": 255, - "in Cursor, an agent’s Return Current from a replay refused right after its borrow of the first group gives the chat its keyboard back and says that nothing was arranged": 251, - "in Cursor, an agent’s Return Current from a replay while the learner’s file is in front of the first group gives the chat its keyboard back after borrowing the first group, while Cursor names its chat part’s group": 266, - "in Cursor, an agent’s Return Current from the saved replay its cold select reopened gives the chat its keyboard back after borrowing through the captured source, while Cursor names its chat part’s group": 366, - "in Cursor, an agent’s Return Current from the saved replay leaves the keyboard in the terminal the learner opened in another group after the measurement showed the captured source, while the editor still reports that source": 353, - "in Cursor, an agent’s Return Current right after its cold Study selection from the chat gives the chat its keyboard back, also after its measurement showed the captured source with the keyboard": 356, - "in Cursor, an agent’s Study selection that reopens a replay an agent opened earlier, while the learner’s file has the keyboard, says once that the Application pane has it": 359, - "in Cursor, an agent’s cold Study selection that reopens a replay while the editor names the Repository Wiki’s group and the chat input has the keyboard gives the chat its keyboard back and says so once": 363, - "in Cursor, an agent’s replay open after the learner’s click into the first group’s file during its layout read keeps the keyboard there, gives the chat nothing and tells no keyboard sentence": 260, - "in Cursor, an agent’s replay open from the chat tab gives the chat its keyboard back and says so the first time in an editor session only": 361, - "in Cursor, an agent’s replay open refused for the learner’s change of the first group’s file during its layout read gives the chat no keyboard and tells nothing": 171, - "in Cursor, an agent’s replay open refused right after its borrow of the first group gives the chat its keyboard back and says that nothing was arranged": 155, - "in Cursor, an agent’s replay open refused right after its borrow still gives the chat its keyboard back and says that nothing was arranged after an earlier focus request was refused for the learner’s newer choice": 298, - "in VS Code, an agent’s Study selection that reopens a replay an agent opened earlier, while the learner’s file has the keyboard, says once that the Application pane has it": 253, - "one bottom playback seek from a hidden Application commits the requested recorded moment without another target action": 325, - "opening a recording never tells the learner the captured source is not ready while its own first frame is still presenting": 309, - "opening a recording restores its captured source after context focus covers the manually moved source group": 489, - "opening a recording while a live run is attached presents its saved frame": 329, - "opening a recording while the bottom pane holds keyboard reveals Summary without taking that keyboard": 350, - "opening the recording of this session’s own run while no study is selected shows no \"another configured article\" error during or after the load": 278, - "ordinary Study entry retains manually shared pane columns until the learner explicitly arranges them": 79, - "pinning the displayed capture during a newer seek preserves provider bytes after an earlier source acquisition was cancelled": 360, - "pressing Recording after the editor closed the Application panel of an attached live run presents the saved frame": 440, - "pressing Recording after the historical session ended keeps the moment whose position save is still held by storage": 452, - "pressing Recording after the historical session ended presents the saved moment again through a new session": 465, - "pressing Recording after the historical session ended presents the saved moment again while a live run is still attached": 398, - "pressing Recording after the historical session ended still presents the saved moment when the editor fails to release the old debugger": 400, - "pressing Recording again on a displayed replay whose historical session is still running keeps its moment and its session": 355, - "pressing Recording again on a displayed replay without recorded debugger state keeps its moment without reloading it": 322, - "pressing Recording again on the same recording keeps its displayed frame until the reloaded moment is presented": 416, - "pressing Recording again while a live run is attached presents the saved frame through the same recording renderer": 369, - "re-presenting a committed recording refuses to reopen a source the learner closed": 418, - "reading a Study pane does not claim focus after the learner selects a draft during native maximization": 76, - "reading a recording while a live run is paused renews that run’s pause hold for each presented moment": 419, - "replay reads app, source and sidebar summary then restores their shared layout without changing history": 389, - "saved Study sends captured facts without copying retained source bodies into its webviews": 259, - "saved replay does not retry a non-paint viewport failure": 303, - "saved replay reports a second viewport paint loss without advancing the saved position": 332, - "saved replay survives one recorded viewport paint loss without rerunning the target": 323, - "seeking a saved recording gap keeps the keyboard in the historical source the learner selected": 663, - "seeking a saved recording gap leaves the keyboard in an unreported native view after the learner left historical source": 1175, - "seeking a saved recording gap takes no keyboard from another window after a historical source choice": 582, - "seeking from a stop without loaded values into missing history drops the Run and Debug hint": 417, - "successful Study reading clears an earlier background-window reading error": 136, - "the Run and Debug hint stays while Play advances through the same recorded stop": 513, - "the fake editor names the learner’s new empty group with no tab and reports no active text editor already while it tells its group and tab listeners (Cursor)": 65, - "the fake editor names the learner’s new empty group with no tab and reports no active text editor already while it tells its group and tab listeners (VS Code)": 67, - "the fake editor reports the text editor that had the keyboard behind a terminal opened in the editor area already while it tells its tab and group listeners (Cursor)": 70, - "the fake editor reports the text editor that had the keyboard behind a terminal opened in the editor area already while it tells its tab and group listeners (VS Code)": 73, - "the workspace harness answers a recording viewport only while its own renderer is the document in the shared Application panel": 267, - "the workspace harness live viewport leaves an attached renderer panel alone and re-handshakes only when it leaves history, like the real viewport": 146, - "the workspace harness’s historical debugger follows the model-selection scenario the real owner is held to": 352 + "failed initial pane reservation with 1 main panes and a separate part cannot create Context before an explicit retry": 664, + "failed initial pane reservation with 1 main panes and one part cannot create Context before an explicit retry": 621, + "failed initial pane reservation with 2 main panes and a separate part cannot create Context before an explicit retry": 647, + "historical source annotations identify the recorded file, time, hash and selected line and replace that identity inside a gap": 458, + "historical source capacity freezes every pinned display and permits explicit recovery after one older view is unpinned": 447, + "holding position saves in one workspace harness does not hold the saves of another, and a second hold while one is active is refused": 668, + "in Cursor beside its chat part, an agent’s Study selection that reopens a replay an agent opened earlier while the learner’s file has the keyboard gives that file nothing back and says once that the Application pane has the keyboard": 362, + "in Cursor, an agent’s Return Current from a replay after the learner’s click into the first group’s file during its layout read keeps the keyboard there, gives the chat nothing and tells nothing": 248, + "in Cursor, an agent’s Return Current from a replay leaves the keyboard in Keyboard Shortcuts the learner opened in the Wiki’s group while the arrangement’s receipt was read, and the chat gets none back": 262, + "in Cursor, an agent’s Return Current from a replay leaves the keyboard in Settings the learner opened in the Wiki’s group while the arrangement’s receipt was read, and the chat gets none back": 290, + "in Cursor, an agent’s Return Current from a replay leaves the keyboard in the empty group the learner opened while the arrangement’s receipt was read, also while the editor still reports the first group’s file, and the chat gets none back": 260, + "in Cursor, an agent’s Return Current from a replay leaves the keyboard in the empty group the learner opened while the arrangement’s receipt was read, and the chat gets none back": 272, + "in Cursor, an agent’s Return Current from a replay leaves the keyboard in the terminal the learner opened in another group after the borrow of the first group, while the editor still reports the first group’s file": 253, + "in Cursor, an agent’s Return Current from a replay refused for the learner’s change of the first group’s file during its layout read gives the chat no keyboard and tells nothing": 262, + "in Cursor, an agent’s Return Current from a replay refused right after its borrow of the first group gives the chat its keyboard back and says that nothing was arranged": 256, + "in Cursor, an agent’s Return Current from a replay while the learner’s file is in front of the first group gives the chat its keyboard back after borrowing the first group, while Cursor names its chat part’s group": 263, + "in Cursor, an agent’s Return Current from the saved replay its cold select reopened gives the chat its keyboard back after borrowing through the captured source, while Cursor names its chat part’s group": 345, + "in Cursor, an agent’s Return Current from the saved replay leaves the keyboard in the terminal the learner opened in another group after the measurement showed the captured source, while the editor still reports that source": 340, + "in Cursor, an agent’s Return Current right after its cold Study selection from the chat gives the chat its keyboard back, also after its measurement showed the captured source with the keyboard": 345, + "in Cursor, an agent’s Study selection that reopens a replay an agent opened earlier, while the learner’s file has the keyboard, says once that the Application pane has it": 357, + "in Cursor, an agent’s cold Study selection that reopens a replay while the editor names the Repository Wiki’s group and the chat input has the keyboard gives the chat its keyboard back and says so once": 354, + "in Cursor, an agent’s replay open after the learner’s click into the first group’s file during its layout read keeps the keyboard there, gives the chat nothing and tells no keyboard sentence": 251, + "in Cursor, an agent’s replay open from the chat tab gives the chat its keyboard back and says so the first time in an editor session only": 357, + "in Cursor, an agent’s replay open refused for the learner’s change of the first group’s file during its layout read gives the chat no keyboard and tells nothing": 149, + "in Cursor, an agent’s replay open refused right after its borrow of the first group gives the chat its keyboard back and says that nothing was arranged": 147, + "in Cursor, an agent’s replay open refused right after its borrow still gives the chat its keyboard back and says that nothing was arranged after an earlier focus request was refused for the learner’s newer choice": 277, + "in VS Code, an agent’s Study selection that reopens a replay an agent opened earlier, while the learner’s file has the keyboard, says once that the Application pane has it": 250, + "one bottom playback seek from a hidden Application commits the requested recorded moment without another target action": 458, + "opening a recording never tells the learner the captured source is not ready while its own first frame is still presenting": 267, + "opening a recording restores its captured source after context focus covers the manually moved source group": 474, + "opening a recording while a live run is attached presents its saved frame": 344, + "opening a recording while the bottom pane holds keyboard reveals Summary without taking that keyboard": 363, + "opening the recording of this session’s own run while no study is selected shows no \"another configured article\" error during or after the load": 270, + "ordinary Study entry retains manually shared pane columns until the learner explicitly arranges them": 68, + "pinning the displayed capture during a newer seek preserves provider bytes after an earlier source acquisition was cancelled": 401, + "pressing Recording after the editor closed the Application panel of an attached live run presents the saved frame": 394, + "pressing Recording after the historical session ended keeps the moment whose position save is still held by storage": 386, + "pressing Recording after the historical session ended presents the saved moment again through a new session": 398, + "pressing Recording after the historical session ended presents the saved moment again while a live run is still attached": 381, + "pressing Recording after the historical session ended still presents the saved moment when the editor fails to release the old debugger": 390, + "pressing Recording again on a displayed replay whose historical session is still running keeps its moment and its session": 337, + "pressing Recording again on a displayed replay without recorded debugger state keeps its moment without reloading it": 309, + "pressing Recording again on the same recording keeps its displayed frame until the reloaded moment is presented": 398, + "pressing Recording again while a live run is attached presents the saved frame through the same recording renderer": 328, + "re-presenting a committed recording refuses to reopen a source the learner closed": 409, + "reading a Study pane does not claim focus after the learner selects a draft during native maximization": 86, + "reading a recording while a live run is paused renews that run’s pause hold for each presented moment": 379, + "replay reads app, source and sidebar summary then restores their shared layout without changing history": 357, + "saved Study sends captured facts without copying retained source bodies into its webviews": 270, + "saved replay does not retry a non-paint viewport failure": 268, + "saved replay reports a second viewport paint loss without advancing the saved position": 290, + "saved replay survives one recorded viewport paint loss without rerunning the target": 426, + "seeking a saved recording gap keeps the keyboard in the historical source the learner selected": 678, + "seeking a saved recording gap leaves the keyboard in an unreported native view after the learner left historical source": 601, + "seeking a saved recording gap takes no keyboard from another window after a historical source choice": 627, + "seeking from a stop without loaded values into missing history drops the Run and Debug hint": 415, + "successful Study reading clears an earlier background-window reading error": 139, + "the Run and Debug hint stays while Play advances through the same recorded stop": 436, + "the fake editor names the learner’s new empty group with no tab and reports no active text editor already while it tells its group and tab listeners (Cursor)": 66, + "the fake editor names the learner’s new empty group with no tab and reports no active text editor already while it tells its group and tab listeners (VS Code)": 69, + "the fake editor reports the text editor that had the keyboard behind a terminal opened in the editor area already while it tells its tab and group listeners (Cursor)": 69, + "the fake editor reports the text editor that had the keyboard behind a terminal opened in the editor area already while it tells its tab and group listeners (VS Code)": 71, + "the workspace harness answers a recording viewport only while its own renderer is the document in the shared Application panel": 275, + "the workspace harness live viewport leaves an attached renderer panel alone and re-handshakes only when it leaves history, like the real viewport": 164, + "the workspace harness’s historical debugger follows the model-selection scenario the real owner is held to": 349 } }, "studyWorkspaceRepositoryReader.test.js": { - "totalMs": 6954 + "totalMs": 6600 }, "studyWorkspaceStorage.test.js": { - "totalMs": 14713, + "totalMs": 15018, "tests": { - "Close drains an accepted workbench arrangement batch without dispatching another layout change afterward": 188, - "Close during initialization prevents the pending Open from recreating reader panes": 78, - "Open replay whose load fails while the ledger write of the recording shown before it is still pending ends within its bound and shows the failure": 4537, - "Retry storage keeps the line of a ledger it could not clean of studies removed by hand, although the rest of the retry succeeds": 73, - "Study Run requires an editor-agent repository declaration and cannot launch an embedded target": 73, - "a Retry whose forced checkpoint cannot write the history shows the History not saved line once and no archive line": 190, - "a Retry whose repair of the saved studies fails shows that failure on the archive line and no History not saved line": 193, - "a cold reader keeps the newer selected study and its observation when an older Retry read completes": 278, - "a failed latest image checkpoint stays failed and partial while the older captured facts remain readable until Retry": 185, - "a host-suppressed vscode.setEditorLayout failure warns the learner and cannot claim the incomplete layout for a later Wiki return": 865, - "a queued checkbox from a previous configured profile cannot change another article understanding or raise an error": 70, - "a recording opened for the status bar's Open replay is the study the reader opens on after a restart": 412, - "a recording whose load failed leaves the earlier selection in the ledger, and the reader opens on that study after a restart": 1611, - "a recording whose load was replaced by another recording before it was shown never writes its study to the ledger": 385, - "a slow archive writer does not delay inspection of the committed live pause": 118, - "a source reveal that arrives while the reader is still reading the run from before the observation shows that observation": 157, - "a source reveal whose display is superseded by another reveal of the same observation waits for that display and succeeds": 189, - "a successful runtime with a rejected final history write stays partial in both service and reader until Retry": 195, - "an MCP source reveal rejects a host rendering failure instead of recording a successful reveal": 124, - "an interpretation added to an earlier stopped run persists while the later run keeps execution ownership": 242, - "an obsolete failed history read cannot downgrade a newer verified reader or API checkpoint": 162, - "an older successful save cannot erase the failed final archive from explicit Retry": 344, - "an understanding choice made while an earlier one still waits to be written is not taken and does not replace it: the progress line says so, and Retry storage / refresh saves the earlier choice alone": 351, - "an understanding choice the ledger refuses waits with the line “Not saved: …” and Retry storage / refresh, marks nothing by itself, and the Retry that writes it saves the choice the learner made and leaves no line": 378, - "every opened recording writes its study to the ledger once, and seeking within it writes nothing more": 615, - "failed disk verification downgrades a formerly saved attached study and Retry restores the exact checkpoint": 206, - "failed disk verification downgrades a formerly saved retired study and Retry restores the exact checkpoint": 197, - "history selected during a retained run save shows the new explanation before claiming saved evidence": 284, - "native transient half-pixel layout sizes are finalized in the workbench before Wiki ownership is verified": 197, - "reopening the reader restores a captured source tab after Close removed it": 76, - "retiring a failed final checkpoint stays partial with an older saved projection": 243, - "retiring a failed final checkpoint stays partial without any saved catalog entry": 196, - "retiring before the next polling tick preserves the last accepted interpretation and terminal state": 111, - "retiring the reader leaves a study whose content did not change since its last save byte-identical, and still writes one that changed": 175, - "starting a live viewport after closing recorded Study leaves its old film closed and preserves the saved replay position": 362, - "starting a live viewport while recorded Study is open preserves the independently selected film": 394, - "updating repository source and extension location preserves recorded bytes and learner history while requesting source review": 258 + "Close drains an accepted workbench arrangement batch without dispatching another layout change afterward": 172, + "Close during initialization prevents the pending Open from recreating reader panes": 71, + "Open replay whose load fails while the ledger write of the recording shown before it is still pending ends within its bound and shows the failure": 4571, + "Retry storage keeps the line of a ledger it could not clean of studies removed by hand, although the rest of the retry succeeds": 90, + "Study Run requires an editor-agent repository declaration and cannot launch an embedded target": 64, + "a Retry whose forced checkpoint cannot write the history shows the History not saved line once and no archive line": 234, + "a Retry whose repair of the saved studies fails shows that failure on the archive line and no History not saved line": 221, + "a cold reader keeps the newer selected study and its observation when an older Retry read completes": 248, + "a failed latest image checkpoint stays failed and partial while the older captured facts remain readable until Retry": 183, + "a host-suppressed vscode.setEditorLayout failure warns the learner and cannot claim the incomplete layout for a later Wiki return": 839, + "a queued checkbox from a previous configured profile cannot change another article understanding or raise an error": 63, + "a recording opened for the status bar's Open replay is the study the reader opens on after a restart": 414, + "a recording whose load failed leaves the earlier selection in the ledger, and the reader opens on that study after a restart": 1452, + "a recording whose load was replaced by another recording before it was shown never writes its study to the ledger": 429, + "a slow archive writer does not delay inspection of the committed live pause": 122, + "a source reveal that arrives while the reader is still reading the run from before the observation shows that observation": 139, + "a source reveal whose display is superseded by another reveal of the same observation waits for that display and succeeds": 170, + "a successful runtime with a rejected final history write stays partial in both service and reader until Retry": 187, + "an MCP source reveal rejects a host rendering failure instead of recording a successful reveal": 113, + "an interpretation added to an earlier stopped run persists while the later run keeps execution ownership": 227, + "an obsolete failed history read cannot downgrade a newer verified reader or API checkpoint": 149, + "an older successful save cannot erase the failed final archive from explicit Retry": 361, + "an understanding choice made while an earlier one still waits to be written is not taken and does not replace it: the progress line says so, and Retry storage / refresh saves the earlier choice alone": 388, + "an understanding choice the ledger refuses waits with the line “Not saved: …” and Retry storage / refresh, marks nothing by itself, and the Retry that writes it saves the choice the learner made and leaves no line": 498, + "every opened recording writes its study to the ledger once, and seeking within it writes nothing more": 969, + "failed disk verification downgrades a formerly saved attached study and Retry restores the exact checkpoint": 175, + "failed disk verification downgrades a formerly saved retired study and Retry restores the exact checkpoint": 193, + "history selected during a retained run save shows the new explanation before claiming saved evidence": 292, + "native transient half-pixel layout sizes are finalized in the workbench before Wiki ownership is verified": 209, + "reopening the reader restores a captured source tab after Close removed it": 65, + "retiring a failed final checkpoint stays partial with an older saved projection": 228, + "retiring a failed final checkpoint stays partial without any saved catalog entry": 190, + "retiring before the next polling tick preserves the last accepted interpretation and terminal state": 105, + "retiring the reader leaves a study whose content did not change since its last save byte-identical, and still writes one that changed": 179, + "starting a live viewport after closing recorded Study leaves its old film closed and preserves the saved replay position": 356, + "starting a live viewport while recorded Study is open preserves the independently selected film": 387, + "updating repository source and extension location preserves recorded bytes and learner history while requesting source review": 265 } }, "studyWorkspaceTestReplay.test.js": { - "totalMs": 2314 + "totalMs": 2321 + }, + "studyWorkspaceTestReplayOutput.test.js": { + "totalMs": 4856 + }, + "studyWorkspaceTestReplaySource.test.js": { + "totalMs": 4190 }, "takenStopPosition.test.js": { "totalMs": 1 }, + "testOutputHtml.test.js": { + "totalMs": 1 + }, "textEditorColumn.test.js": { "totalMs": 1 }, @@ -3541,25 +3582,25 @@ "totalMs": 23 }, "verifyVitestTestResult.test.js": { - "totalMs": 13 + "totalMs": 16 }, "waitForWikiChatAnswer.test.js": { - "totalMs": 5 + "totalMs": 4 }, "waitForWikiOutputChange.test.js": { "totalMs": 1 }, "waitForWikiPublish.test.js": { - "totalMs": 57 + "totalMs": 56 }, "watchWikiChatReply.test.js": { - "totalMs": 2 + "totalMs": 3 }, "watchWikiUpdateSigns.test.js": { "totalMs": 1 }, "webviewFocus.test.js": { - "totalMs": 2511 + "totalMs": 2514 }, "wikiManifestIdentity.test.js": { "totalMs": 6 @@ -3571,205 +3612,205 @@ "totalMs": 1 }, "wikiPageWorker.test.js": { - "totalMs": 31874, + "totalMs": 31991, "tests": { - "a 2 MiB page of nested formatting elements that drives a page worker toward its heap limit leaves the process that runs the worker alive, and is refused at the memory limit or served, never failed": 2037, + "a 2 MiB page of nested formatting elements that drives a page worker toward its heap limit leaves the process that runs the worker alive, and is refused at the memory limit or served, never failed": 2177, "a page asked for while a retired idle worker’s thread does not end gets a worker once that thread is counted as lost at the stop limit and is served, and once that thread has ended two pages asked for at once still get one worker between them": 2057, - "a page asked for while an idle worker whose time is up is being stopped gets its worker only once that worker’s thread has ended": 357, - "a page that gets a worker before its wait limit is served by that worker, also when the answer comes after the limit": 1617, - "a page that needs more memory than a page worker may use is refused at the memory limit, while a small page is still served under the same limit": 154, - "a page that waited for a free worker gets its whole deadline from the moment a worker takes it, and is served": 1530, - "a page that waits behind a page stopped at the deadline gets its worker only once the stopped worker’s thread has ended": 529, - "a page that waits behind a stopped worker whose thread does not end gets a worker once the stop limit has passed, and is served": 829, - "a page that waits behind stopped workers whose threads do not end is answered as busy at the wait limit and leaves the line, so the page asked for after it waits and is served once a thread ends": 4639, + "a page asked for while an idle worker whose time is up is being stopped gets its worker only once that worker’s thread has ended": 355, + "a page that gets a worker before its wait limit is served by that worker, also when the answer comes after the limit": 1615, + "a page that needs more memory than a page worker may use is refused at the memory limit, while a small page is still served under the same limit": 159, + "a page that waited for a free worker gets its whole deadline from the moment a worker takes it, and is served": 1529, + "a page that waits behind a page stopped at the deadline gets its worker only once the stopped worker’s thread has ended": 526, + "a page that waits behind a stopped worker whose thread does not end gets a worker once the stop limit has passed, and is served": 832, + "a page that waits behind stopped workers whose threads do not end is answered as busy at the wait limit and leaves the line, so the page asked for after it waits and is served once a thread ends": 4634, "a page whose request goes while it is prepared stops its worker, and the next page gets its place at once": 37, "a page whose request went before it was asked for is answered as failed at once, and no worker starts for it": 1, "a page whose worker answers something that is no prepared page is answered as failed, that worker ends, and the next page gets a new worker and is served": 39, "a page whose worker cannot start is answered as failed, not with an error, and the next page gets a worker that starts": 26, "a page whose worker thread ends before it answers, without an error, is answered as failed, and the page waiting behind it gets a worker once that thread has ended and is served": 39, - "a stopped worker that kept its place past the stop limit while the lost threads were at their bound gives its place back once a lost thread ends, and the page behind it is served while its own thread is still ending": 2339, - "a worker left without a page for longer than its idle time ends, and the next page gets a new worker": 359, + "a stopped worker that kept its place past the stop limit while the lost threads were at their bound gives its place back once a lost thread ends, and the page behind it is served while its own thread is still ending": 2335, + "a worker left without a page for longer than its idle time ends, and the next page gets a new worker": 374, "a worker stopped at the deadline prepares no later page: it ends, and the next page gets a new worker": 529, - "a worker whose heap grew large while it prepared an ordinary page of more than 1 MB ends after its answer, and the next page gets a new worker": 160, - "an idle worker retired while the lost threads are at their bound gives its place back once a lost thread ends, and the page asked for during its stop is served while that worker’s own thread is still ending": 2160, - "an idle worker retired while the lost threads are at their bound keeps its place past the stop limit, and the page asked for during its stop gets a worker once that worker’s own thread has ended, while the lost thread still runs": 2168, - "an ordinary page of more than 1 MB is served under the page worker’s heap limit": 144, + "a worker whose heap grew large while it prepared an ordinary page of more than 1 MB ends after its answer, and the next page gets a new worker": 161, + "an idle worker retired while the lost threads are at their bound gives its place back once a lost thread ends, and the page asked for during its stop is served while that worker’s own thread is still ending": 2157, + "an idle worker retired while the lost threads are at their bound keeps its place past the stop limit, and the page asked for during its stop gets a worker once that worker’s own thread has ended, while the lost thread still runs": 2161, + "an ordinary page of more than 1 MB is served under the page worker’s heap limit": 130, "no more than two pages are prepared at once: a third page waits for a free worker, and a page whose request goes while it waits is answered at once without a worker": 2028, - "once a lost thread has ended, the next stopped worker whose thread does not end gives its place back at the stop limit, the page behind it is served, and once both lost threads ended two pages asked for at once still get one worker between them": 3136, + "once a lost thread has ended, the next stopped worker whose thread does not end gives its place back at the stop limit, the page behind it is served, and once both lost threads ended two pages asked for at once still get one worker between them": 3133, "the page workers that may run at once may together use no more heap than two page workers of 512 MB": 0, - "two pages prepared one after another are prepared by the same worker thread": 29, + "two pages prepared one after another are prepared by the same worker thread": 27, "when the worker of a page that waited cannot start, that page is answered as failed and the page behind it still gets a worker": 36, - "while as many stopped threads are lost as page workers may run at once, a further stopped worker keeps its place until its thread has ended": 2836, - "while both page workers are ending, the two pages the reader admits in their place wait and are served, and a page beyond the reader’s bound is still refused as busy": 530, - "while two pages are prepared and four wait, a further page is refused as busy at once without a worker, and the four waiting pages are still served": 1529 + "while as many stopped threads are lost as page workers may run at once, a further stopped worker keeps its place until its thread has ended": 2835, + "while both page workers are ending, the two pages the reader admits in their place wait and are served, and a page beyond the reader’s bound is still refused as busy": 529, + "while two pages are prepared and four wait, a further page is refused as busy at once without a worker, and the four waiting pages are still served": 1530 } }, "wikiQuestionPage.test.js": { - "totalMs": 89 + "totalMs": 137 }, "wikiReaderShell.test.js": { - "totalMs": 406 + "totalMs": 486 }, "wikiUpdateFlow.test.js": { - "totalMs": 11626, + "totalMs": 11212, "tests": { - "Update anyway is not offered while another window’s update is running": 8, - "a Cancel pressed while the watch reads a site the chat has published stops the watch with that new site named as published, and leaves no reservation, and a press after a later source change starts the next update instead of waiting for a chat that has finished": 85, - "a Cursor Wiki update that fails ends as failed with the agent message and keeps the site": 16, - "a Cursor Wiki update that publishes ends as succeeded with the new identity": 10, - "a Cursor Wiki update the learner cancels ends as cancelled and shows a cancelled notice, no error": 22, - "a Cursor agent that does not stop is not waited for longer than the termination grace when the window closes": 116, - "a Cursor agent that ends its turn without publishing is a failure that kept the site": 11, - "a Cursor agent that publishes and then fails is shown as a failure that replaced the site, not one that kept it": 8, - "a Cursor run whose publish was stopped inside its swap says the Wiki is missing and names the recovery, and the next press names the same step": 7, + "Update anyway is not offered while another window’s update is running": 12, + "a Cancel pressed while the watch reads a site the chat has published stops the watch with that new site named as published, and leaves no reservation, and a press after a later source change starts the next update instead of waiting for a chat that has finished": 92, + "a Cursor Wiki update that fails ends as failed with the agent message and keeps the site": 15, + "a Cursor Wiki update that publishes ends as succeeded with the new identity": 14, + "a Cursor Wiki update the learner cancels ends as cancelled and shows a cancelled notice, no error": 11, + "a Cursor agent that does not stop is not waited for longer than the termination grace when the window closes": 108, + "a Cursor agent that ends its turn without publishing is a failure that kept the site": 6, + "a Cursor agent that publishes and then fails is shown as a failure that replaced the site, not one that kept it": 7, + "a Cursor run whose publish was stopped inside its swap says the Wiki is missing and names the recovery, and the next press names the same step": 10, "a Cursor update during which another repository was opened ends as failed and says to reopen the Wiki": 6, - "a Cursor update that runs past its bound ends as timed out, the state VS Code reports for the same event": 10, - "a VS Code Wiki update shows running, then the new identity once the editor agent publishes": 141, - "a VS Code update sends its request into a chat session of its own: the chat is revealed, the editor’s New Chat has returned, and only then the request is sent": 26, - "a VS Code update that ends at its start at a moment the Wiki folder cannot be read does not stay running: the press returns, the update ends with the sentence that Codebook could not read how it ended, and the next press sends a request": 14, - "a VS Code update that publishes the same sources and revision again still ends as succeeded": 85, - "a VS Code watch that itself breaks off ends the update with the sentence that Codebook stopped watching while the chat can still publish, and the next press is answered with the wait for that chat and Update anyway, not with a second request": 70, + "a Cursor update that runs past its bound ends as timed out, the state VS Code reports for the same event": 6, + "a VS Code Wiki update shows running, then the new identity once the editor agent publishes": 178, + "a VS Code update sends its request into a chat session of its own: the chat is revealed, the editor’s New Chat has returned, and only then the request is sent": 36, + "a VS Code update that ends at its start at a moment the Wiki folder cannot be read does not stay running: the press returns, the update ends with the sentence that Codebook could not read how it ended, and the next press sends a request": 10, + "a VS Code update that publishes the same sources and revision again still ends as succeeded": 66, + "a VS Code watch that itself breaks off ends the update with the sentence that Codebook stopped watching while the chat can still publish, and the next press is answered with the wait for that chat and Update anyway, not with a second request": 114, "a VS Code watch that passes its 15 minutes while the chat still works says what held then and what each state of the chat asks for; a press before the chat publishes is refused with Update anyway, as the notice says, and after the chat’s publish nothing the notice says is untrue and a press finds the Wiki current": 116, - "a VS Code watch that saw the chat’s candidate goes on waiting for that chat after a publish that left the candidate beside the Wiki, and stops waiting once the candidate is gone and a site was published after the watch’s end": 146, + "a VS Code watch that saw the chat’s candidate goes on waiting for that chat after a publish that left the candidate beside the Wiki, and stops waiting once the candidate is gone and a site was published after the watch’s end": 129, "a VS Code watch that was stopped before the chat staged anything still refuses the next press, until the learner chooses Update anyway": 87, - "a VS Code watch the learner cancels at a moment the Wiki folder cannot be read does not stay running: the update ends with the sentence that Codebook could not read how it ended, claims nothing about the site, and the next press is answered with the wait for the chat and Update anyway": 68, - "a Wiki of a project without a Git repository whose indexed sources match says that added files are not checked, and opens no chat request": 13, - "a Wiki that already matches the source says so and opens no chat request": 7, - "a chat command that never returns ends the update as failed at its bound with the sentence that the request may still be in the chat; the retry sends no second request and is answered with the wait for that chat and Update anyway, which then starts the update": 142, - "a chat command that returns at once with nothing while no chat replies leaves the update running until one millisecond before the bound and ends it at the bound, with no command run against the chat": 15, - "a chat that answers with an error in the moment the 30 second bound passes ends the update with the sentence of a reply with an error and its message, as within the bound, and no chat command runs": 18, - "a chat that asks for its first approval right after Codebook left its request at the bound starts no watch: the page and the notice keep the sentence that the request may still be in the chat": 16, - "a chat that cannot open ends the update as failed, says what to install and shows one error notice with Open LLM Wiki that does not claim the update could not start": 7, - "a chat that cannot open with a long error is recorded as Codebook’s own sentence, with the error cut and the next step kept": 8, - "a chat that completes its reply in the moment the 30 second bound passes ends the update with the sentence that the chat finished its reply without publishing, not that its request may still be in the chat, and no chat command runs": 16, + "a VS Code watch the learner cancels at a moment the Wiki folder cannot be read does not stay running: the update ends with the sentence that Codebook could not read how it ended, claims nothing about the site, and the next press is answered with the wait for the chat and Update anyway": 61, + "a Wiki of a project without a Git repository whose indexed sources match says that added files are not checked, and opens no chat request": 8, + "a Wiki that already matches the source says so and opens no chat request": 4, + "a chat command that never returns ends the update as failed at its bound with the sentence that the request may still be in the chat; the retry sends no second request and is answered with the wait for that chat and Update anyway, which then starts the update": 139, + "a chat command that returns at once with nothing while no chat replies leaves the update running until one millisecond before the bound and ends it at the bound, with no command run against the chat": 16, + "a chat that answers with an error in the moment the 30 second bound passes ends the update with the sentence of a reply with an error and its message, as within the bound, and no chat command runs": 16, + "a chat that asks for its first approval right after Codebook left its request at the bound starts no watch: the page and the notice keep the sentence that the request may still be in the chat": 20, + "a chat that cannot open ends the update as failed, says what to install and shows one error notice with Open LLM Wiki that does not claim the update could not start": 6, + "a chat that cannot open with a long error is recorded as Codebook’s own sentence, with the error cut and the next step kept": 6, + "a chat that completes its reply in the moment the 30 second bound passes ends the update with the sentence that the chat finished its reply without publishing, not that its request may still be in the chat, and no chat command runs": 15, "a chat that opens the Wiki’s manifest for the request before it replies is watched for its publish": 15, "a chat that runs the publisher in a terminal for the request before it replies is watched for its publish": 16, - "a chat that shows a first sign after 5 seconds and completes its reply after 40 seconds without publishing ends the update at once with the sentence that it finished without publishing, leaves no marker, and the next press sends a request": 81, - "a chat that takes the request and never answers ends the update after 30 seconds, on the page and as an error notice, with the sentence that Codebook saw no sign of the update and that its request may still be in the chat": 17, - "a chat whose first answer comes after 40 seconds is left to the learner at the 30 seconds: no Cancel runs, the page says that the request may still be in the chat, and the late answer starts no watch": 18, + "a chat that shows a first sign after 5 seconds and completes its reply after 40 seconds without publishing ends the update at once with the sentence that it finished without publishing, leaves no marker, and the next press sends a request": 76, + "a chat that takes the request and never answers ends the update after 30 seconds, on the page and as an error notice, with the sentence that Codebook saw no sign of the update and that its request may still be in the chat": 16, + "a chat whose first answer comes after 40 seconds is left to the learner at the 30 seconds: no Cancel runs, the page says that the request may still be in the chat, and the late answer starts no watch": 17, "a chat whose reply ends with an error after its first sign ends the update at once with the sentence that quotes the chat’s message": 65, - "a chat whose reply reports an error ends the update at once with a sentence that quotes the chat’s message and names no 30 seconds, on the page and in the notice": 7, - "a chat whose reply waits for a confirmation 20 seconds after it took the request is watched for its publish and not ended at 30 seconds": 15, - "a chat whose reply waits for a confirmation after its first sign stays watched": 52, - "a chat whose reply waits for a confirmation in the moment the 30 second bound passes is watched for its publish, as within the bound, and no chat command runs": 18, - "a chat whose response is complete after it published ends the update as Updated at once, without a watch": 8, - "a chat whose response is complete and that published nothing ends the update at once with the sentence that it finished without publishing: no watch, no marker left, and the next press sends a request": 10, + "a chat whose reply reports an error ends the update at once with a sentence that quotes the chat’s message and names no 30 seconds, on the page and in the notice": 5, + "a chat whose reply waits for a confirmation 20 seconds after it took the request is watched for its publish and not ended at 30 seconds": 16, + "a chat whose reply waits for a confirmation after its first sign stays watched": 47, + "a chat whose reply waits for a confirmation in the moment the 30 second bound passes is watched for its publish, as within the bound, and no chat command runs": 15, + "a chat whose response is complete after it published ends the update as Updated at once, without a watch": 6, + "a chat whose response is complete and that published nothing ends the update at once with the sentence that it finished without publishing: no watch, no marker left, and the next press sends a request": 9, "a configured Wiki output folder is the one the update state names": 8, - "a failed, refused or timed-out update’s notification is an error notice with Open LLM Wiki, so the editor keeps it until dismissed": 155, - "a file the learner opens, a terminal that opens and a command the learner runs while the chat does not answer are not taken for the chat’s work: the update still ends at the 30 seconds": 28, - "a folder the publisher prepares beside the Wiki counts as the chat’s work although the editor reported no step, and the update is watched": 29, - "a learner who moved to another chat during the 30 seconds keeps the request in progress there: Codebook runs no Cancel and no queue command, and reports its own request as possibly still in the chat": 17, - "a marker a killed editor of 0.2.29.0 left twenty-two minutes ago does not refuse the update, although a process has its id": 8, - "a marker file another window is writing refuses an Update before this window’s own stopped watch is weighed, so Update anyway is not offered": 64, - "a new publish whose manifest stays unreadable ends the run after its grace with the recovery request, and the next press names the same step": 161, - "a press after a publish stopped inside its swap names the unfinished publish, not a missing Wiki": 8, - "a press that finds another window’s stopped watch and this window’s own at once names the other window’s chat, and Update anyway on it is refused again naming this window’s own chat, with no chat request": 160, - "a press while a publish has held the Wiki’s publish lock for a minute says that the lock is held and its publish may still run, not that an earlier publish did not finish": 3, - "a publish Codebook cannot check against the source passes the reason on and says a retry will not help": 62, - "a publish that finishes while the start check waits for it is the generation the run starts from, not one the watch later takes for its own result": 43, - "a publish that no longer matches the source says the site was replaced and how many files changed": 63, - "a reply that reports an error ends the update without the chat’s Cancel and without its queue command": 5, - "a request the chat works on is left to the chat when the 30 seconds pass and when the learner cancels the watch: the editor ran no command after the request": 67, + "a failed, refused or timed-out update’s notification is an error notice with Open LLM Wiki, so the editor keeps it until dismissed": 119, + "a file the learner opens, a terminal that opens and a command the learner runs while the chat does not answer are not taken for the chat’s work: the update still ends at the 30 seconds": 21, + "a folder the publisher prepares beside the Wiki counts as the chat’s work although the editor reported no step, and the update is watched": 26, + "a learner who moved to another chat during the 30 seconds keeps the request in progress there: Codebook runs no Cancel and no queue command, and reports its own request as possibly still in the chat": 16, + "a marker a killed editor of 0.2.29.0 left twenty-two minutes ago does not refuse the update, although a process has its id": 7, + "a marker file another window is writing refuses an Update before this window’s own stopped watch is weighed, so Update anyway is not offered": 59, + "a new publish whose manifest stays unreadable ends the run after its grace with the recovery request, and the next press names the same step": 160, + "a press after a publish stopped inside its swap names the unfinished publish, not a missing Wiki": 4, + "a press that finds another window’s stopped watch and this window’s own at once names the other window’s chat, and Update anyway on it is refused again naming this window’s own chat, with no chat request": 157, + "a press while a publish has held the Wiki’s publish lock for a minute says that the lock is held and its publish may still run, not that an earlier publish did not finish": 4, + "a publish Codebook cannot check against the source passes the reason on and says a retry will not help": 73, + "a publish that finishes while the start check waits for it is the generation the run starts from, not one the watch later takes for its own result": 40, + "a publish that no longer matches the source says the site was replaced and how many files changed": 61, + "a reply that reports an error ends the update without the chat’s Cancel and without its queue command": 6, + "a request the chat works on is left to the chat when the 30 seconds pass and when the learner cancels the watch: the editor ran no command after the request": 66, "a second start from the browser link before the chat’s first sign names nothing on screen: it says that the progress is in the browser reader and that the status bar shows the watch once the chat has taken up the request": 7, - "a second start from the browser link while the watch is shown in the status bar is refused before the confirmation is shown and says that the progress is in the browser reader and in the status bar": 8, - "a second window’s Update is refused while the first window’s run has staged nothing yet": 21, - "a second window’s Update is refused while the first window’s stopped watch is still inside its bound": 91, - "a second window’s Update is refused with the sentence of another window’s stopped watch while nothing was published since, and starts with no refusal once a site was published after that watch’s end": 68, - "a start during whose checks the Wiki is published twice is refused with the sentence that the Wiki was published again, which keeps its end that the last usable site is kept, and sends no request": 7, - "a start whose step throws before the request is sent ends the update as failed with what was thrown, leaves no marker, sends nothing to the chat, and the next press is not answered with \"already updating\"": 9, - "a stopped VS Code watch whose record cannot be stored leaves no unhandled rejection and keeps its reservation across reload and process exit, so neither window starts a second chat without Update anyway": 65, - "a stopped watch whose reservation could not be written because another window held the claim on the marker writes it at the next attempt once the claim is free, and another window is then refused for the chat that may still publish, with Update anyway": 829, - "a stopped watch’s reservation leaves the disk when its window closes, and not the marker of a window that took the update over": 154, - "a watched VS Code update whose chat finishes its reply without publishing, at a moment the editor cannot show the notice of that end, is not recorded as a watch that broke off: the page has the sentence of the finished reply, the marker is gone, nothing is left unhandled, and the next press sends a request": 103, - "a window that closes while it watches a VS Code update waits until the record of the run it stops is written, so the reloaded window starts the next update and does not read the record of the stopped watch before it": 179, - "a window that closes while the VS Code chat is still opening waits until the run it stopped has ended, and leaves no marker beside the Wiki": 114, - "a window that closes while the failed end of a start that threw is being recorded waits for it, and the marker is gone when the close returns": 123, - "a window that closes while the removal of its marker waits for its next attempt makes that attempt as it closes, and the marker leaves the disk with the window": 599, - "a window that closes within a stopped watch’s bound keeps that watch’s reservation on disk when a later finished update of another output took its record’s place in storage": 119, - "a window that is reloaded after its VS Code watch was stopped still answers the next press with the wait for that chat and Update anyway, from the record of the run in its workspace state": 65, - "a window that was reloaded while it watched a VS Code update starts the next update at once": 14, - "after a VS Code watch passed its 15 minutes, a press on Update LLM Wiki followed by Update anyway in the notification of the refusal starts the update again, the step the notice of the bound names for a chat that stopped": 131, - "after a VS Code watch stopped at its 15 minutes, a press before the chat published is refused with the sentence that Codebook waits for that chat and with Update anyway; after the chat’s publish a press for a source that changed again starts the update with no refusal": 126, - "after a stopped watch on one Wiki output and an update of another output, a press on the first output again within the watch bound is refused for the chat that may still work there and offers Update anyway": 124, + "a second start from the browser link while the watch is shown in the status bar is refused before the confirmation is shown and says that the progress is in the browser reader and in the status bar": 6, + "a second window’s Update is refused while the first window’s run has staged nothing yet": 8, + "a second window’s Update is refused while the first window’s stopped watch is still inside its bound": 104, + "a second window’s Update is refused with the sentence of another window’s stopped watch while nothing was published since, and starts with no refusal once a site was published after that watch’s end": 66, + "a start during whose checks the Wiki is published twice is refused with the sentence that the Wiki was published again, which keeps its end that the last usable site is kept, and sends no request": 15, + "a start whose step throws before the request is sent ends the update as failed with what was thrown, leaves no marker, sends nothing to the chat, and the next press is not answered with \"already updating\"": 8, + "a stopped VS Code watch whose record cannot be stored leaves no unhandled rejection and keeps its reservation across reload and process exit, so neither window starts a second chat without Update anyway": 63, + "a stopped watch whose reservation could not be written because another window held the claim on the marker writes it at the next attempt once the claim is free, and another window is then refused for the chat that may still publish, with Update anyway": 820, + "a stopped watch’s reservation leaves the disk when its window closes, and not the marker of a window that took the update over": 142, + "a watched VS Code update whose chat finishes its reply without publishing, at a moment the editor cannot show the notice of that end, is not recorded as a watch that broke off: the page has the sentence of the finished reply, the marker is gone, nothing is left unhandled, and the next press sends a request": 79, + "a window that closes while it watches a VS Code update waits until the record of the run it stops is written, so the reloaded window starts the next update and does not read the record of the stopped watch before it": 178, + "a window that closes while the VS Code chat is still opening waits until the run it stopped has ended, and leaves no marker beside the Wiki": 109, + "a window that closes while the failed end of a start that threw is being recorded waits for it, and the marker is gone when the close returns": 108, + "a window that closes while the removal of its marker waits for its next attempt makes that attempt as it closes, and the marker leaves the disk with the window": 642, + "a window that closes within a stopped watch’s bound keeps that watch’s reservation on disk when a later finished update of another output took its record’s place in storage": 111, + "a window that is reloaded after its VS Code watch was stopped still answers the next press with the wait for that chat and Update anyway, from the record of the run in its workspace state": 60, + "a window that was reloaded while it watched a VS Code update starts the next update at once": 11, + "after a VS Code watch passed its 15 minutes, a press on Update LLM Wiki followed by Update anyway in the notification of the refusal starts the update again, the step the notice of the bound names for a chat that stopped": 125, + "after a VS Code watch stopped at its 15 minutes, a press before the chat published is refused with the sentence that Codebook waits for that chat and with Update anyway; after the chat’s publish a press for a source that changed again starts the update with no refusal": 128, + "after a stopped watch on one Wiki output and an update of another output, a press on the first output again within the watch bound is refused for the chat that may still work there and offers Update anyway": 122, "an Update beside a marker file this user may not read, written 3 s before, is refused with the sentence that names the file, what can make it readable and when the refusal ends, and the file stays": 4, - "an Update is refused with the sentence of a starting update while another window’s marker file has no content yet, and the file stays": 5, - "an Update that meets a marker nobody owns while another window holds the claim on it is refused with the sentence of a starting or ending update, and the marker and the claim stay": 7, - "an update of a Wiki published without recorded page hashes whose index.html was deleted starts": 6, - "an update of a Wiki that belongs to another checkout says the update could not start, without an \"Error:\" prefix, and the page reads the same reason as a failed start": 13, - "an update of a Wiki whose index.html was deleted is refused as a missing generated page that names index.html, with no file error and no chat request": 8, - "an update of a project without a Git repository ends as Updated and says that no revision is recorded and that added files are not checked": 72, - "an update that fails with a thrown object that only carries a message shows that message, not [object Object]": 7, - "an update whose end could not remove its marker because another window held the claim on it shows its end at once, refuses another window as beside a running update meanwhile, and removes the marker at its next attempt once the claim is free, after which that window starts": 1098, - "an update whose start checks throw is answered on the page as a start that failed, with the reason, instead of a wait for a confirmation": 3, - "at the 30 second bound Codebook runs none of the chat’s commands: its unanswered request is left in the chat, and the page and the notice say that it may still be there and that the learner stops it in the Chat view": 17, + "an Update is refused with the sentence of a starting update while another window’s marker file has no content yet, and the file stays": 4, + "an Update that meets a marker nobody owns while another window holds the claim on it is refused with the sentence of a starting or ending update, and the marker and the claim stay": 9, + "an update of a Wiki published without recorded page hashes whose index.html was deleted starts": 22, + "an update of a Wiki that belongs to another checkout says the update could not start, without an \"Error:\" prefix, and the page reads the same reason as a failed start": 3, + "an update of a Wiki whose index.html was deleted is refused as a missing generated page that names index.html, with no file error and no chat request": 15, + "an update of a project without a Git repository ends as Updated and says that no revision is recorded and that added files are not checked": 68, + "an update that fails with a thrown object that only carries a message shows that message, not [object Object]": 98, + "an update whose end could not remove its marker because another window held the claim on it shows its end at once, refuses another window as beside a running update meanwhile, and removes the marker at its next attempt once the claim is free, after which that window starts": 1088, + "an update whose start checks throw is answered on the page as a start that failed, with the reason, instead of a wait for a confirmation": 6, + "at the 30 second bound Codebook runs none of the chat’s commands: its unanswered request is left in the chat, and the page and the notice say that it may still be there and that the learner stops it in the Chat view": 18, "cancelling a VS Code Wiki update with its status bar entry stops watching and not the chat, ends it as cancelled, removes the entry and leaves the published site byte-identical": 62, - "closing the window stops the Cursor agent and waits until its process has closed": 117, + "closing the window stops the Cursor agent and waits until its process has closed": 109, "closing the window while a Cursor update is still in its start checks starts no agent once the checks have ended": 7, "closing the window while a VS Code update is still in its start checks sends no chat request and starts no watch once the checks have ended": 10, - "closing the window while a VS Code update is watched stops the watch and shows no notification to a window that is gone": 11, - "closing the window while the VS Code chat is still opening ends the update as cancelled and starts no watch once the chat has opened": 13, - "dismissing the confirmation of the browser's update link starts no update: no chat request, no watch, and the update state stays idle": 3, - "every Wiki update shows the one place that can cancel it, also when nobody cancels it: a status bar entry for the VS Code watch, a progress notification for the Cursor run": 68, - "in Cursor a second Update LLM Wiki command while the agent works says that Codebook is already updating and starts no second agent": 7, - "in an editor without the New Chat command a queue command that would fail is not run either, no Cancel runs, and the sentence says that the request may still be in the chat and that the chat may be busy": 17, - "in an editor without the New Chat command an unanswered request in progress in the open chat is left there: no command of the chat runs at the bound, and the sentence says that the request may still be in the chat and that the chat may be busy": 17, - "in an editor without the New Chat command the confirmation says that the request goes into the open chat like a typed message: behind a request in progress, cancelling one that waits for a confirmation, replacing a draft": 11, - "in an editor without the New Chat command the request goes into the open chat; queued there behind a request of the learner it is left in the queue at the bound, neither “Remove All Queued” nor the chat’s Cancel runs, and the sentence says that the request may still be in the chat and that the chat may be busy": 18, - "pressing Open LLM Wiki on an update notice leaves no unhandled rejection when the Wiki cannot be opened": 68, - "rewriting the manifest file without a publish is not recorded as Updated": 145, - "the Cursor update request carries the same contract but asks for no report nobody would read": 44, - "the VS Code update request tells the chat that the publish must match the source within the 15 minute watch": 13, - "the bound a Cursor update is stopped at is the bound its page and its request name": 18, - "the confirmation of an update whose output lies outside the project says the chat will ask to approve each step there, and its watch is the same status bar entry, with no notification": 475, - "the confirmation of the browser’s update link says that the request goes into a new chat, that the open chat keeps its place in the chat list, and what becomes of a draft": 19, - "the reservation a stopped watch left on one Wiki output leaves the disk at its watch bound, also after an update of another output began in the meantime": 3631, - "the two listeners for signs of the update are registered while Codebook waits for the first answer and gone once the start has ended": 18, - "the update command and the browser link pressed while the first start is still in its start checks send one chat request and start one watch": 20, - "the update request for a project without a Git repository asks for no revision and tells the chat not to create a repository": 22, - "the watch of a VS Code update is the same status bar entry, and no notification, for the command, for the page’s button with a chat that asks for an approval, and in an editor without New Chat": 17, - "updating before any Wiki exists says to generate one first instead of showing a file error, and the page shows the same sentence as a refused start that kept no site": 7, - "when a VS Code watch is cancelled, its status bar entry is already gone at the moment the page and the editor show the end of the run": 9, - "while Codebook watches a VS Code update no notification of the watch stays on screen over the chat’s approval: the watch is an entry of the status bar, gone once the update has ended": 57, - "with an unchanged source a deleted generated page is still refused as missing, not answered as Already current": 7 + "closing the window while a VS Code update is watched stops the watch and shows no notification to a window that is gone": 7, + "closing the window while the VS Code chat is still opening ends the update as cancelled and starts no watch once the chat has opened": 6, + "dismissing the confirmation of the browser's update link starts no update: no chat request, no watch, and the update state stays idle": 2, + "every Wiki update shows the one place that can cancel it, also when nobody cancels it: a status bar entry for the VS Code watch, a progress notification for the Cursor run": 83, + "in Cursor a second Update LLM Wiki command while the agent works says that Codebook is already updating and starts no second agent": 5, + "in an editor without the New Chat command a queue command that would fail is not run either, no Cancel runs, and the sentence says that the request may still be in the chat and that the chat may be busy": 15, + "in an editor without the New Chat command an unanswered request in progress in the open chat is left there: no command of the chat runs at the bound, and the sentence says that the request may still be in the chat and that the chat may be busy": 14, + "in an editor without the New Chat command the confirmation says that the request goes into the open chat like a typed message: behind a request in progress, cancelling one that waits for a confirmation, replacing a draft": 6, + "in an editor without the New Chat command the request goes into the open chat; queued there behind a request of the learner it is left in the queue at the bound, neither “Remove All Queued” nor the chat’s Cancel runs, and the sentence says that the request may still be in the chat and that the chat may be busy": 16, + "pressing Open LLM Wiki on an update notice leaves no unhandled rejection when the Wiki cannot be opened": 57, + "rewriting the manifest file without a publish is not recorded as Updated": 149, + "the Cursor update request carries the same contract but asks for no report nobody would read": 13, + "the VS Code update request tells the chat that the publish must match the source within the 15 minute watch": 17, + "the bound a Cursor update is stopped at is the bound its page and its request name": 8, + "the confirmation of an update whose output lies outside the project says the chat will ask to approve each step there, and its watch is the same status bar entry, with no notification": 118, + "the confirmation of the browser’s update link says that the request goes into a new chat, that the open chat keeps its place in the chat list, and what becomes of a draft": 7, + "the reservation a stopped watch left on one Wiki output leaves the disk at its watch bound, also after an update of another output began in the meantime": 3616, + "the two listeners for signs of the update are registered while Codebook waits for the first answer and gone once the start has ended": 16, + "the update command and the browser link pressed while the first start is still in its start checks send one chat request and start one watch": 10, + "the update request for a project without a Git repository asks for no revision and tells the chat not to create a repository": 12, + "the watch of a VS Code update is the same status bar entry, and no notification, for the command, for the page’s button with a chat that asks for an approval, and in an editor without New Chat": 51, + "updating before any Wiki exists says to generate one first instead of showing a file error, and the page shows the same sentence as a refused start that kept no site": 3, + "when a VS Code watch is cancelled, its status bar entry is already gone at the moment the page and the editor show the end of the run": 11, + "while Codebook watches a VS Code update no notification of the watch stays on screen over the chat’s approval: the watch is an entry of the status bar, gone once the update has ended": 69, + "with an unchanged source a deleted generated page is still refused as missing, not answered as Already current": 21 } }, "wikiUpdateNotice.test.js": { "totalMs": 2 }, "wikiUpdatePage.test.js": { - "totalMs": 433 + "totalMs": 319 }, "wikiUpdatePublisherFlow.test.js": { - "totalMs": 12351, + "totalMs": 12298, "tests": { - "Update anyway on a refusal that named a candidate the stopped watch never saw, while this window’s own stopped chat is also in the way, is refused again naming this window’s chat, with no chat request": 197, - "Update anyway on each refusal of a start that another window’s stopped watch and this window’s own stopped chat with the candidate its watch saw are in the way of names the other window’s chat first and this window’s candidate second, then starts the update with one new chat request and keeps the candidate": 347, - "Update anyway on each refusal, first for a candidate the stopped watch never saw and then for this window’s own stopped chat, starts the update after those two refusals with one new chat request and keeps the candidate": 239, - "Update anyway pressed after a new candidate was written since the refusal is refused again, names the new candidate and sends no chat request": 171, - "Update anyway pressed late on the refusal that named this window’s stopped chat with the newest candidate its watch saw is refused again once an older candidate that watch saw was written again, names that candidate, and sends no chat request": 451, - "a candidate that exists before the click refuses the start as somebody else’s update and sends no chat request": 78, - "a candidate the agent staged in a folder of its own name ends the watched run as a conflict over the learner’s file and leaves the Wiki folder byte-identical": 190, - "a candidate the earlier chat keeps writing after this window stopped watching refuses the retry": 233, - "a generated page the learner edited by hand stops the update before any chat request and names the page": 170, - "a learner file created after the candidate was staged ends the watch as blocked and names it": 241, - "a manifest changed after its publish stops the update before any chat request instead of letting the watch time out": 72, - "a publish into a configured Wiki folder is seen there, ends the run as succeeded and keeps the learner’s file": 262, - "a publish the real publisher refuses over the learner’s file ends the watched run as a conflict, and the previous site, its manifest, its receipt and the learner’s files are byte-identical": 255, - "a real publish that keeps the sources and the revision and only excludes a new file is seen and ends the run as succeeded": 249, - "a retry after this window’s own run ended with the chat’s reply starts again although that run’s abandoned candidate is still there, and does not blame it": 2257, - "a running Cursor update parses the candidates once while nothing is written, not at every look": 486, - "a running Cursor update says the agent is preparing a new site once the real publisher staged a candidate": 2105, - "a staged-candidate look that returns after its run ended does not show the next run as preparing a new site": 244, - "a watched VS Code run parses the candidates once while nothing is written, not at every look": 480, - "a watched VS Code run says the chat is preparing a new site once the real publisher staged a candidate": 152, - "a watched run in which nothing is published ends as timed out when its fifteen minutes have passed, warns in the editor and leaves the Wiki folder byte-identical": 189, - "after a VS Code watch ended on a learner’s file while the chat still works, the learner moves the file and presses: no second request is sent, the press is answered with the wait for that chat and Update anyway, and the chat can still publish its site": 242, - "after a VS Code watch ended on a learner’s file, Update anyway on the one refusal of the next press starts the update again, and the new run does not take the earlier chat’s candidate for its own": 294, - "after a start refused for a candidate an earlier chat left, choosing Update anyway starts the update without deleting the folder": 145, - "after a window reload the candidate this window’s own ended update left behind does not refuse the next start": 145, - "an earlier publish that did not finish stops the update before any chat request and names its journal": 2084, - "cancelling a watched run while the agent has a candidate staged leaves the whole Wiki folder byte-identical": 188, - "the editor shows an ended update’s notification in the same turn the page’s status changes": 184 + "Update anyway on a refusal that named a candidate the stopped watch never saw, while this window’s own stopped chat is also in the way, is refused again naming this window’s chat, with no chat request": 172, + "Update anyway on each refusal of a start that another window’s stopped watch and this window’s own stopped chat with the candidate its watch saw are in the way of names the other window’s chat first and this window’s candidate second, then starts the update with one new chat request and keeps the candidate": 297, + "Update anyway on each refusal, first for a candidate the stopped watch never saw and then for this window’s own stopped chat, starts the update after those two refusals with one new chat request and keeps the candidate": 243, + "Update anyway pressed after a new candidate was written since the refusal is refused again, names the new candidate and sends no chat request": 174, + "Update anyway pressed late on the refusal that named this window’s stopped chat with the newest candidate its watch saw is refused again once an older candidate that watch saw was written again, names that candidate, and sends no chat request": 417, + "a candidate that exists before the click refuses the start as somebody else’s update and sends no chat request": 104, + "a candidate the agent staged in a folder of its own name ends the watched run as a conflict over the learner’s file and leaves the Wiki folder byte-identical": 194, + "a candidate the earlier chat keeps writing after this window stopped watching refuses the retry": 249, + "a generated page the learner edited by hand stops the update before any chat request and names the page": 161, + "a learner file created after the candidate was staged ends the watch as blocked and names it": 255, + "a manifest changed after its publish stops the update before any chat request instead of letting the watch time out": 88, + "a publish into a configured Wiki folder is seen there, ends the run as succeeded and keeps the learner’s file": 225, + "a publish the real publisher refuses over the learner’s file ends the watched run as a conflict, and the previous site, its manifest, its receipt and the learner’s files are byte-identical": 236, + "a real publish that keeps the sources and the revision and only excludes a new file is seen and ends the run as succeeded": 196, + "a retry after this window’s own run ended with the chat’s reply starts again although that run’s abandoned candidate is still there, and does not blame it": 2262, + "a running Cursor update parses the candidates once while nothing is written, not at every look": 476, + "a running Cursor update says the agent is preparing a new site once the real publisher staged a candidate": 2091, + "a staged-candidate look that returns after its run ended does not show the next run as preparing a new site": 220, + "a watched VS Code run parses the candidates once while nothing is written, not at every look": 474, + "a watched VS Code run says the chat is preparing a new site once the real publisher staged a candidate": 157, + "a watched run in which nothing is published ends as timed out when its fifteen minutes have passed, warns in the editor and leaves the Wiki folder byte-identical": 213, + "after a VS Code watch ended on a learner’s file while the chat still works, the learner moves the file and presses: no second request is sent, the press is answered with the wait for that chat and Update anyway, and the chat can still publish its site": 263, + "after a VS Code watch ended on a learner’s file, Update anyway on the one refusal of the next press starts the update again, and the new run does not take the earlier chat’s candidate for its own": 300, + "after a start refused for a candidate an earlier chat left, choosing Update anyway starts the update without deleting the folder": 108, + "after a window reload the candidate this window’s own ended update left behind does not refuse the next start": 166, + "an earlier publish that did not finish stops the update before any chat request and names its journal": 2218, + "cancelling a watched run while the agent has a candidate staged leaves the whole Wiki folder byte-identical": 157, + "the editor shows an ended update’s notification in the same turn the page’s status changes": 181 } }, "wikiUpdateRun.test.js": { @@ -3779,130 +3820,68 @@ "totalMs": 1 }, "withServedAddresses.test.js": { - "totalMs": 8024, - "tests": { - "HTML form, button, heading, table and formatting rules keep later foreign links visible": 1, - "a

or
leaves svg and a heading end closes an open heading of any other level, so what follows is judged where a browser reads it": 0, - "a in a template closes the open caption, table section or row though no table is open, so a link in a later svg style loses its link": 0, - "a block or list item start inside an open select leaves the paragraph or list item opened before the select open, so a link in the svg after a formatting end loses its link": 0, - "a feDropShadow start or end in svg content is written in svg case as Chrome writes it, so the link after a plaintext or in a CDATA start is judged where a browser reads it": 0, - "a formatting end removes the entry of a formatting element closed earlier, also after a caption or a cell closed, and a form end forgets a form left in a table, so a link in a later svg style loses its link": 0, - "a frame’s srcdoc loses its effect, whatever it holds and in any case of its name": 0, - "a heading-family end from a foreign child restores HTML style text": 0, - "a hidden input closes an open select in a table caption but not in the table itself, as Chromium reads them": 0, - "a hidden input in a table body or a row, or written HIDDEN, leaves an open select open, so Chrome reads the style after the select as text, and its link loses its link where the older select rules follow it": 0, - "a link after a noscript is judged as a browser with scripting reads it, and a link inside the noscript, which a browser without scripting follows, loses its link too": 0, - "a link inside svg’s style or script, inside MathML’s text after it, and after a script whose text holds