Skip to content

Cycle 0051: a test replay opens in the region-2 composition, with the Learning summary in the chat's place, one transport and 5A #122

Closed

Description

@ryota-murakami

Outcome

A saved test replay opens in the learning-replay composition of the v9 PNG's region 2, in VS Code and in Cursor, as a browser replay already does: the Learning summary takes the chat's place, one transport serves both replay families, and the summary collapses behind a visible Learning summary button and reopens without losing the moment (approved choice 5A). This is a feature cycle (D8 of #107; #118 closed with nothing carried).

Why now. PRODUCT_GOAL.md's replay contract says "the chat area becomes a learning summary" and that one playhead serves every surface (Contract: learning replay; Design target, region 2). A test replay breaks both today, and the library-test form is a required row of four of the nine final projects (P02 to P05) and the form the development target is studied with. The browser replay already has the composition, so this increment reuses it instead of building a second one. The replay contract names test evidence itself (PRODUCT_GOAL.md:151: "Server/test/extension evidence never invents a Web UI"), so region 2 governs a test replay too.

Verified current state (main at 8dd675b9, v0.2.38.0; read 2026-10-24):

Surface (region 2) Browser replay Test replay Gap
Chat area Learning summary view codebook.learningSummary gets every Study message while summaryComposition is true (studyWorkspace.ts:13460-13461) summaryComposition = this.recordingActive (studyWorkspace.ts:8154) is false, so the view shows only "Open saved learning from Codebook to view its summary." (:19608-19612); its messages are dropped (:22718-22719, :22749-22750) Summary, sequence and the moment's explanation sit in the Study pane's Test replay section (ui/studyHtml.ts:214, renderTestReplay :2363-2374) with the chat still at the right
Study pane closed in the summary composition (studyWorkspace.ts:8183-8188) open; it hosts the Test replay section the composition differs by family
Transport one #recording-transport (ui/studyHtml.ts:217): ?, Replay from start, Previous and Next recorded stop, Play or Pause, slider with coverage, readout; in the bottom panel while it is visible, else the summary's fixed footer (showsTransport, :3205-3207) its own sticky #node-history-transport in the Study pane section (:2536-2730): Previous and Next stop, Play, slider, readout, Previous and Next event two transports
Bottom panel titled "Learning replay", shows the transport only (studyWorkspace.ts:13463-13465, ui/constants.ts:219-229) titled "Observed moments", receives every message (studyWorkspace.ts:13466) and draws a second working copy of the Study pane, Test replay section included; nothing asserts it defect found by this audit (task 7)
5A collapse and reopen absent: no visible Learning summary button; native hide keeps the document (retainContextWhenHidden, :19615) and the bottom-panel transport stays usable (studyWorkspace.test.ts:3739) absent both families
Shared renderers sequenceView (ui/studyHtml.ts:2216-2347), renderTimelineCoverage (:364-454), projectHistoricalTimeline the same reused, no new renderer

Inventory (estimated by a read-only research pass; task 1 re-measures it, and every line number here is at 8dd675b9): recordingActive has 83 reads (82 in studyWorkspace.ts, 1 in runtimeSupport/utils/isStopKeyboardHandOverDue.ts:23); 8 need a test-replay counterpart, 7 probably, 67 keep the families apart or are browser-video specific. message.recording has 77 reads (75 in ui/studyHtml.ts, 2 in utils/capturedAppHtml.ts); 44 lines of ui/studyHtml.ts need a counterpart. Task 1 freezes the per-line table.

Proposed change. A selected test replay enters the same summary composition as a browser replay.

  1. Composition (DS-A). summaryComposition is true while a browser recording is active or a test replay is selected (selectedNodeHistory). Its open closes the Study pane exactly as the browser replay's does, keeps the Application pane (Recorded test output · <t> s) above the recorded-source slot, the replay debugger in Run and Debug, and shows the Learning summary view: in VS Code moved once per profile into the chat's container (moveSummaryBesideChatOnce, studyWorkspace.ts:19221-19242), in Cursor in its own container with the existing Move View offer (F209, D31 of Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118). A test replay's open from Open replay or Saved studies (the learner's entries, openNodeHistoryFromHost, studyWorkspace.ts:11656) takes this path and brings the composition to the front. An agent cannot open a test replay: MCP 1.8 refuses codebook_playback for a test replay's study id with PLAYBACK_PROFILE_UNSUPPORTED before anything is loaded (service.ts:897-902; the tool's description, protocol.ts:362; its recovery, errors.ts:52, tells the agent to ask the learner to open it). This cycle keeps that contract, and a refused call changes no selection, view or focus. The browser replay's agent rule (keepsViewsInFront, studyWorkspace.ts:19115-19160) is unchanged. Return to Live leaves it as a browser replay's Return to Live does: the Live composition with the Study pane closed (studyWorkspace.ts:8183-8188, :9136-9156) and the same keyboard focus. Choosing another saved study retires the test replay into that study's own composition; deleting the selected saved study and a failed reopen retire it as well, and every retirement stops a running playback timer.

  2. Summary content (DS-B). For a test replay the Learning summary view shows, top to bottom in the order of the PNG's region 2: (i) the test replay's title, its status line and, for a partial or interrupted capture, its capture reason, then the question as a muted line; (ii) the processing summary; (iii) the sequence diagram (sequenceView) with the selected step marked in the drawing itself, and Step details (the numbered steps, collapsed); (iv) the moment block: a heading Step <n> · <step label> when the selected event has a selected step, then the position line, the saved explanation and the not-recorded, unverified and pointer lines; (v) the values hint with Show Variables and Inspect in native debugger when wanted; (vi) "I understand this test history"; (vii) the collapsed event list with its pages. These are the Test replay section's own elements and strings, moved, not rewritten; two are new, the moment block's step heading (a heading element with tabindex="-1", so it can take a fallback focus) and the drawing's mark.

    The drawing's mark. The selected step's arrow label in the SVG carries aria-current="step" and a style that is not color alone (--vscode-textLink-foreground, weight 600 and an underline), as the PNG marks its current arrow. Each arrow label in the SVG carries its step's id (data-step), and on every Study message the mark moves by setting aria-current and a class (not an inline style) on those existing nodes, as markTestReplaySteps does for the numbered steps (ui/studyHtml.ts:2781-2799); the drawing is built only when the material changes (ui/studyHtml.ts:2762), so a move keeps the diagram's scroll position and the focus. A pending moment or an event with no step removes the mark. The browser replay's renderer does not call this marker in this cycle, so its diagram is unchanged (later candidate C8). An event with no selected step (an output or the result that no step references) shows no step heading and marks no step: never the step of an earlier moment. The numbered steps under Step details keep their aria-current and Same recorded moment marks (DS21).

    First viewport. At task 2's measured Learning summary size in each host, the moment block's heading (without one, its position line) starts inside the view without scrolling, also with a question of three lines, a processing summary and a capture reason of the schema's full length (MAX_EXPLANATION_CHARS, 8,192 characters, constants.ts:90) and a diagram of six participants. For this, the question, the processing summary and the capture reason each show at most three lines with a Show more button (aria-expanded) that shows the whole text in place. The diagram's own scroll area is capped for this, by a constant in ui/constants.ts that applies to the test replay's diagram container only; the whole drawing stays reachable by that area's scroll, horizontal scroll included (F206's columns are kept, no reflow).

  3. One transport (DS-C). #recording-transport serves both families. For a test replay: Replay from start goes to the first event; Previous and Next recorded stop go to the previous and next stop (DS12 of Cycle 0049: a Vitest test run the editor chat explained is saved and replayed as a learning replay in both editors #107: stops are primary); Play or Pause runs the test replay's playback; the slider spans the recorded test time with the existing coverage marks; the readout reads <t> s / <total> s; two buttons shown only for a test replay, Previous event and Next event, step through outputs and the result. The transport's seven move controls are Replay from start, Previous recorded stop, Play or Pause, Next recorded stop, the slider, Previous event and Next event (? and the 5A button are not move controls). For a test replay each sends the message the Test replay section sends today, with the same fields (a revision where that message carries one; node-history-playback carries none, and the page sends only times inside the history's range, because the host refuses a seek outside it, utils/nodeHistoryPlaybackController.ts:129-140):

    Control or key (test replay) Message
    Replay from start node-history-event with the first event's sequence (a seek to its time would select the last of several events recorded at that time, utils/nodeHistoryPlaybackController.ts:150; the store accepts equal times, nodeTestHistoryStore.ts:1645)
    Previous / Next recorded stop node-history-step with unit: 'stop', direction: 'previous' / 'next'
    Previous / Next event node-history-step with unit: 'event'
    Play / Pause node-history-playback play / pause
    Slider change node-history-playback seek to the slider's value
    ArrowLeft, ArrowDown / ArrowRight, ArrowUp on the focused slider node-history-step with unit: 'event', previous / next (a test replay's moments are discrete events, and a time step would land on the same event again, because its seek selects the event at or before the time, utils/nodeHistoryPlaybackController.ts:128)
    Page Down / Page Up node-history-step with unit: 'stop', previous / next (the browser's directions: Page Up is forward)
    Home / End node-history-event with the first / last event's sequence

    The host projects the history's firstSequence and lastSequence from all its entries beside nodeHistoryPlayback, because the page receives only the event list's current page of 20 entries (NODE_HISTORY_READER_PAGE_SIZE, studyWorkspace.ts:406, :13214-13217); Replay from start, Home and End and their enabled states use them, compared by sequence, never by time. The slider runs from the first event's time to the last event's time, so no seek lies before the first event. The shared slider keeps the browser's step="1" in milliseconds; a test replay's times are whole milliseconds. Its accessible value keeps each family's present wording (a test replay: <t> s of recorded test time). Each control's enabled state for a test replay is the one its counterpart has in today's Test replay transport, so a history with no event or one event has no usable move control and Previous or Next stop is disabled where no stop lies that way; two rules are new for a test replay: Replay from start (which its transport lacks today) is enabled unless the first event is selected, and the existing disabling of Play at a history's last event (ui/studyHtml.ts:1820) stays. A third is new too: a history of two or more events whose times are all equal keeps the slider enabled and focusable for its keys, where today's rule disables it for an empty time range (ui/studyHtml.ts:2659-2660); with no time range a drag sends no seek. A history sealed with no event (F85 of Cycle 0049: a Vitest test run the editor chat explained is saved and replayed as a learning replay in both editors #107) opens with every move control disabled and the section's existing empty lines. A seek is sent on the slider's change event, as for both families today (ui/studyHtml.ts:805); a seek between two events selects the event at or before that time, as today's test replay seek does; the coverage marks already draw a test replay's range (renderTimelineCoverage, ui/studyHtml.ts:2568). The slider's keys run through two handlers selected by the family: the browser replay's present handler, unchanged, and a test replay's handler for the table above; each handles its keys itself and calls preventDefault, as ui/studyHtml.ts:852 does, so the native step does not apply. The shortcut list keeps its six entries for the recording timeline (ui/constants.ts:55-90) and gains six for the test replay timeline, with that context named (Previous event, Next event, Previous stop, Next stop, First event, Last event), so the list, the tooltips and the behavior agree (PRODUCT_GOAL.md:255). Playback's timer is the host's (utils/nodeHistoryPlaybackController.ts:116 for a test replay, playbackController.ts for a browser replay), so a hidden view does not slow it. #node-history-transport is removed. scripts/fixtures/history-transport-golden.txt pins the browser transport's timeline track (the slider and its coverage marks, compared at study-bootstrap-qa.mjs:9989), not its buttons; it stays byte-equal and is not re-recorded.

    Order and groups. Left to right, the playback row is ?, Replay from start, Previous recorded stop, Play or Pause, Next recorded stop, the slider with its coverage, the readout, and, for a test replay only, the event group: Previous event and Next event as text buttons with their present labels, so they never read as the stop icons ◀| and |▶. The status row below holds the status line and, at its right end, the Learning summary button (5A), a text button apart from the move controls and outside the status line's role="status" element, so a status update never announces it again. A row too narrow for its controls wraps by group, never inside one: the event group takes its own line before the slider shrinks below its present minimum width. For a browser replay the visible controls, with their ids, order and labels, are today's plus the Learning summary button (a Reader DOM case pins the list).

    Keys. The test replay's slider names its keys in its tooltip and aria-keyshortcuts, in the browser slider's tooltip format (for example Previous event — ← / ↓ (Focused test replay timeline)), so the tooltip, the shortcut list and the keys agree (D035). One keydown listener reads the family shown when the key is pressed and runs that family's handler, so a family switch with the slider focused uses no stale handler. Arrow keys move by event while a drag moves by time: an intended asymmetry (a test replay's moments are discrete events), not a defect. A key move updates the slider's aria-valuetext once, and the status line speaks only refusals, so a move is not read twice.

  4. Bottom panel (DS-D). During a test replay the bottom panel is titled "Learning replay" and shows the transport only, as during a browser replay; its second copy of the Study pane goes (task 7).

  5. 5A (DS-E), both families. The transport always shows a Learning summary button (tooltip and accessible name "Show learning summary"), so the summary can collapse behind it however the host hid it (the learner hid or collapsed the view, or closed its container), with no visibility detection; pressing it runs the command, which shows a hidden view or brings the keyboard to a shown one. Hiding and reopening keep the selected moment, the replay debugger's session and frame and the summary's scroll position. Hiding neither pauses nor resumes playback: a paused replay shows the same moment after the reopen, a playing replay goes on playing and the reopened summary shows the moment then current. After the button is pressed the Learning summary view takes the keyboard focus, on the control it last held when it held one (its existing focus memory, ui/studyHtml.ts:1915-1929). Seeks and moves made while the summary is hidden are applied by the host as always; the hidden view, whose document is retained, receives the latest Study message and shows the moment then current when it reopens. A view the host has not resolved yet gets the latest Study message when it resolves (its ready message, studyWorkspace.ts:22753-22757), and the button's focus goes through the view's existing focus receipt (codebook-focus-receipt) once the view is visible, as for a browser replay. The 5A button (labelled Learning summary) stands at the right end of the transport's status row, apart from the move controls (Proposed change 3); it is an action, not a toggle (pressing it never hides the summary, O2), so it has no pressed state; it runs the command Codebook: Show Learning Summary, which this plan calls "the command" to keep the two apart. When the control the summary last held is no longer shown or usable, the focus goes, in this order, to the summary of the nearest shown disclosure around it, the moment block's step heading, or the summary's title heading (both headings tabindex="-1"), focused with preventScroll so the reading position stays. This replaces the view's present last resort, the removed #node-history-transport (nodeTransportFocus, ui/constants.ts:193-200, read by stayingControl, ui/studyHtml.ts:1897); the bottom panel's transport keeps replayTransportFocus, with the event buttons added for a test replay. The collapse itself is the host's own (hiding the view or its container); Codebook adds no collapse control that could close the chat. When the learner has also hidden the bottom panel, no transport is visible and no button is promised (their layout choice is kept, PRODUCT_GOAL.md 5A); the Command Palette's Codebook: Show Learning Summary and the Learning summary's own container still reopen it.

  6. Routing (DS-F). Node-history messages from the Learning summary view and the bottom panel are accepted as from the Study pane; Show Learning Summary works for a test replay. During a browser replay they are refused as today. Moves from the three views share the host's one selection, where the latest request wins, as today (selectedNodeHistoryRequest, studyWorkspace.ts:24781-24797): a held key, or a click in one view while another view's move is pending, never queues stale moves, and a superseded move reports no refusal. A message that arrives after the test replay was retired is refused with today's sentence (Select the matching saved test replay before navigating its timeline., studyWorkspace.ts:23005-23009), and a sequence that is not in the history is refused before any move.

  7. States (DS-G). Each state keeps today's test replay wording; the table says where it shows in the composition.

    State Learning summary Transport
    Opening, before the view's first Study message the view's present placeholder, replaced by the content at the first message move controls disabled until its first message
    Moment pending (D29, F203) the position line names the target; the step heading, the explanation, the steps and the not-recorded lines of the moment left are withheld, as today; no step is marked the slider and the readout show the target; each control keeps today's enabled state
    Moment committed the whole moment block; the drawing marks its step enabled as in Proposed change 3
    Move refused or failed (no such stop or event, a replay debugger session that does not start) the last committed moment stays and is never shown as the new one the host's sentence in the status line (#recording-status, role="status"), so it is read with the summary hidden too. A replay debugger that does not start on a move gets the recovery clause the open path gives today (studyWorkspace.ts:24781-24797: Select this stop or use Inspect in native debugger to restart it.), and the sentence says that the last moment is still shown; the start is bounded (REPLAY_DEBUG_CAPTURE_TIMEOUT_MS, constants.ts:1429), so no move waits without end
    History sealed with no event (F85) the section's present empty lines every move control disabled
    One event that event's moment no usable move control, as today
    Partial or interrupted capture the status line and the capture reason under the title the coverage marks show the gaps
    An output, the result, an unverified stop (4A) the not-recorded or unverified line; the debugger's Not recorded at this moment thread unchanged
    Application closed the pointer line and Show recorded output unchanged
    No learning material the present no-material line in place of the summary and the diagram unchanged
    Open failed (a load) not entered; the existing notification, which ends open it again from Saved studies. and offers Show details, and its Output › Codebook entry (tellTestReplayOpenFailure, studyWorkspace.ts:11745-11761; utils/describeNodeLearningSave.ts:184-189) not shown for that replay

    For a test replay the transport hides the browser-only recovery: Reload saved recording, Recording error details, the playback pending and reason lines and the covered-application remedy.

The MCP API stays 1.8 and no stored format changes. presentation reports the test replay's panes as it reports the browser replay's (AC1).

Acceptance criteria (each test states protects=…; fails_when=…; no_claim=…):

  1. Opening a saved test replay by Open replay and by Saved studies closes the Study pane and shows the Application pane above the recorded-source slot, the replay debugger, and the Learning summary view in front; an agent's codebook_playback open of a test replay's study id is still refused with PLAYBACK_PROFILE_UNSUPPORTED and its recovery sentence, and changes no selection, view or focus (DS-A; MCP 1.8 unchanged); no Study pane test replay section exists anywhere (host tests, one per entry, in VS Code's harness and in Cursor's: VS Code moves the view into the chat's container once per profile, Cursor keeps its own container and makes the Move View offer), and the presentation resource reports for a test replay the pane set it reports for a browser replay (host test).
  2. The Learning summary view of a test replay renders the elements of Proposed change 2 in that order, for a stop, an output and the result; with Step details collapsed, the drawing marks the selected step (aria-current="step" and the non-color style) and the moment block's heading names it; an event with no selected step marks none; the browser replay's diagram is unchanged; at task 2's measured summary size the moment block starts inside the view with a three-line question, a full-length processing summary and capture reason, and a six-participant diagram, and Show more expands each clamped text in place and back; a step label and an output line holding <, " and </text> render as text; on moves the mark moves without a rebuild of the drawing, keeping its scroll position (Reader DOM).
  3. A test replay's transport is the element #recording-transport; each of its seven move controls sends the message of Proposed change 3's table; the controls stand in Proposed change 3's order and groups for each family; the browser replay's timeline track equals history-transport-golden.txt byte for byte, its visible controls with their ids, order and labels are today's plus the Learning summary button (a closed list; any other difference fails), and every existing browser replay transport test passes unchanged (Reader DOM and the golden).
  4. During a test replay the bottom panel is titled "Learning replay" and shows only the transport: no Saved studies, no Observed moments, no event list, with the Learning summary shown and with it hidden (host and Reader DOM); outside a replay the bottom panel keeps today's title and content (host).
  5. The transport shows the Learning summary button with the view hidden and with it shown; pressing it shows the hidden view, or brings the keyboard to the shown one. For a paused test replay and a paused browser replay, the selected moment, the playhead, the replay debugger's session and frame and the summary's scroll position are equal before the hide and after the reopen, and the focused element after the reopen is the summary control focused before the hide (host tests for the moment, playhead and debugger, with the workspace harness's historical debugger stand-in; in the real hosts the scroll position and the focus are proven by N51's part (c) only, so these tests' no_claim names the harness stand-ins; Reader DOM for the scroll position and the focus, by the view's hide and focus events). For a playing replay, playback goes on across the hide and the reopen (host test). With no control held before (the first open, an empty history), the reopen focuses the summary's title heading; when the held control is gone at the reopen (Inspect hidden after playback moved), it focuses the moment block's step heading; both keep the scroll position (Reader DOM).
  6. Node-history messages from the Learning summary view and the bottom panel move the test replay; during a browser replay they are refused with the existing sentence (host).
  7. Every existing browser replay, live run, save, Wiki and shortcut test passes unchanged, except the Study-pane pins marked "moves with D8" (F123), each changed or replaced with its reason in the pull request.
  8. N51 passes in both hosts (task 10), in the Space local:codebook-qa at the D034 layout (PRODUCT_GOAL.md, Product constraints: an ordinary desktop display, the editor window expanded, default zoom): VS Code with Copilot Chat GPT-6 Luna, Cursor with Agent Grok 4.6 High; a natural /codebook question about a code path of nextjs-dashboard that Cycle 0049: a Vitest test run the editor chat explained is saved and replayed as a learning replay in both editors #107 and Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118 did not ask, run through its test, saved and reopened from Saved studies, recorded with OBS Window Capture and every native frame of each transition inspected. It passes when, in each host: (a) Run and Debug, the Application pane above the recorded-source slot, the Learning summary (in VS Code in the chat's container; in Cursor in its own container, D31 of Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118) and the transport at the bottom all show the opened test replay; (b) Replay from start, Previous and Next stop, Previous and Next event, a seek and Play move every surface to one moment with no frame pairing two moments; (c) 5A hide and reopen keep the moment, the debugger frame and the reading position; (d) a browser replay opened afterwards shows its own composition as in task 2's frames; (e) Return to Live from the test replay gives the Live composition and the keyboard focus a browser replay's Return to Live gives (the Study pane stays closed), every native frame of that transition inspected; (f) in one dark and one light theme per host, the drawing's step mark, the event buttons and the focus ring are visible and distinguishable. A screenshot of (a) is compared with the PNG's region 2 and every difference is listed; differences named in Out of scope, the generated learning content and Cursor's placement are allowed, and any other difference is a defect fixed in this cycle. Also allowed by task 2 (O6): the host's side-bar width and panel height, the learner's unrelated editor groups, the summary's two shared header controls (Keyboard shortcuts, the collapsed Study view and pane controls), and VS Code's Chat-collapse click and Cursor's Move View step as the hosts' own steps. Beside the pass criteria each host records one learning task, not gating: from the saved summary and its moments, the driver finds the condition that decided the test's result and the recorded value behind it, and notes the answer with its evidence, the moves it took, any confusion and the time it took from the open in Saved studies to that answer (this plan's time-to-first-result measure; target under 2 minutes, not gating).
  9. On the pull request's final tree, each of these 15 checks exits 0 (the exact-tree gate; Cycle 0050's records called it 16 checks, a miscount of the same 15): from extension/, pnpm format:check, pnpm typecheck, pnpm lint, pnpm health:static, pnpm dupes, pnpm dead-code and pnpm test; from the repository root, after that build, node extension/scripts/<check>-qa.mjs verify <folder> for each of study-bootstrap, wiki-reader-dom, study-reading-pose, understanding-focus and repository-return, each given a new empty folder of its own outside the repository (the check writes its result.json and video there; setup in AGENTS.md, Reader DOM); from extension/, pnpm test:package and then pnpm health; from the repository root, node --test .codex/restore-product-context.test.mjs. Required CI passes on the exact head.
  10. Each user-visible behavior a CHANGELOG entry names has its sentence in extension/README.md.
  11. C2: on the focused shared slider during a test replay, each key of Proposed change 3's table moves the test replay to the event or stop it names, which each case asserts as the moment shown after the move (in a sparse history with events at 0 s and 5 s, ArrowRight from the first reaches the second; in a history whose first two events share 0 ms, Replay from start and Home show sequence 1, not sequence 2), and no key moves past the first or last event; modifier keys, IME composition and a defaultPrevented event move nothing; the browser replay's keys behave as before (three Reader DOM regression cases: arrows, pages, Home and End); the shortcut list shows the test replay timeline's six entries with their context. Each case is red first.
  12. The pull request meets AC1 to AC11 and AC13 to AC15 on its final tree; the moved section carries no transport of its own there.
  13. A browser recording and a selected test replay never coexist: a recording's load retires a selected test replay (studyWorkspace.ts:12039-12043) and a test replay's open during a browser replay is refused with its existing offer to close it (studyWorkspace.ts:11657-11667); a test replay opened after leaving a browser replay redraws the transport for its family (event steps shown, its slider's accessible wording). After a window reload no test replay reopens by itself, because its selection lives in memory and the persisted selection is the browser profile's only (studyWorkspace.ts:11805, configuredStudySchemas.ts:203-208); reopening it from Saved studies enters the composition at its saved reader position (saveReaderPosition, studyWorkspace.ts:24660-24669), VS Code's once-per-profile move is not repeated, and a summary the host keeps hidden stays hidden with the 5A button shown (host tests). A test replay that reopens by itself after a reload is a later candidate (C10).
  14. States (DS-G): a pending moment withholds the step heading, the explanation and the drawing's mark; a refused move leaves the last committed moment and shows the host's sentence in the transport's status line, read with the summary hidden; with the summary hidden, a replay debugger that refuses to start on a move shows the recovery clause, and following it (selecting that stop again) reaches the same target; a test replay's transport shows none of the browser-only recovery controls; with the variable sets of the four supported themes (dark, light, high contrast dark, high contrast light) the step mark and the event buttons' text keep a contrast of at least 4.5:1 and the mark keeps its non-color cue, measured against each set's --vscode-editor-background (no_claim: the four sets are fixtures, not installed themes; N51 (f) covers two real themes per host) (Reader DOM; the refusal also by a host test).
  15. Leaving and late input: Return to Live gives the Live composition with the Study pane closed; choosing another saved study, deleting the selected saved study and a failed reopen retire the test replay, and a test replay playing with its summary hidden stops its playback timer when retired; a node-history message that arrives after the retirement, or names a sequence that is not in the history, is refused and moves nothing; held-key repeat and moves from two views at once end at the latest request, with no stale refusal shown; Replay from start, Home and End reach the history's first and last events from any page of the event list (host tests).

Testing plan.

Layer What Count
Host (studyWorkspaceTestReplay*.test.ts) composition per entry, retirement, Return to Live, routing from each view, Show Learning Summary, 5A state preservation (paused and playing), bottom panel title, each entry in VS Code's and Cursor's harness. Count: entries 4 (two learner entries in two hosts), the agent's refused open 1, presentation 1, routing 2 (summary view, bottom panel), refusal during a browser replay 1, Show Learning Summary 1, 5A paused 2 (both families) and playing 1, precedence and reload 2 (AC13), Return to Live giving the Live composition 1, a refused move's sentence and recovery reaching the transport 1, a failed open's notification and its Saved studies sentence 1, Replay from start and Home reaching the first of two events recorded at the same time 1, retirement by another saved study 1, by deleting the selected study 1, a hidden playing replay's timer stopped on retirement 1, a late message after retirement 1, a sequence not in the history 1, latest-wins across held keys and two views 1, a summary view not resolved before the first Show Learning Summary 1, the bottom panel outside a replay 1, the first and last events from another page of a 41-event history 1 +28
Reader DOM (study-bootstrap-qa.mjs) summary content per moment kind, the shared transport's seven move controls, bottom panel content, the Learning summary button, focus and scroll on reopen, the test replay's slider keys (C2) and the browser key regression; each red first. Count: summary 3 (stop, output, result), move controls 7, bottom panel 2 (summary shown and hidden), the button 2 (summary hidden, summary shown), focus and scroll 2 (one per family), test replay keys 8 (each asserting the moment reached), ignored modifiers and IME 1, browser key regression 3 (arrows, pages, Home and End), the shortcut list's test replay entries 1, the drawing's step mark with Step details collapsed 1, no mark for an event without a step 1, the first viewport 1, the transport's order per family 2, the browser transport's control list 1, a pending moment 1, a refused move in the status line 1, the browser-only recovery hidden 1, the focus fallback 2, the four themes' variable sets 1, Replay from start and Home sending the first event's sequence 1, the Learning summary button outside the live region 1, markup in a step label and an output line rendered as text 1, Show more on the clamped texts 1, keys in a history whose events share one time 1, Home and End from another page of the event list 1, the step mark moving without a rebuild (scroll kept) 1, one aria-valuetext update per key move 1 +49, and the "moves with D8" pins changed
Golden the transport golden (the timeline track) and the sequence golden unchanged 0 new files
Native (N51) both hosts, frames inspected 2 rounds

The Reader DOM job has a 10-minute limit (.github/workflows/reader-dom.yml:25); the new cases are timed in it before the pull request opens, and a new check file takes the overflow if needed (it joins that workflow and workflowPins.test.mjs).

Terms. 5A: approved choice 5A, the summary's collapse and reopen (PRODUCT_GOAL.md:143). D034: the layout rule (PRODUCT_GOAL.md:109). D8, DS12, E8, E9: decisions and later candidates of Cycle 0049's plan (#107). F85, F123, F209: Cycle 0049 tasks, closed in Cycle 0050 (#118); D31: #118's decision on Cursor's summary container. N51: this cycle's native round (task 10). The transport golden extension/scripts/fixtures/history-transport-golden.txt holds the browser transport's timeline track only; study-bootstrap-qa.mjs:9989 compares the markup with it, and this cycle leaves it unchanged. C8: the browser replay's diagram mark, a later candidate.

Rules for the implementing agent.

  1. Acceptance criteria are each test's protects / fails_when / no_claim. Never "make the tests pass".
  2. Real code and real tests land together.
  3. Any change to a test, validator, CI step, timeout, tolerance, threshold, snapshot or suppression is reported on its own line with its reason.
  4. A reported command names the command and its observed result.
  5. A report is a claim until the driving agent re-executes it.

Delivery (D-PR, recommended). One pull request, built in staged commits (composition and routing; summary content; one transport and the bottom panel; 5A; C2), through the local reviews, /ship, required CI, the exact-tree gate and N51 before its merge, so no half-built composition reaches main. Task 2's spike runs before the first product commit.

Rollback. Revert the pull request. No stored format or MCP contract changes.

Effort [estimated]. Inventory and spike 4 h (the spike checks placement and readability); composition and routing 6 h; summary content 4 h; one transport 6 h; C2 keys 2 h; bottom panel 2 h; 5A 5 h; summary order, step mark and states 4 h; tests and Reader DOM 20 h; the host's first and last sequence, the zero-range slider, the mark by attribute, the clamped texts and the exits 5 h; documents 1 h; N51 4 h per host. Total: human team about 2 weeks; CC about 3 to 5 working days plus the native rounds; nothing is cut to fit: C2 is required (AC11, AC12), and an overrun re-plans the cycle in #122 before the pull request opens.

Files.

File Change
extension/src/studyWorkspace.ts:8154 summaryComposition for a selected test replay
extension/src/studyWorkspace.ts:13440-13468 publish: the summary view for a test replay; playbackPanelVisible; bottom panel title
extension/src/studyWorkspace.ts:19080, 19106, 19608, 22718-22750 Show Learning Summary and the view's document and messages for a test replay
extension/src/studyWorkspace.ts (open and retirement of a test replay) enter and leave the summary composition
extension/src/ui/studyHtml.ts:214, 217, 2363-2864, 3205-3507 the summary's test replay content; one transport; the Learning summary button
extension/src/ui/constants.ts:219-241, :55-90 transport and bottom panel rules for a test replay; the shortcut list's six test replay timeline entries
extension/src/studyWorkspace.ts (Study message, retirement, routing) the history's firstSequence and lastSequence beside nodeHistoryPlayback; the exits; late and invalid messages
extension/scripts/fixtures/history-transport-golden.txt unchanged (it pins the timeline track only)
extension/src/tests/studyWorkspaceTestReplay*.test.ts, extension/scripts/study-bootstrap-qa.mjs the tests above
extension/README.md, CHANGELOG.md the behavior

Out of scope. New run profiles (Pages Router, Chrome MV3, Vite, Express, Hono, library Examples) and Vitest inside a workspace package; per-step "I understand this step" (E8 of #107); the PNG's transport wording mm:ss / mm:ss, Unrecorded interval and Recorded state · <step> (E9); the Japanese 4A sentence; drift disclosure; the Wiki, skill and shortcut gaps of the entry audit; any change to the browser replay's behavior beyond 5A (C2 leaves its keys as they are, guarded by three regression cases); a host-side transport projection for both families (C1 of the CEO review) is a later candidate; the browser replay's diagram mark (C8) is a later candidate; no status bar entry is added for a summary hidden together with the bottom panel (the command and the summary's own container reopen it, and 5A keeps the learner's layout); a setting that keeps the old Study-pane layout for a test replay is not added (region 2 is the contract; the host's hide and move of views, 5A and Return to Live are the ways out); a test replay's open through MCP is not added (MCP 1.8 refuses it, and a contract change needs its own DX review); a test replay that reopens by itself after a window reload is a later candidate (C10); the PNG's transport controls Jump back, settings and fullscreen (with E9's wording, later candidate C12)

Tasks

The source of every task is this cycle's plan (D8 of #107) unless it says otherwise. A finding found during this cycle becomes one more task.

  1. Inventory: freeze in this Issue the per-line table of the 83 recordingActive reads and the 77 message.recording reads, the lines whose disposition is counterpart or probably, each with the task that changes it, and the count of the rest (the owner's rule against ritual work, AGENTS.md); dispositions: counterpart (the line decides behavior a test replay must also get in the composition), probably (it decides that only in some states; task 1 settles it as counterpart or none) or none (browser-video specific, or it keeps the two families apart). If the counterpart and probably lines exceed the estimate (15 recordingActive reads, 44 ui/studyHtml.ts lines) by more than half, the cycle is re-scoped in Cycle 0051: a test replay opens in the region-2 composition, with the Learning summary in the chat's place, one transport and 5A #122 before the first product commit. Closes with the comment. Evidence: Cycle 0051: a test replay opens in the region-2 composition, with the Learning summary in the chat's place, one transport and 5A #122 comment 6381376802 (83 and 77 reads confirmed; counterpart plus probably 20 and 35, under the 22 and 66 triggers; two gaps added: showLearningSummary's stale-selection guard compares selection.studyId (studyWorkspace.ts:19091, :19107), and enterStudyCompositionForReplay returns early with a Study pane (:11711)).
  2. Placement spike, both hosts (native, driving agent): with the current build, open a browser replay and record where the Learning summary view, Run and Debug and the chat stand in VS Code and in Cursor at the D034 layout, and whether, by the ordinary entry (with Cursor's published Move View step if it is needed, its clicks counted and named), the summary, the recorded source and the debugger's values can be read together (PRODUCT_GOAL.md:143); if they cannot in a host, that host's composition is re-planned in Cycle 0051: a test replay opens in the region-2 composition, with the Learning summary in the chat's place, one transport and 5A #122 before the first product commit. It also measures the Learning summary's width and height in each host (the first-viewport rule of Proposed change 2 and the transport's wrap use them) and compares a frame of the browser replay's composition with the PNG's region 2, every difference listed, before the first product commit. Closes with the frames, the measurements and a one-line verdict per host. Evidence: Cycle 0051: a test replay opens in the region-2 composition, with the Learning summary in the chat's place, one transport and 5A #122 comment 6381379758 (VS Code readable together after one host click, Chat collapsed, 298 × 885 px; Cursor after the published Move View step, 440 × 965 px; D31 kept, O6).
  3. Composition (DS-A) with its host tests (AC1). Fixed in 5f0bbe0 (host tests in studyWorkspaceTestReplayComposition.test.ts: the entries per host, the agent's refusal and presentation).
  4. Summary content (DS-B) with its Reader DOM cases (AC2). Fixed in 5f4ab5a (Reader DOM: the order for a stop, an output and the result, the mark, markup as text, Show more and the first viewport).
  5. One transport (DS-C) with its Reader DOM cases and the golden check (AC3). Fixed in 5f4ab5a (Reader DOM: the seven controls, the order per family and the browser control lists; the golden is byte-equal and the race behind it is removed).
  6. Routing (DS-F) with its host tests (AC6). Fixed in 5f0bbe0 (host tests: the summary view, the bottom panel, the browser replay's refusal, late and invalid messages, latest wins and the entry ticket).
  7. Bottom panel during a test replay (DS-D; source: this cycle's entry audit, the second working copy of the Study pane in the bottom panel) with its tests (AC4). Fixed in 5f0bbe0 and 5f4ab5a (host: the title; Reader DOM: transport only, no second copy).
  8. 5A for both families (DS-E) with its host and Reader DOM tests (AC5). Fixed in 5f0bbe0 and 5f4ab5a (host: paused and playing replays; Reader DOM: the button, focus and scroll, and the fallback; the button stands in the bottom panel's transport).
  9. The "moves with D8" pins (F123): each changed or replaced with its reason (AC7). Fixed in 5f0bbe0 and 5f4ab5a; each pin's Value line states its reason.
  10. N51 in both hosts on the pull request's candidate (AC8), the chat being the owner's assigned model in each host or, after observed credit exhaustion, the installed Codex Extension (AGENTS.md, Development target), named with the host and VSIX versions in the evidence: the request and its causal links frozen in a comment titled "N51 frozen requests" before the first submission; the result per host is PASS, PARTIAL, FAIL or NOT RUN with its takes' SHA-256. Evidence: VS Code PARTIAL (comment 6384164458, Copilot Chat GPT-6 Luna), Cursor PARTIAL (comment 6384636040, Agent Grok 4.6 High); (a), (c), (d), (f) PASS in both, (b) and (e) PARTIAL by transient frames, carried as N51-V1 to V3 (non-critical, feature cycle).
  11. README and CHANGELOG for the behavior (AC10). In extension/README.md, the sentences that place a test replay's explanation and transport in the Study pane (the Open replay paragraph, the Study pane's Test replay section paragraph and step 5 of Quick start: a test replay, at 8dd675b9) are replaced; a short table gives each family's transport keys (a test replay's arrows by event, Page Up forward as in the browser replay, Home and End to the first and last event); one sentence names the ways back to a hidden summary (the Learning summary button, Codebook: Show Learning Summary, the view's own container) and the host's own ways to move or hide the views; one sentence says that an agent asks the learner to open a test replay. README fixed in 73dd516. The CHANGELOG entry is written in /ship's release commit.
  12. C2: the test replay's slider keys and the browser regression case (AC11). Fixed in 5f4ab5a (Reader DOM: eight keys, chords and IME, three browser regressions, the shortcut list).
  13. The visible current step (DS-B's step heading and drawing mark), the first viewport and the states (DS-G), with their Reader DOM and host cases (AC2, AC14). Fixed in 5f4ab5a (Reader DOM: pending, refusal, browser recovery hidden, four themes' contrast).
  14. The host's first and last sequence, the zero-range slider, the mark moved by attribute, the clamped texts with Show more, the exits and late or invalid messages, with their host and Reader DOM cases (AC2, AC3, AC11, AC15). Fixed in 5f0bbe0 and 5f4ab5a (host: the 41-event history and equal times; Reader DOM: a zero time range and one spoken update).

Owner decisions

  • Standing: the owner's goal of 2026-10-24 (verbatim in Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118) and the direction of 2026-10-22 (devote every resource to the product; never spend money or break the law). The owner cannot answer, so every decision point takes the recommended option and is named here.

  • O1 (recommended, /spec; kept at the CEO review as a taste decision against Codex's priority challenge): this cycle's increment is the test replay's region-2 composition (D8 of Cycle 0049: a Vitest test run the editor chat explained is saved and replayed as a learning replay in both editors #107). Why before the entry blockers: test replays already run end to end in both hosts on the development target (N49, N50), so their screen is what learners use today; every later profile (a server, a Chrome extension, an Example) saves into the same replay screen, so this composition is where their replays will land; package-root Vitest (P02, P05) is independent of it and stays the next candidate. Considered: package-root Vitest for P02 and P05, and new run profiles (Pages Router, Chrome MV3, Vite, Express, Hono, Examples), which the entry audit ranks as the largest final-acceptance gaps; they stay the next candidates. D8 was chosen with those gaps on record (Cycle 0049: a Vitest test run the editor chat explained is saved and replayed as a learning replay in both editors #107's closing audit) and repairs a contract mismatch in a delivered feature.

  • O2 (recommended, /spec): 5A's collapse is the host's own hide of the view; Codebook adds the visible Learning summary button and keeps the state. Considered: an in-page collapse control, which in VS Code would have to close the chat's container.

  • O3 (recommended, /spec): one transport element; Previous and Next event are shown only for a test replay. Considered: dropping event steps, which loses outputs and the result as moments. The contract asks that play, pause, step backward and forward and seek share one selected moment (PRODUCT_GOAL.md:147); a test replay's outputs and result are such moments, so its event steps stay.

  • O4 (recommended, /spec): no spawned agent; the driving agent implements under the delivery chain.

  • O5 (recommended, /autoplan final gate, gate_rev 1, reply rec under the owner's standing direction "返事ができないので、選択肢はReccomendをpickしてください"): the plan as amended by the CEO, Design, DX and Eng reviews is approved as-is (plan1a). The taste decisions each took their recommendation:

    • d1: keep O1.
    • d2: N51's learning task is recorded, not gating.
    • d3: the 5A button is always shown.
    • d4: C1 is deferred.
    • d5: the 5A button sits at the status row's end.
    • d6: the label stays "Learning summary".
    • d7: the Eng contract fixes are applied, with C10 later.

    No User Challenge. Review record (private): artifacts/cycle-0051/plan/plan.md.

  • O6 (recommended, task 2): both hosts keep D31 of Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118. VS Code's summary shares the Chat container and is readable together with the recorded source and the debugger after one host click (collapse the Chat section). Cursor's summary is readable together after its published Move View step. The first-viewport rule and the transport's wrap use the measured sizes with those steps done: VS Code 298 × 885 px, Cursor 440 × 965 px. Task 11's README names both steps. Considered: forcing the Chat section closed at the replay entry, which would take the learner's chat away (O2, 5A), and a new secondary side bar entry in VS Code, which vscode.moveViews cannot create (C11).

Later candidates (a short list, no carried defect; AGENTS.md Cycle rule):

  • Package-root Vitest for P02 and P05, and new run profiles (Pages Router, Chrome MV3, Vite, Express, Hono, library Examples) (O1).
  • C1: a host-side transport projection for both families.
  • C5: the summary's visibility in presentation.
  • C8: the browser replay's diagram mark.
  • C9: a test replay's MCP open.
  • C10: a test replay that reopens by itself after a window reload.
  • E8: per-step "I understand this step".
  • E9: the PNG's transport wording.
  • C11: a full-height summary in the chat's place at VS Code's replay entry, without the host's Chat-collapse click (both families).
  • C12: the PNG's transport controls Jump back, settings and fullscreen.

Next action

Closed. PR #123 merged as bd082540 (v0.2.39.0) after CodeRabbit APPROVED 3bf26744, required CI and the exact-HEAD gate (PR comment 6384641645). The next cycle is a bug-fix cycle: /spec writes its Issue from this Issue's closing comment, one task per carried defect.

Activity

  1. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Entry and gap audit (2026-10-24, baseline main at 8dd675b9, v0.2.38.0)

    Entry.

    • Read in full: PRODUCT_GOAL.md (444 lines, goal version 10) and AGENTS.md (411 lines).
    • Image: docs/designs/assets/codebook-product-spec-v9.png, 1,878,402 bytes, SHA-256 f189ee82…caf2aa, which matches the Design target. I viewed it scaled, and region 2 at full size. All four regions are found: live, replay, DeepWiki and shortcuts.
    • State: branch codex/cycle-0051 at 8dd675b9, clean. No pull request is open. Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118 closed with nothing carried.

    Method. Each row was read against its contract from source at 8dd675b9, with file and line cited. Two read-only research passes were spot-checked by the driving agent: the profile list and summaryComposition were confirmed in source.

    Proof: native evidence is macOS only, in the Space local:codebook-qa, from Cycles 0049 and 0050 (#107 and #118). Windows and Ubuntu are not run, and no final-acceptance row is filled.

    Row Implementation (source) Proof Next action
    AC-LIVE Two profiles only: repository-browser (Next App Router at the workspace root, next dev --webpack, one click, up to 8 stops) and node-test (Vitest 4 or later at the repository root) (constants.ts:1012-1013, service.ts:1133-1138, configuredProfile.ts:55). VS Code's default Copilot-harness chat cannot reach the tools; the skill sends the learner to a Local session (utils/aiChatReadyMessage.ts:12). Development target, both hosts. Natural requests reached demonstrated for a test run (N49, N50), and a browser run reached it on the project's own port (N50 R2). Later candidates: multi-step operation and more profiles.
    AC-SAVE Status item states and Save/Open commands (studyWorkspace.ts:11331-11407). The library is the Study webview's Saved studies list (ui/studyHtml.ts:216). Both hosts, N49 and N50. Unchanged this cycle.
    AC-REPLAY Browser replay: summary composition. Test replay: Study pane section, the chat still beside it, its own transport (studyWorkspace.ts:8154, ui/studyHtml.ts:214, :2536-2730). Both hosts, N50: synchronized surfaces, F203 closed. This cycle, tasks 3 to 6.
    AC-GAPS 4A placeholder and Not recorded at this moment debugger thread for both families. Both hosts, N50 (F204). Regression only.
    AC-LEARNING One understanding decision per item (learnerSchemas.ts:22-45, nodeTestHistorySchemas.ts:126-131). Per-step "I understand this step" is absent. The current step is marked in both families. Both hosts. Per-step understanding (E8) is a later candidate.
    AC-WIKI Generation procedure inside the skill (skills/codebook/SKILL.md:51-116); loopback reader with Q&A (deepWikiReader.ts). Q&A sends source excerpts only (6 files × 80 lines, constants.ts:799-803). Cursor Q&A uses a separate cursor-agent process (utils/requestCursorWikiText.ts:91-106). Earlier cycles; no new evidence. Later candidate.
    AC-WIKI-UPDATE Output setting, Change location, the Update button and freshness (extension.ts:950-962, :1820-1859, utils/inspectDeepWikiFreshness.ts). Generating from Codebook's own Wiki entry is absent: with no Wiki it refuses and points to chat (extension.ts:1465). No new evidence. Later candidate.
    AC-SOURCE-LINKS Static vscode:// links rebound to the active host (utils/rebindDeepWikiEditorLinks.ts); handler with containment and a drift warning (extension.ts:1861-1888). A root mismatch is refused rather than routed to the right window. No new evidence. Later candidate.
    AC-ENTRY Containers codebook and codebookLearning share one icon file (package.json:227-247). The "Repository Wiki" view is the MCP book reader, not the DeepWiki (repositoryReader.ts:196-233). Both hosts (N50, F208 and F209 closed). Later candidate.
    AC-DESKTOP D034 layout; F206 and F207 closed. Region 2 for a test replay is not yet the composition. Both hosts, N50. This cycle, AC8.
    AC-SHORTCUTS Shared dialog (utils/installShortcutHelp.ts); tooltips are one string Action — Key (L234-242). There is no contributes.keybindings, no palette entry and no ? dialog in the book reader or the static Wiki. No new evidence. Later candidate. The moved transport keeps its shortcuts (regression).
    AC-SKILL One SKILL.md 1.0.47 and chatSkills. Cursor install has a receipt. The Cursor copy replaces {{CODEBOOK_PUBLISHER_PATH}} (cursorSkillDeployment.ts:1393-1402), while the README says it installs the exact bytes. Both hosts (N49, N50). Later candidate.
    AC-REAL-PROJECTS No cart target. No profile for P01 Pages Router (utils/resolveNextClientManifest.ts:13-16), Chrome MV3 (P06, P07), Vite, Express or Hono (P07, P08), or any library Example (P02 to P05). Vitest inside a workspace package is unsupported (utils/readVitestPrerequisite.ts:69), which blocks P02 and P05's tests. Development target only. The largest final-acceptance gap. Next candidates: package-root Vitest, then new profiles.

    Found by this audit: during a test replay, the bottom panel draws a second working copy of the Study pane (studyWorkspace.ts:13466, no test asserts it). It becomes task 7.

    Selected increment (O1). The region-2 composition for test replays (D8 of #107): AC-REPLAY is primary; AC-DESKTOP and AC-ENTRY are dependencies; AC-GAPS, AC-SAVE and AC-SHORTCUTS are regressions.

    • Why now: it fixes a contract mismatch in a delivered feature, on the library-test form that four of the nine projects require.
    • Starting action: task 1 (inventory) and task 2 (placement spike, native).
    • Falsifying observation: the spike shows the Learning summary cannot stand where the chat is beside a replay in a host. Then the composition for that host is re-planned before code moves.
  2. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Re-entry after compaction (2026-10-24)

    • Read in full from disk: PRODUCT_GOAL.md (444 lines, goal version 10) and AGENTS.md (411 lines); this Issue's body and comments.
    • Image: docs/designs/assets/codebook-product-spec-v9.png opened with an image tool; 1024 × 1536, 1,878,402 bytes, SHA-256 f189ee82541a72ed981e3f7a0e21bd35a19b6601df1c7208671117a335caf2aa, which matches the Design target. Regions found: 1 live, 2 replay (Learning summary in the chat's place, one transport at the bottom), 3 DeepWiki, the shortcut strip.
    • State: branch codex/cycle-0051 at 8dd675b9, no product source changed; no pull request open.
    • Phase: /autoplan Phase 1 (CEO) closed; Phase 2 (Design) resumes. No product code has moved.
  3. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    /autoplan review (2026-10-24): approved, gate_rev 1

    All four phases ran with both voices completed: the native Claude subagent and Codex (gpt-6-astra). Each Codex claim was checked against source before it was decided. The body above is the amended, approved plan. The full review record is private (artifacts/cycle-0051/plan/plan.md, git-ignored).

    Phase Codex Claude Consensus Result
    CEO (selective expansion) 5 concerns 9 issues 4/6, 2 to the gate C2 keys by event and stop; task 2 hard gate; one PR
    Design 6 concerns 12 issues litmus 2/8, 1 resolved 4/10 → 8/10; region-2 order, visible current step, transport order, states table
    DX (polish) 3 concerns 19 issues 3/6, 1 to the gate 5/10 → 7/10; MCP 1.8 refusal kept, recovery clause, README replacements
    Eng (full review) 7 concerns 12 issues 2/6, 1 resolved reality rows 7/7, 0 unverified premises, 0 critical gaps

    Five premises that were false at plan time are corrected:

    1. An agent cannot open a test replay: MCP 1.8 refuses it (service.ts:897).
    2. The transport golden pins only the timeline track (scripts/fixtures/history-transport-golden.txt).
    3. Return to Live goes to the Live composition, with the Study pane closed (studyWorkspace.ts:8183).
    4. No test replay is restored after a window reload. The persisted selection covers the browser profile only (configuredStudySchemas.ts:206).
    5. The open failure offers Show details and no Retry (utils/describeNodeLearningSave.ts:184).

    Found in review:

    • The event list reaches the page in pages of 20, so the host projects firstSequence and lastSequence (studyWorkspace.ts:406).
    • Equal-time events exist, so Replay from start, Home and End select by sequence.
    • A zero time range disables the slider (ui/studyHtml.ts:2659).
    • Long texts can push the moment out of the first viewport (constants.ts:90).
    • The diagram's mark must move by attribute so the drawing is not rebuilt (ui/studyHtml.ts:2762).
    • A move's debugger failure lacks the open path's recovery (studyWorkspace.ts:24781).

    Tests planned: host +28, Reader DOM +49, native N51 in both hosts. The test plan is ~/.gstack/projects/laststance-codebook/ryotamurakami-codex-cycle-0051-eng-review-test-plan-20261024-160308.md (private).

    Gate: rec, under the owner's standing direction; recorded as O5 in Owner decisions. There are 7 taste decisions and no User Challenge. Later candidates are listed under Owner decisions.

  4. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Task 1: inventory (closes task 1)

    Read-only; produced by a research subagent and spot-checked by the driver against studyWorkspace.ts:8154, :13444, :13463, :19080, :19608, :22719 and ui/studyHtml.ts:3206, :3314 (each quote matches the source at 8dd675b9).

    Commit: 8dd675b (branch codex/cycle-0051, v0.2.38.0). Read-only; line numbers are at this commit. Method: TypeScript AST scan (identifier recording as property or alias; enclosing function) plus a read of the code around every hit.

    Counts

    recordingActive (extension/src, non-test) recording field (ui/studyHtml.ts + utils/capturedAppHtml.ts)
    Lines containing the symbol 91 (86 in studyWorkspace.ts; 5 in isStopKeyboardHandOverDue.ts: 7, 13, 14 doc, 17 type, 23 read) 78 in studyHtml.ts (incl. 3 declaration-only lines) + 2 in capturedAppHtml.ts
    Declaration 1 (studyWorkspace.ts:845) 3 declaration-only lines (studyHtml.ts:156 type, 2001 and 2016 parameter types); line 482 is a declaration of an alias and also a read
    Pure assignments 2 (12045 = true, 12580 = false) 0
    Doc/type mentions (not counted) 1 (studyWorkspace.ts:13381) + 4 in isStopKeyboardHandOverDue.ts (7, 13, 14, 17) 0
    Total reads 83 (82 studyWorkspace.ts + 1 isStopKeyboardHandOverDue.ts:23) 77 (75 studyHtml.ts + 2 capturedAppHtml.ts)
    counterpart 8 28
    probably 12 7
    none 63 42

    (The plan's estimate of 83 and 77 reads is confirmed. Counterpart plus probably: 20 for recordingActive, 35 for studyHtml.ts.)

    recordingActive: counterpart and probably rows

    file:line function quote disposition plan item change
    studyWorkspace.ts:8154 open const summaryComposition = this.recordingActive counterpart DS-A summaryComposition = recordingActive || testReplayHoldsComposition() (selected or opening test replay; the opening state matters because enterStudyCompositionForReplay calls open() before selectedNodeHistory is set); this one line also closes the Study pane (8183-8188) and sends every Study message to the summary view (13460)
    studyWorkspace.ts:13444 publish this.recordingActive && this.moments?.visible, counterpart DS-C playbackPanelVisible must also be true for a test replay while the bottom panel is visible, so showsTransport (studyHtml 3207) gives the transport to the bottom panel and not to the summary footer
    studyWorkspace.ts:13463 publish this.moments.title = this.recordingActive counterpart DS-D moments.title = "Learning replay" for a test replay too (today "Observed moments"); with the bottom pane then suppressing the Study section (studyHtml 2355, 3564)
    studyWorkspace.ts:19080 showLearningSummary if (!this.recordingActive || !this.summaryComposition || this.closing) counterpart DS-F precondition !recordingActive || !summaryComposition -> allow when summaryComposition holds for a test replay (Show Learning Summary works for a test replay); note 19091 and 19107 compare this.selection.studyId, which is not the test replay history id (selectedNodeHistory.header.studyId), so assertCurrent needs a family-aware identity
    studyWorkspace.ts:19106 showLearningSummary > assertCurrent !this.recordingActive || counterpart DS-F same family test in the stale-selection guard; replace studyId !== this.selection.studyId by the test replay history id for that family
    studyWorkspace.ts:19608 installReaders > resolveWebviewView (summary view) if (this.recordingActive && this.summaryComposition) { counterpart DS-A / DS-B the summary view gets studyHtml("context") and a first publish only for a browser recording; for a test replay it shows the placeholder "Open saved learning from Codebook..." (clearLearningSummary at 19612). Use the composition test (summaryComposition) alone
    studyWorkspace.ts:22719 receive (first owner check) (!this.opened || !this.recordingActive || this.closing))) counterpart DS-F a message from owner === summaryView is dropped unless recordingActive; accept it while summaryComposition holds for a test replay (node-history-* from the Learning summary view)
    studyWorkspace.ts:22750 receive (re-check after initialize) (!this.opened || !this.recordingActive || this.closing))) counterpart DS-F identical twin of 22719 after await this.initialize(); change both together
    studyWorkspace.ts:1374 presentationState contentTab: this.recordingActive ? 'recording' : this.selection.tab, probably DS-A (AC1) contentTab "recording" for MCP presentation.reader. State: test replay selected. Recommend none: contentTab is the Study pane tab, MCP stays 1.8 and AC1 asks for the pane set, not the tab; the pane set comes from composition flags. Revisit only if the spike shows an agent reading contentTab to know a replay is open
    studyWorkspace.ts:2090 admitPresentation (composition branch) const recordedBundle = this.recordingActive probably DS-A recordedBundle = playback.bundle() guards assertPlacedEvidenceUnchanged (2586) across a Restore/Select layout change. State: Restore layout while a test replay moves. Recommend none: a test replay has no pixel bundle to keep equal; its moment is re-presented by its own selection. Add one host test of Restore during playing
    studyWorkspace.ts:4646 isStoppedOutsideRecording !this.recordingActive && probably DS-A live-run keyboard rule "no recording open". State: live run paused while a test replay is selected. Recommend none: unchanged behavior (a test replay is not a recording today either); confirm in task 2 spike that the replay debugger stop does not take the keyboard
    studyWorkspace.ts:4782 isLiveRunWithoutFrame !this.recordingActive probably DS-A same family as 4646 (live-run return keyboard); recommend none, same check
    studyWorkspace.ts:4839 holdsKeyboardInActiveEditor !this.recordingActive && probably DS-A same family as 4646 (hand-over to the active editor outside a recording); recommend none, same check
    studyWorkspace.ts:10844 refresh !this.recordingActive && probably DS-A "enter live once per run" skips a shown browser replay. State: new live run starts while a test replay is selected and its summary shown. Recommend counterpart: add !this.selectedNodeHistory (or !this.summaryComposition) so a run start cannot call open() over a shown replay; Return to Live stays the explicit way out
    studyWorkspace.ts:13185 message model: this.recordingActive probably DS-B model: projectPlaybackStudy(bundle) vs projectStudy. State: test replay selected. Recommend none: the test replay content rides on nodeHistory* fields (13214-13278), not on model
    studyWorkspace.ts:13189 message contentTab: this.recordingActive ? 'recording' : this.selection.tab, probably DS-B Study message contentTab "recording" (twin of 1374). Recommend none: studyHtml must switch its layout on a replay-family value, not on contentTab, because contentTab "recording" selects recording-tab (studyHtml 3647) which a test replay does not have
    studyWorkspace.ts:13332 message canClick: !this.recordingActive && Boolean(nextAction), probably DS-B canClick: !recordingActive && nextAction. State: test replay selected. Recommend none: the click/run controls are hidden in the replay layout (studyHtml 3378-3379 counterpart)
    studyWorkspace.ts:13358 message !this.recordingActive probably DS-B runRefusal hidden during a recording; #errors shows it in the summary view (studyHtml 3596). State: a refused run exists while a test replay is selected. Recommend counterpart: also withhold it for a test replay so the summary reads the replay only
    studyWorkspace.ts:14579 isStopHandOverDue recordingActive: this.recordingActive, probably DS-A passes recordingActive to isStopKeyboardHandOverDue: no keyboard hand-over while a replayed debugger stops. codebookStopLedger covers live runs and owned Node test runs only, not the replay debugger. State: replay debugger stop of a test replay. Recommend none if the spike shows no hand-over today (it is unchanged); counterpart (recordingActive || selectedNodeHistory) if it does
    runtimeSupport/utils/isStopKeyboardHandOverDue.ts:23 isStopKeyboardHandOverDue !state.recordingActive && probably DS-A the pure predicate; follows the decision at 14579 (change the caller, not this function)

    Recommendation tally for the 12 probably rows: recommend counterpart 2 (studyWorkspace.ts:10844, 13358); recommend none 10 (1374, 2090, 4646, 4782, 4839, 13185, 13189, 13332, 14579, isStopKeyboardHandOverDue.ts:23). 14579 flips to counterpart if the spike shows the replay debugger stop takes the keyboard.

    None rows for recordingActive: 63 (browser playback, recording readiness, the replay renderer, reload and the deliberate never-coexist guards).

    message.recording (studyHtml.ts, capturedAppHtml.ts): counterpart and probably rows

    file:line function quote disposition plan item change
    ui/studyHtml.ts:647 document click handler (data-playback) if (target.dataset.playback === 'start' && current?.recording?.range) counterpart DS-C Replay from start: for a test replay send node-history-event with the first event sequence (firstSequence projected by the host), not a time seek
    ui/studyHtml.ts:648 document click handler (data-playback) playback('seek', current.recording.range.startMs) counterpart DS-C browser branch body of 647; stays for the browser family inside the family dispatch
    ui/studyHtml.ts:839 playhead keydown handler !current?.recording?.range || counterpart DS-C (C2) guard !current?.recording?.range makes the slider keys browser-only; one listener must read the family shown and run that family handler (arrows by event, Page by stop, Home/End by sequence)
    ui/studyHtml.ts:2355 isReplayInBottomPanel isBottomPanel && Boolean(message.recording) counterpart DS-D bottom pane suppresses the Study section only for a browser recording; make it true for a test replay (bottom panel shows the transport only; its second Study copy goes)
    ui/studyHtml.ts:3206 showsTransport Boolean(message.recording) && counterpart DS-C Boolean(message.recording) decides that #recording-transport shows; true for a test replay too (nodeHistory present)
    ui/studyHtml.ts:3311 message listener (alias) const { model, recording } = message, counterpart DS-B / DS-C const { model, recording } = message creates the alias every later check uses; derive the replay family here and key the rows below on it
    ui/studyHtml.ts:3314 message listener document.body.dataset.replay = String(Boolean(recording)) counterpart DS-A / DS-C body[data-replay=true] drives the fixed transport, the padding and the bottom-panel CSS (ui/constants.ts 219-229, 249); must be true for a test replay
    ui/studyHtml.ts:3315 message listener text('reader-kind', recording ? 'Learning summary' : 'Codebook study') counterpart DS-B reader-kind "Learning summary" vs "Codebook study" for the document of the summary view
    ui/studyHtml.ts:3346 message listener recording counterpart DS-B presentation caption "Recorded application and source stay in the editor; learning summary stays in the sidebar." is true for a test replay too
    ui/studyHtml.ts:3357 message listener Boolean(recording) || counterpart DS-B Save-preference control hidden in a replay (the composition refuses save-preference, assertCompositionAllows 1860)
    ui/studyHtml.ts:3365 message listener button('enlarge-context')!.hidden = Boolean(recording) counterpart DS-B Enlarge-context hidden: a native sidebar has no central explanation pane to enlarge
    ui/studyHtml.ts:3366 message listener button('read-context')!.textContent = recording ? 'Summary' : 'Explanation' counterpart DS-B Read-context label "Summary"
    ui/studyHtml.ts:3369 message listener recording ? 'Read learning summary' : 'Read explanation', counterpart DS-B Read-context aria-label "Read learning summary"
    ui/studyHtml.ts:3371 message listener button('focus-context')!.textContent = recording counterpart DS-B Focus-context label "Focus learning summary" (host side action focus-context goes to showLearningSummary, 8896)
    ui/studyHtml.ts:3378 message listener element('next-scenario').hidden = Boolean(recording) counterpart DS-B next-scenario hidden in a replay
    ui/studyHtml.ts:3379 message listener element('study-controls').hidden = Boolean(recording) counterpart DS-B study-controls hidden in a replay
    ui/studyHtml.ts:3383 message listener (transport block start) if (recording) { counterpart DS-C the whole block 3383-3507 writes the shared transport only for a browser recording; split into shared parts (position, toggle, start, stops, slider, coverage) and browser-only parts (pending, reason, covered remedy, diagnostics, hint)
    ui/studyHtml.ts:3384 message listener (transport block) const range = recording.range, counterpart DS-C range of the slider/readout; a test replay needs first and last event time (slider spans recorded test time); also feeds start.disabled (3477) and playhead min/max (3481-3482)
    ui/studyHtml.ts:3386 message listener (transport block) const timeline = recording.historyTimeline ?? { counterpart DS-C historyTimeline -> coverage marks via browserCoverageLegend/renderTimelineCoverage (3502-3507); test replay keeps "the existing coverage marks"
    ui/studyHtml.ts:3389 message listener (transport block) const presentedMs = recording.presentedMs counterpart DS-C presentedMs = position for gap test and readout; a test replay uses the selected event time
    ui/studyHtml.ts:3414 message listener (transport block) '${recording.presentedMs === undefined ? 'No position presented' : 'Presented ${seconds(recording.presentedMs) counterpart DS-C #playback-position readout: browser "Presented x / y"; test replay " s / s"
    ui/studyHtml.ts:3455 message listener (transport block) const pause = recording.mode === 'playing' || pending counterpart DS-C Play/Pause state from recording.mode (+ pending); test replay from nodeHistoryPlayback state (messages node-history-playback play/pause)
    ui/studyHtml.ts:3465 message listener (transport block) (recording.readiness !== 'ready' || counterpart DS-C Play disabled rule (readiness, no range, at end); test replay: disabled at the history last event (today studyHtml 1820) and with no usable event
    ui/studyHtml.ts:3467 message listener (transport block) recording.presentedMs === range.endMs) counterpart DS-C end-of-range part of the same Play disabled rule
    ui/studyHtml.ts:3484 message listener (transport block) playhead.value = String(recording.presentedMs ?? range?.startMs ?? 0) counterpart DS-C playhead.value; test replay value = selected event time, a history with equal times keeps the slider enabled (new rule)
    ui/studyHtml.ts:3487 message listener (transport block) recording.presentedMs === undefined counterpart DS-C aria-valuetext wording per family (" s of recorded test time" for a test replay)
    ui/studyHtml.ts:3489 message listener (transport block) : '${seconds(recording.presentedMs)} presented${range?.endKnown === false ? '; recording end unknown' : ''}', counterpart DS-C branch of the same aria-valuetext (browser wording stays)
    ui/studyHtml.ts:3564 message listener Boolean(recording && document.body.classList.contains('moments-only')) counterpart DS-D #study-state hidden in the bottom pane when a recording shows; a test replay in the bottom pane must hide it too (transport only)
    ui/studyHtml.ts:3318 message listener !recording && probably DS-B shouldRevealFollowedPause needs !recording. State: contentTab live + follow + an observation while a test replay is selected, narrow view. Recommend counterpart (replay family): otherwise the summary view scrolls live-content into view
    ui/studyHtml.ts:3440 message listener (transport block) !failed && recording.nativeValuesUninspected probably DS-B / DS-C #playback-hint shows nativeValuesHint. State: test replay with uninspected values. Recommend none for the transport: DS-B puts the values hint with Show Variables in the summary content; a second copy in the transport duplicates it
    ui/studyHtml.ts:3447 message listener (transport block) !failed && Boolean(recording.nativeValuesUninspected), probably DS-B / DS-C offerShowVariables for the transport (same decision as 3440; recommend none)
    ui/studyHtml.ts:3546 message listener message.study?.terminal && !recording probably DS-B endedProgress "Last observed stop" for a terminal study when not recording. State: a configured study ended and a test replay selected. Recommend counterpart: omit it for a test replay
    ui/studyHtml.ts:3568 message listener ? '${recording ? 'Recorded study (whole run)' : message.study.terminal ? 'Study ended' : 'Study in progress'} probably DS-B #study-state wording "Recorded study (whole run)" vs study ended/in progress. State: message.study present while a test replay is selected (stale browser study). Recommend counterpart: hide #study-state for a test replay (it describes another study)
    ui/studyHtml.ts:3752 message listener const learning = recording?.learningSummary probably DS-B learning = recording.learningSummary feeds #learning-material (title, question, summary, sequence). State: test replay. Recommend none: keep the test replay content in #node-history (renderTestReplay*) and reorder per the PNG; reuse sequenceView, not this section. If the implementation chooses to reuse #learning-material, all of 3752-3803 become counterpart
    ui/studyHtml.ts:3754 message listener element('learning-unavailable').hidden = !recording || Boolean(learning) probably DS-B #learning-unavailable shown when recording has no learning summary; with !recording it stays hidden for a test replay (correct). Recommend none, but re-check if 3752 flips

    Recommendation tally for the 7 probably rows: counterpart 3 (3318, 3546, 3568); none 4 (3440, 3447, 3752, 3754).

    None rows for recording: 42 (40 in studyHtml.ts, 2 in capturedAppHtml.ts).

    Re-plan trigger check

    • recordingActive: counterpart + probably = 20 (8 + 12); the plan estimated 15 (8 + 7); the limit is 22 (1.5 x 15). Not exceeded (1.33 x). The counterpart count equals the plan's 8; the probably rows are 12 against 7, but 10 of them recommend none.
    • ui/studyHtml.ts: counterpart + probably = 35 (28 + 7); the plan estimated 44; the limit is 66. Not exceeded (0.80 x). Counted per line of the recording field; the real transport work is larger than the line count suggests (see the note above: the block 3383-3507 and the click and keydown handlers are rewritten into a family dispatch), but the line-based trigger does not fire.
    • Verdict: no re-plan trigger. Two things the plan does not mention and a re-plan should not wait for: (1) studyWorkspace.ts:19091 and 19107 compare this.selection.studyId, which is not the test replay's id, so showLearningSummary's stale-selection guard cannot be reused as is; (2) studyWorkspace.ts:11711 (enterStudyCompositionForReplay returns early when opened && !liveComposition && contextPanel) assumes a Study pane; with the summary composition there is none, and a reader already in the Study composition (with a context panel) must still run open() to switch composition.

    Other places the composition depends on

    summaryComposition reads are implicit counterparts of recordingActive: once 8154 is true for a test replay every one of them starts to apply. Those that carry a browser-only assumption:

    file:line symbol why it matters
    studyWorkspace.ts:968 private summaryComposition declaration; reset at 8621 (forgetUnopenedComposition) and 9544 (close); set at 8181
    studyWorkspace.ts:8154-8188 open composition flags; Study pane disposal and presentationMode set at 8183-8188; DS-A core
    studyWorkspace.ts:8146 open !this.testReplayHoldsComposition() already keeps a test replay out of the Live composition (F208); the same predicate is the natural test for 8154
    studyWorkspace.ts:8526-8531 open if (this.summaryComposition) calls waitForRecordingWindow and showLearningSummary(revealPlayback = origin !== 'repository' && (firstOpen
    studyWorkspace.ts:5646-5649 performPresentation summaryComposition -> settleOwnedPlayback (browser playback wait); no-op needed for a test replay
    studyWorkspace.ts:12420 loadPlayback wait summaryComposition && !summaryView.visible ends the wait for a rendered receipt; browser path only, but keyed on the flag
    studyWorkspace.ts:13460-13461 publish posts the Study message to the summary view while summaryComposition (no recordingActive here); the test replay's messages reach the view automatically after 8154, but 19608 must give the view its document first
    studyWorkspace.ts:22715-22716, 22746-22747 receive owner check: with summaryComposition the owner must be the summary view (not the Study pane); bottom-panel owner is already accepted for any family
    studyWorkspace.ts:19151-19153, 19403-19412 showLearningSummary, clearLearningSummary summaryDocumentActive lazily sets the summary view html; clearing shows the placeholder
    studyWorkspace.ts:19142, 19174, 19330-19333, 19390, 19421-19425 showLearningSummary, moveSummaryBesideChatOnce, isSummaryViewInState visibility tracking of summaryView that 5A (DS-E) builds on; family independent
    studyWorkspace.ts:19601-19606 resolveWebviewView onDidChangeVisibility republishes when the summary view becomes visible, keeps focus memory; family independent, needed for 5A
    studyWorkspace.ts:6258, 8896 readStudyPane, action focus-context context region goes to showLearningSummary when summaryComposition; fails today for a test replay through 19080
    studyWorkspace.ts:2533 mayRevealCoveredReplay summaryComposition && replayApplicationCovered; the flag is browser-only and stays false for a test replay
    studyWorkspace.ts:1298, 1324, 1880, 2068, 2410, 17251, 20825-20842, 21577-21607, 24434 usesPreparedApplicationLayout, presentationState, hasComposition, admitPresentation, focusCurrentPresentation, noteCreatedSourceGroup, restore/arrange helpers, needsReaderArrangement layout code that treats Live and summary as one app/source + sidebar composition; they pick up the test replay without edits, which AC1 tests
    studyWorkspace.ts:1322, 2285, 8891, 11528-11534, 13551, 14721 testReplayHoldsComposition() the existing test-replay-only predicate (selected, opening, host opening): presentationState columns, source slot, Focus source, renderSelection early return, layoutSourceReady
    studyWorkspace.ts:11710-11718 enterStudyCompositionForReplay early return opened && !liveComposition && contextPanel assumes the Study pane (see trigger check)
    studyWorkspace.ts:13443-13445 publish playbackPanelVisible (listed above as 13444)
    studyWorkspace.ts:11801, 12601, 22937-23064 node-history receivers / selectedNodeHistoryRequest latest-request-wins routing DS-F relies on (request counter bumped at 11801 and 12601); refusal sentence at 23005-23008
    ui/studyHtml.ts:1854 isBottomPanel body.classList.contains('moments-only'); the pane identity used by 2355, 3207, 3564
    ui/studyHtml.ts:3205-3226 showsTransport, offerTransport the transport owner rule (playbackPanelVisible && !isBottomPanel) and the empty status regions of the pane that does not show it
    ui/studyHtml.ts:2042-2050 hideArticleForTestReplay already keyed on message.nodeHistory (not recording): hides tabs, source-flow, loading and selected for a test replay
    ui/studyHtml.ts:2363-2374, 2536-2730 renderTestReplay, renderTestReplayTransport the Study-pane section and its own #node-history-transport (to be replaced by the shared transport); replaying argument at 3896
    ui/studyHtml.ts:3469-3477 transport block recordedStep()-based Previous/Next moment disabled and Replay from start disabled: browser-only sources
    ui/studyHtml.ts:3918 revealNodeHistoryOnOpen scroll/focus on open of a test replay in the Study pane; must follow it into the summary view
    ui/studyHtml.ts:1915-1929, 1991 focus memory / settleFocus summary-view focus memory 5A uses
    ui/constants.ts:219-229, 249 CSS body[data-replay=true], body.moments-only[data-replay=true] hides saved studies/observed moments/node-history section in the bottom pane and fixes the transport; all keyed on the attribute written at studyHtml.ts:3314
    utils/unconfirmedCompositionRefusal.ts:10 unconfirmedCompositionRefusal(showsRecording) called with this.summaryComposition at studyWorkspace.ts:2671 and 5965; wording says recording for any summary composition
    (no helper found) isBrowserReplay-like helper none exists; the two predicates are the field recordingActive and the message field recording / playbackPanelVisible
  5. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Task 2: placement spike, both hosts (closes task 2)

    Setup.

    • Space: local:codebook-qa (macOS 26 VM, display 1920 × 1080, light theme, default zoom).
    • Window: each editor at 1920 × 1050.
    • Build: main at 8dd675b9, packaged as codebook-8dd675b9.vsix (SHA-256 95c8f6ca…49a7, identical on both sides), installed as 0.2.38 in both hosts.
    • VS Code 1.142.0 (6d62b1d5), profile Codebook QA 0049.
    • Cursor 3.27.12 (df132ffb), default QA profile.
    • Repository: nextjs-dashboard at 1936e41, clean.
    • Evidence: private, in artifacts/cycle-0051/spike/. Each SHA-256 is identical in the Space and on the Mac:
      • vscode-browser-replay-01.png 5b70dc59…3989
      • vscode-browser-replay-02-chat-collapsed.png 70be4471…c8cf
      • cursor-01.png f444b73b…74b0
      • cursor-03-moved.png f6970617…28b7
      • cursor-04-moved-with-debug.png 9cd04fc8…2c945

    VS Code (a saved browser replay, opened from the Study workspace).

    • The Learning summary stands in the Chat container of the secondary side bar, as D31 of Cycle 0050: every defect Cycle 0049 carried is fixed or closed with evidence #118 places it. In this profile its section is about 298 × 195 px, above the Chat. Only the title and controls show, and the summary, diagram and moment are below the fold. The default size after the once-per-profile move is unknown: this profile was moved in earlier cycles.
    • One host click (collapse the Chat section by its header; the same click expands it again) gives the summary the whole side bar, about 298 × 885 px. The summary, the recorded source and the debugger's recorded values can then be read together, and the layout is close to region 2.
    • Verdict: readable together after one host click. D31's placement is kept.

    Cursor (the Learning summary container; no browser replay is saved in Cursor's storage, so its placement was observed with the view's placeholder).

    • By the ordinary entry, the summary opens in the primary side bar in Run and Debug's place, so it is not readable together with the debugger's values.

    • The published step resolves this:

      1. Move Learning Summary…
      2. New Secondary Side Bar Entry (two clicks so far).
      3. Run and Debug back on the left (⇧⌘D, one click), because Cursor left the primary side bar empty.

      After it, the summary stands on the right in the chat's place, about 440 × 965 px, with the Agent chat one tab away.

    • Verdict: readable together after the published step (two clicks plus one).

    • D31's placement is kept. The layout was restored afterwards with View: Reset View Locations; the profile's views were at their defaults before the move.

    Region 2 versus the browser replay's composition (VS Code, Chat collapsed):

    1. The right column is narrower: 298 px against about a third of the window. This is the host's side-bar width, which the learner can resize, so it is allowed.
    2. The summary starts with Keyboard shortcuts, the collapsed Study view and pane controls, and (browser only) Open article, before the title. For a test replay, DS-B's order governs, and the two shared header controls are allowed: Keyboard shortcuts is region 2's ?.
    3. An unrelated editor group (utils.ts) stands under the recorded source. These are the learner's own editors, kept by 5A, so allowed.
    4. The recorded application pane is short. This is the host's editor-group size, so allowed.
    5. The bottom panel is taller than the transport, with an empty area. This is the host's panel height, so allowed.
    6. The PNG's transport has Jump back, a settings button, a fullscreen button and the wording mm:ss / mm:ss / Unrecorded interval / Recorded state · <step>. These are out of scope (E9 and these controls; later candidate C12).
    7. The browser diagram marks no current step (C8).

    Decision (O6, recommended).

    • Both hosts keep D31.
    • The first-viewport rule (DS-B) and the transport's wrap use the measured sizes with each host's step done: VS Code 298 × 885 px, Cursor 440 × 965 px.
    • Task 11's README sentence names VS Code's Chat-collapse click and Cursor's Move View step.
    • Later candidate C11: a full-height summary in the chat's place at VS Code's replay entry without the host click (both families).

    No product code changed in tasks 1 and 2.

  6. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Re-entry after compaction (2026-10-24, implementation phase)

    • Read in full from disk: PRODUCT_GOAL.md (444 lines, goal version 10), AGENTS.md (411 lines), and this Issue's body and its 5 comments.
    • Image: docs/designs/assets/codebook-product-spec-v9.png, opened with an image tool. It is 1024 × 1536, 1,878,402 bytes, SHA-256 f189ee82541a72ed981e3f7a0e21bd35a19b6601df1c7208671117a335caf2aa, which matches the Design target.
    • Regions found: 1 live, 2 replay, 3 DeepWiki, and the shortcut strip. Region 2 has the Learning summary in the chat's place, the moment block under the diagram, and one transport at the bottom with ? and the status.
    • State: branch codex/cycle-0051 at 8dd675b9. The uncommitted product edits are in studyWorkspace.ts, ui/studyHtml.ts, ui/constants.ts, utils/describeNodeTestReplay.ts and utils/installShortcutHelp.ts. No pull request is open.
    • Phase: implementing (tasks 3 to 8 and 12 to 14 are in progress). Done so far: the composition and routing on the host, the shared transport on the page, the step heading, the drawing's mark and Show more. Next: the focus fallback, CSS, the refusal and recovery projection, then the tests.
  7. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Implementation progress (2026-10-24): findings while moving the old pins

    The work is uncommitted on codex/cycle-0051. The host composition, routing, shared transport, summary content and the 5A button are in place.

    Checks so far:

    • All 2,005 existing host tests in the studyWorkspace* and playbackController partitions pass.
    • All 235 existing cases of study-bootstrap-qa.mjs pass.
    • The "moves with D8" pins (F123) were converted, each with its reason in the test's Value line.
    • The new host tests are in studyWorkspaceTestReplayComposition.test.ts. The new Reader DOM cases are next.

    Findings, each fixed in this cycle or recorded as evidence:

    1. Deleting the selected test replay cannot happen. studyRemovalRefusal refuses a test replay's deletion with its nodeHistory sentence. "Retirement by deleting the selected study" therefore does not apply. The host test pins the refusal, and the replay stays on its moment.
    2. A failed open of another test replay now pauses the shown one. openNodeHistory pauses the playback, so no timer runs behind a failed open, and the last committed moment stays (DS-G).
    3. Bug: an open could treat itself as superseded. openNodeHistoryFromHost captured the reader revision as a default parameter, before "Close browser replay" and the composition entry changed it. The status item's open now takes the revision after the entry.
    4. Bug: the latest entry did not always win. An earlier entry's composition change could finish after a later click. Each learner entry now takes a ticket when it starts, and an entry that a newer one overtook stops (EN19).
    5. A test replay's Restore in the summary composition now uses its own Restore, which shows the slot again (F413). It required the Study pane before.
    6. Bug: a preview refusal could retry forever. The refusal was answered after the composition change, so the named group no longer held the preview. It is now answered first, in the composition the open met it in.
    7. The transport golden depended on a race, on main too. Something outside the page script adds style="" to the slider. The golden matched only while the first recording message wrote aria-valuetext first. The slider now gets its no-position text at start, so the attribute order is fixed. The golden file is unchanged.
    8. 5A button placement. The 5A button appears only in the bottom panel's transport. In the summary's own footer it would bring back a summary that is already shown, and it squeezed the browser status row at 300 px.
    9. Focus on reopen. The reopen focuses the title heading only in a summary that has never had a focused control (the first open, an empty history). A learner's deliberate background click keeps its rule.
    10. Test seams changed (each reported in the PR):
      • The harness's receive and receiveContext deliver from the Learning summary view while a replay holds the summary composition, because its Study pane is closed.
      • constrainStudyGrid now takes the group count.
  8. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Local reviews and native smoke (2026-10-24)

    Local CodeRabbit CLI (0.9.1, base 8dd675b9, -c .coderabbit.yaml). coderabbit config validate refuses the CLI's own current schema (unknown keyword: "x-undocumented"); this is a tooling limit, not a finding about our config.

    • Round 1, on a1a7a558: 5 findings, all fixed in a7f9a206.
      • Major: two test replay entries at once on a closed reader left no replay shown. Entries now take turns entering the composition, and the latest one opens.
      • Minor (two findings): the one-replay-at-a-time answer now closes only the browser replay it named, and only for the latest entry.
      • Minor: two Reader DOM case groups now publish their own starting state.
      • Trivial: one assertion that the harness's ordering made pass is removed.
      • Each fix has a test that is red on a1a7a558.
    • Round 2, on a7f9a206: 2 minor findings, both fixed in 8a30e882. The Shift+Tab case's Value line now states the fixed-bar contract, and the README names how far 5A was checked by hand.

    OCR delegated review (open-code-review 1.13.3, range 8dd675b9..a1a7a558):

    • 7 of 7 eligible files reviewed: studyWorkspace.ts, ui/studyHtml.ts, ui/constants.ts, describeNodeTestReplay.ts, installShortcutHelp.ts, studyWorkspaceHarness.ts, study-bootstrap-qa.mjs.
    • OCR's default exclusions (reported separately): README.md and 7 test files.
    • 1 low finding: a doc comment stood on the wrong field. Fixed in a1a7a558.

    Red-first evidence:

    • Host: 16 of the 27 composition tests fail on 8dd675b9. The other 9 guard contracts main already kept: the agent's refusal, the refused deletion, no reopen after a reload, timers stopping on Return to Live.
    • Reader DOM: 29 of the new block's 38 case groups fail on 8dd675b9. Of the passing ones, the browser rows, controls and keys are regression guards, and the two 5A focus cases guard the existing focus memory. The chord case and the browser-recovery case gained positive controls after that run.

    Native smoke, not N51 (development VSIX codebook-a7f9a206.vsix, SHA-256 a46ef254…3532, identical in the Space; Space local:codebook-qa; nextjs-dashboard at 1936e41):

    • VS Code 1.142.0, profile Codebook QA 0049. Opening a saved test replay from Saved studies gave the composition: the Study pane closed, the Application pane, the recorded-source tab, Run and Debug, the Learning summary above the Chat, and the bottom panel with the shared transport (event steps, Test replay paused, the Learning summary button).
      • Next stop moved every surface to one moment, and ArrowRight on the slider stepped to the next event.
      • Hiding the side bar and pressing the Learning summary button gave back the same moment and reading position.
      • On the earlier build a1a7a558, two defects showed: the saved browser study's parts above the summary, and a "recorded source not shown" line. Both are fixed in a7f9a206 and confirmed absent on the new build.
    • Cursor 3.27.12. The same composition. Run and Debug took the primary side bar it shares with the summary (D31). The Learning summary button showed the summary there, and its title took the focus.
    • No screenshots were kept as evidence; N51 (task 10) records OBS takes on the PR candidate.
  9. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Re-entry after compaction (2026-10-24, /ship phase)

    • Read in full from disk: PRODUCT_GOAL.md (444 lines, goal version 10), AGENTS.md (411 lines), and this Issue's body and its 8 comments.
    • Image: docs/designs/assets/codebook-product-spec-v9.png, opened with an image tool; 1024 × 1536, 1,878,402 bytes, SHA-256 f189ee82541a72ed981e3f7a0e21bd35a19b6601df1c7208671117a335caf2aa, which matches the Design target. Regions found: 1 live, 2 replay (Learning summary in the chat's place, one transport at the bottom), 3 DeepWiki, the shortcut strip.
    • State: branch codex/cycle-0051 at 8a30e882; uncommitted edits in extension/scripts/study-bootstrap-qa.mjs and extension/src/tests/studyWorkspaceTestReplayComposition.test.ts (pre-gate fixes). No pull request is open.
    • Phase: validating. /ship Step 5 pre-gate: the timing check now passes (3 waits marked gstack-timing-ok with their reason); the secrets check flags two key-name literals in a Reader DOM case as secret-named values (false positive), being rewritten.
  10. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    /ship result (2026-10-24): PR #123, v0.2.39.0

    PR: #123 (Refs #122), head ac27cc1a, final tree d2753786. Delivery: PR-open. Required CI, hosted CodeRabbit and N51 (task 10) run before the merge.

    Gates on the final tree.

    • Exact-tree gate (AC9), 15 checks: all exit 0. pnpm test gave 6,696 tests (0 fail), pnpm test:package 1,071 (0 fail), and study-bootstrap 282 cases (0 errors) in about 25 s of the reader-dom job's 600 s.
    • Pre-gate Stage 1 passes.
    • Coverage audit: 93% value-weighted (26 of 28 paths). The 2 gaps are pre-existing browser-replay clicks.
    • Plan audit: 15 of 15 items DONE or CHANGED. AC15's delete is refused rather than retired, as the findings comment records.

    Repairs during /ship. Each repair commit is red-first where it changes behavior.

    • f9347aac: the pre-gate's secrets scan flagged key names in a Reader DOM case. Three timed waits were marked gstack-timing-ok.
    • 5500fba5: the measured health gate counted two page handlers above the baseline. The new branches now stand in helpers, and behavior is unchanged (282 Reader DOM cases).
    • 9d745e0d: a test replay's departure left the Learning summary's document beside the chat with dead controls. This fails AC15 and AC8 (e). The summary is now cleared when the reader leaves the summary composition. Both tests fail without the fix.
    • 12d8f430: the new Reader DOM block's counter broke the package test's revision rule. It is renamed.
    • The release commit missed EXTENSION_VERSION. Amended.

    Reviews. Pre-landing passes 1, 2 and 4 used 6 specialists plus Red Team. Pass 3's record was lost to a detached HEAD and re-run as pass 4 on the same tree. Adversarial passes 1–3 used Claude, Codex adversarial and Codex structured (gpt-6-astra); the structured gate passed each time.

    Feature-cycle rule: non-critical findings are answered Skip and carried. They will be named in this Issue's closing comment for the next cycle:

    • fixed-time waits in three host tests;
    • two JSDoc blocks above the wrong functions;
    • an unanswered one-replay-at-a-time notice holds the entry turn;
    • Close and Return to Live do not invalidate a waiting entry;
    • a stale-revision Saved studies open can leave an empty summary composition;
    • Open replay with the summary and the bottom panel hidden re-shows no UI;
    • a browser study chosen from a test replay's summary bypasses the editor-area deferral;
    • showLearningSummary's identity changes during an open (STALE_PRESENTATION);
    • every move failure is worded as a debugger failure;
    • forgetUnopenedComposition, and a Reload racing another open(), can leave or blank the summary;
    • step marks bound by SVG sibling order;
    • Show more's expanded state persists across replays;
    • nodeHistoryRefusal is not sanitized at publish;
    • untested cells: browser replay × another study, browser replay × failed open, browser Replay from start and Pause clicks;
    • two stale comments.

    Closed with evidence: an older entry's failed open reporting late (a superseded catch returns superseded), and the preview retry's revision (intended).

    Next: required CI and CodeRabbit on #123, then N51 in both hosts (frozen requests posted before the first submission), the exact-HEAD gate, and the merge with --match-head-commit.

  11. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    N51 frozen requests (Cycle 0051, task 10, AC8)

    Frozen before the first submission. The requests and causal links below were read from nextjs-dashboard at 1936e41 (read-only); the chat gets the request only.

    Candidate. PR #123 head ac27cc1a (v0.2.39.0), VSIX codebook-ac27cc1a.vsix, SHA-256 21fafd57b202db4665d4a6430529c1fa8ccdc996a775b4d0454645e923b3d701 (2,017,716 bytes; identical in the Space), installed as laststance.codebook@0.2.39 in both hosts. Space local:codebook-qa (macOS 26 VM, 1920 × 1080), each editor window expanded, default zoom (D034). VS Code 1.142.0, profile Codebook QA 0049; Cursor 3.27.12, its QA profile. OBS Window Capture, every native frame of each transition inspected.

    VS Code: Copilot Chat, GPT-6 Luna

    Request (verbatim):

    /codebook 請求書を編集して保存するとき、サーバーアクションが入力された金額と状態をどう検証してセント単位に直し、どの値でデータベースを更新して一覧を再検証するのか、入力が不正なときは何も書き込まずに何を返すのかを、テストを実際に動かして、止めた時点の実際の値を見ながら解説して

    Causal links (for checking the explanation; not given to the chat):

    1. updateInvoice(id, prevState, formData) reads customerId, amount and status from the form and validates them with UpdateInvoice.safeParse (app/lib/actions.ts:114-118).
    2. A valid amount is coerced to a number and multiplied by 100 (amountInCents, :127-128); the test's 8.75 becomes 875.
    3. db.update(invoices).set({ customerId, amount: amountInCents, status }).where(eq(invoices.id, id)) (:131-138).
    4. revalidatePath('/dashboard/invoices'), then redirect('/dashboard/invoices') (:143-144); in the test the mocked redirect throws NEXT_REDIRECT.
    5. An invalid input (-1, refunded) returns the field errors and Missing Fields. Failed to Update Invoice. with no update, revalidation or redirect (:120-125).
      Boundaries the explanation must keep apart: the database and revalidatePath are mocks in the test (observed calls, not a real write); the redirect's effect on a browser is source reasoning.

    Cursor: Agent, Grok 4.6 High (Fast allowed)

    Request (verbatim):

    /codebook ログインに失敗したとき、サーバーアクションがパスワードの誤りとそれ以外の認証エラーをどう見分けて、それぞれの場合に何を返すのか、あるいは投げ直すのかを、テストを実際に動かして、止めた時点の実際の値を見ながら解説して

    Causal links (not given to the chat):

    1. authenticate(prevState, formData) calls signIn('credentials', Object.fromEntries(formData)) (app/lib/actions.ts:32); the test checks the email, password and redirectTo it receives.
    2. A rejected signIn with an AuthError whose type is CredentialsSignin returns the string CredentialsSignin (:35-36).
    3. Any other error, such as an AuthError of type AccessDenied, is thrown again (:39).
      Boundaries: signIn and AuthError are mocks in the test; that a successful signIn throws NEXT_REDIRECT (:38) is source reasoning, not observed in these tests.

    Procedure per host

    Run the request in the standard chat; save the replay; stop the run and close the chat; reopen it from Saved studies; then check AC8 (a) to (f), compare a screenshot of (a) with the PNG's region 2 and list every difference, and record the non-gating learning task (the condition that decided the test's result and the recorded value behind it, with the time from the open in Saved studies). Also observed: whether the composition leaves an empty editor group (a pin of the fake editor keeps one; Cycle 0051 /ship review). If credits run out, the installed Codex Extension takes the chat, named as such.

  12. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Re-entry after compaction (2026-10-24, N51 phase)

    • Read in full from disk: PRODUCT_GOAL.md (444 lines, goal version 10), AGENTS.md, and this Issue's body and its 11 comments.
    • Image: docs/designs/assets/codebook-product-spec-v9.png, opened with an image tool; 1024 × 1536, 1,878,402 bytes, SHA-256 f189ee82541a72ed981e3f7a0e21bd35a19b6601df1c7208671117a335caf2aa, which matches the Design target. Regions found: 1 live, 2 replay (Learning summary in the chat's place, one transport at the bottom), 3 DeepWiki, the shortcut strip.
    • State: branch codex/cycle-0051 at 3bf26744 (PR v0.2.39.0 feat: a test replay opens in the learning-replay composition, with one transport and the Learning summary button (Cycle 0051) #123 head, docs-only since ac27cc1a), clean.
    • Phase: validating. N51 in VS Code: take 1 recorded (criteria a, b, c, e); frame inspection in progress; take 2 (d, f) and Cursor next.
  13. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    N51 result, VS Code (task 10, AC8): PARTIAL

    Identities.

    • Candidate: PR v0.2.39.0 feat: a test replay opens in the learning-replay composition, with one transport and the Learning summary button (Cycle 0051) #123 head ac27cc1a (v0.2.39.0). VSIX codebook-ac27cc1a.vsix, SHA-256 21fafd57…d701, installed as laststance.codebook@0.2.39. PR head 3bf26744 changes only CHANGELOG.md and extension/README.md after it, so the packaged code is the same.
    • Space local:codebook-qa: macOS 26 VM, 1920 × 1080. VS Code 1.142.0, profile Codebook QA 0049, window 1920 × 1050, default zoom, theme Dark 2026.
    • Target: nextjs-dashboard at 1936e41, clean.
    • Chat: Copilot Chat in a Local session, Agent mode, model GPT-6 Luna. The frozen request was submitted verbatim at about 11:36:55Z. No credits ran out.

    Live run (not gating).

    • The AI called codebook_status, codebook_start, codebook_continue and codebook_explain_node_history. It ran both updateInvoice tests and explained them at their stops.
    • Its final answer covers both cases:
      • The success case: customer-456, 875, paid, then set/where, then revalidatePath and redirect.
      • The invalid case: -1 and refunded give success: false with 2 Zod issues. The action returns the errors and the message, with no update, revalidation or redirect.
    • It kept the mocked-database boundary.
    • One codebook_continue returned RUNTIME_FAILED because the required fact revalidatePath.mock.calls.length was unavailable. The AI recovered by itself.
    • Copilot asked "Continue to iterate?" once, after 72 steps; I pressed Continue.
    • Both histories were saved complete.

    Takes. Recorded with OBS Window Capture of the QA window, 1920 × 1050 at 30 fps, with a silent audio track (−91 dB). Each SHA-256 is identical in the Space and on the Mac; the files are private, under artifacts/cycle-0051/n51/vscode/.

    Take File SHA-256 Duration
    Preflight 2026-10-24 04-52-23.mp4 bcbbc992…e70c —
    Take 1: (a), (b), (c), (e) 2026-10-24 04-53-23.mp4 46d27aaf…beab 343 s
    Take 2: (d), (e) browser comparison, (f) 2026-10-24 05-11-07.mp4 7191c5a4…149c 437.5 s

    The (f) stills, captured with screencapture: n51-f-dark.png 09ac75be…7037, n51-f-light-c.png f0efe597…5436, n51-f-light-e.png 798fb021…6d70.

    Criteria. Every native frame of each transition was inspected from the change-frame sheets.

    • (a) PASS. Opened from Saved studies (test replay e5cc3f40, "updates invoice cents"). The Study pane closed. Run and Debug showed the recorded stop's values and stack (Recorded test stop 2). The Application pane (Recorded test output · 29.97 s) stood above the recorded-source tab, the Learning summary in the Chat container, and the transport in the bottom panel. No empty editor group.

    • (b) PARTIAL. Next and Previous stop, Next and Previous event (output, then result), Replay from start, a seek, ArrowRight and Home on the slider, and Play each moved every surface to one moment. On stop moves, the previous stop's CodeLens/inline label stays for 2 to 3 frames (about 70 to 100 ms) beside the pending target.

    • (c) PASS. The moment was Stop 2 of 2 · 29.97 s. I hid the side bar, then pressed the transport's Learning summary button.

      • Before the hide and after the reopen (234 s against 256 s): the debugger region differs by AE 0, the transport by AE 13, and the summary column by AE 767 (0.29% of its pixels).
      • The summary column's difference is a hover tooltip. The moment and the reading position are the same.
    • (d) PASS. I opened the saved browser study "Repository browser study 10/23 3:29:19 PM" through its Recording tab. It showed its own composition: the recorded application, Captured-source.mts, recorded values, the browser summary, and a transport without event buttons that reads Presented 245.09 s / 332.90 s.

      • To reach the Recording tab I went through Open article, which opened the Repository Wiki pane, and then the Learning Outline.
    • (e) PARTIAL. I ran Return to Current Pause from the test replay (take 1, about 272 s) and from the browser replay (take 2, about 208 s), for comparison. Both end the same way:

      • the Live composition, with the Study pane closed;
      • the summary's placeholder;
      • the same active editor, Captured-auth.config.ts at Ln 12, Col 1.

      In the transition:

      • Test replay: for 3 frames (about 100 ms), the Learning summary draws the Live Study content: two layout-warning sentences, Observed moments and Saved studies. In the same frames the bottom panel keeps a test-family transport (Test journal playback, event buttons).
      • Browser replay: 1 frame of Study content in the summary, and 1 frame of the test-family transport in the bottom panel.
    • (f) PASS. In Dark 2026 and Light 2026, these are visible and distinguishable: the drawing's step mark (link color, bold, underline), the event buttons, and the keyboard focus ring on Next event (a double ring).

      • The theme was changed with Preferences: Color Theme. The profile's settings.json was restored byte for byte afterwards (SHA-256 42d9312b…e1b5 before and after).

    Region 2 comparison (take 1, 234 s, against the PNG). Each difference, with why it is allowed:

    1. The summary is 298 px wide and sits in the Chat container, with Chat collapsed. Allowed by O6: the host's side-bar width and VS Code's Chat-collapse click.
    2. The summary starts with Keyboard shortcuts and Study view and pane controls. Allowed by O6.
    3. The diagram's scroll area is short and shows one or two participants at this width; the whole drawing scrolls. This follows from the host width and the planned first-viewport cap (DS-B).
    4. The Application pane shows recorded test output, not a page. Test evidence never invents a Web UI (PRODUCT_GOAL.md:151).
    5. Labels: the tab reads codebook · Application and Captured-actions.test.ts where the PNG has … · Replay and actions.ts (recorded source). Run and Debug's configuration picker shows the workspace's launch configuration, and Variables has no (recorded state) suffix.
      • These are host-owned chrome and illustrative sample text (PRODUCT_GOAL.md, Design target).
      • The recorded identity shows in the pane and the source anyway: Recorded test output · 29.97 s, Historical test output…, the Recorded: …:156 · 29.97 s label, and the Call Stack's Recorded test stop 2.
    6. The transport is in the bottom panel, under the editor area. That is host chrome.
      • Out of scope: the PNG's wording and its Jump back, settings and fullscreen controls (E9, C12).
      • Planned: the event buttons (O3) and the 5A button.
    7. There is no per-step "I understand this step". Out of scope (E8).
    8. Unrelated editor groups stand between the Application pane and the source. Allowed by O6.

    No difference outside these classes was found.

    Learning task (not gating).

    • Replay: rejects invalid invoice updates without writing or redirecting, opened at 12:14:56Z with Open replay.
    • Answer: the result was decided by if (!validatedFields.success) at app/lib/actions.ts:120. The recorded validatedFields.success is false, with validatedFields.error.issues.length 2 for invoice-123. The test then asserts the returned errors and Missing Fields. Failed to Update Invoice. (Stop 2, actions.test.ts:177).
    • Evidence: the summary's Step 1 text, Run and Debug's Variables and the recorded-source label.
    • Moves: 0 to reach the condition (the replay opens on Stop 1), then 1 Next event to see the result.
    • Time: about 20 s from the open to the answer, under the 2-minute target.
    • Confusion:
      • The diagram's marked step can stand outside its scrolled area after a move (the scroll position is kept by design).
      • The question's text is clamped, behind Show more.

    Found by N51, VS Code. Each is carried to the next cycle; none is critical:

    • N51-V1 (b): the previous stop's CodeLens stays for 2 to 3 frames during the pending state.
    • N51-V2 (e): when a test replay is retired, the summary is not withdrawn before the Live publish. retireNodeHistorySelection does not do what leavePlayback does for a browser replay, so the Learning summary draws the Live Study content for about 3 frames.
    • N51-V3 (e): shownReplayFamily() returns test for any summary composition without a recording. So for a frame, while either family's Return to Live leaves the composition, the bottom panel draws a test-replay transport with no history. This is new in this PR for a browser replay.
    • N51-V4: after a browser replay, the Application pane's tab title keeps codebook · Recorded application, in the Live composition and in a later test replay.
    • N51-V5 (live): a codebook_continue failed with RUNTIME_FAILED on an unavailable required fact (revalidatePath.mock.calls.length).
    • Observed: a browser replay's open and Return to Live each show 1 frame of the Study document in the summary before its own content. This is the browser path this PR did not change; it was not compared on main, so it is carried as N51-V6 for the bug-fix cycle to check.

    Cursor next (Agent, Grok 4.6 High, Fast allowed).

  14. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    N51 frozen request, addendum: Cursor (d) browser study

    The criterion (d) needs a browser replay. Cursor's storage holds none: its Saved studies list only test replays. So one browser study is recorded in Cursor before (d) is checked. The request was frozen before submission. Its causal links were read from nextjs-dashboard at 1936e41, read-only; the chat gets only the request.

    Chat: Cursor Agent, Grok 4.6 High. Same candidate and Space as the frozen comment above.

    /codebook トップページの「Log in」リンクを押してからログイン画面が表示されるまでに、どのコンポーネントが描画され、ログイン後の戻り先がフォームのどの値として決まるのかを、実際に画面を操作して止めた時点の値を見ながら解説して

    Causal links (for checking the explanation; not given to the chat):

    1. app/page.tsx:24-29: the Link to /login.
    2. app/login/page.tsx: LoginPage renders AcmeLogo and LoginForm inside Suspense. The comment there says that useSearchParams requires the boundary.
    3. app/ui/login-form.tsx:18-21: callbackUrl = searchParams.get('callbackUrl') || '/dashboard'. With no callbackUrl in the URL, it is /dashboard.
    4. app/ui/login-form.tsx:67: the hidden input redirectTo carries callbackUrl.

    Boundary: that the form later sends redirectTo to authenticate is source reasoning. This flow never submits the form.

  15. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    N51 result, Cursor (task 10, AC8): PARTIAL

    Identities.

    • Candidate: same as VS Code. laststance.codebook@0.2.39 from the ac27cc1a VSIX, installed in Cursor at 04:34 local.
    • The Cursor window's extension host had run since 02:35 local, so it was still running 0.2.38. Developer: Reload Window at 12:25:14Z activated 0.2.39 (exthost log at 05:25:15 local). Every check below ran after that reload.
    • Space local:codebook-qa. Cursor 3.27.12, QA profile, window 1920 × 1050, default zoom, theme Cursor Light (the default).
    • Target: nextjs-dashboard at 1936e41, clean.
    • Chat: Cursor Agent, model Grok 4.6 High, Effort High, Fast off. No credits ran out.
      • A new Agent chat opens on Grok 4.7 High, and it switched back to 4.7 once when /codebook was typed. Each time I set Grok 4.6 High again before sending.

    Live run (not gating).

    • The frozen request was submitted at 12:26:38Z (SHA-256 dbda0f8f…a80b, equal to the frozen comment).
    • The AI stopped once: opengraph-image.png stood as a preview tab in a Study group, and the AI asked the learner to keep or close it. The learner kept it (double-click) and answered in the chat, as the AI asked.
    • The AI ran both authenticate tests through codebook_start and codebook_continue, with stops at actions.ts:35 and :39. Its answer:
      • CredentialsSignin returns the string 'CredentialsSignin' (line 36), and the form fields reach signIn.
      • An AuthError of type AccessDenied skips that return and is thrown again (line 39); Vitest sees the same rejection.
      • It stated its boundaries: instanceof was not inspected, and NEXT_REDIRECT is source reasoning only.
    • Saved complete with Save learning replay (12:36:2xZ). The chat was then closed.

    Takes. Recorded with OBS Window Capture of [Cursor] Captured-utils.ts — nextjs-dashboard (window 394), with the transform reset: 1920 × 1050 at 30 fps, no crop, silent audio (−91 dB). Each SHA-256 is identical in the Space and on the Mac. The files are private, under artifacts/cycle-0051/n51/cursor/.

    Take File SHA-256 Duration
    Preflight (VS Code in front for 10 s; Cursor's terminal ticks kept updating behind it) 2026-10-24 05-37-04.mp4 449ced8e…ea6e 28.9 s
    Take 1: (a), (b), (c), (e), (f) 2026-10-24 05-38-33.mp4 e85c44a5…2970 423.2 s
    Take 2: (d), browser Return to Live 2026-10-24 06-06-59.mp4 fa7c0d25…b8494 49.9 s

    The stills, captured with screencapture:

    Still SHA-256
    n51-cursor-a.png c6d98a2a…c6ff
    n51-cursor-c-before.png 2eeb4536…bcd5
    n51-cursor-c-after.png 68589be9…485a
    n51-cursor-f-light.png 72ebd393…7fab
    n51-cursor-f-dark.png 285f84b1…9cb0

    Criteria. Every native frame of each transition was inspected from the change-frame sheets.

    • (a) PASS. I opened the test replay "rethrows authentication errors that are not credential failures" (c1dc77fc) from Saved studies.

      • The Study pane closed.
      • The Application pane showed Recorded test output · 20.56 s above the recorded-source tab (actions.ts:35, Recorded: app/lib/actions.ts:35 · 20.56 s).
      • The Learning summary opened in the primary side bar (D31). After the published Move Learning Summary… → New Secondary Side Bar Entry step and ⇧⌘D, the layout was: Run and Debug on the left (error = AuthError, Call Stack Recorded test stop 1), the summary on the right beside the Agent chat's tab, and the transport with event buttons at the bottom.
      • No empty editor group.
    • (b) PARTIAL. Next and Previous stop, Next event three times (output 45.35 s, then the result; Next event is disabled at the result), Previous event, Replay from start (Output 0.16 s), a seek, ArrowRight, Home and Play each moved every surface to one moment. Two stale details showed during the pending state:

      • The previous stop's CodeLens label stays about 9 frames (300 ms) beside the pending target.
      • On a move to an output, the sticky-scroll header of the old source stays 2 frames.
    • (c) PASS. The moment was Stop 2 · 34.89 s, with the summary scrolled to the diagram. I hid it with View: Toggle Secondary Side Bar, then pressed the transport's Learning summary button.

      • Before and after: Run and Debug differs by AE 0 and the source by AE 0. The transport differs by AE 69 (the button's hover). The summary differs by AE 426: its title heading takes the focus ring, and a tooltip shows.
      • The moment, the scroll position and the diagram are the same.
    • (d) PASS for the composition.

      • Cursor held no browser replay, so a browser study was recorded first, with the frozen addendum request (comment 6384461032).
      • Its Open replay gave the browser family's own composition: codebook · Recorded application, Captured-source.mts, the browser summary (Overview, Live and Recording), and a transport without event buttons that reads Presented 0.00 s / 3.45 s.
      • The recording itself holds no application frame and no source. The AI's run was interrupted (see N51-C2), so task 2's frame content could not be compared.
    • (e) PARTIAL. Return to Current Pause from the test replay (take 1, about 296 s) and from the browser replay (take 2, about 38 s) end the same way:

      • the Live composition, with the Study pane closed;
      • the summary placeholder;
      • the same editor focus.

      In the transition, the same defects as VS Code (N51-V2, N51-V3) showed:

      • Test replay: 1 frame of Study content in the summary, with a history-less test-family transport (Test journal playback).
      • Browser replay: 2 frames of the test-family transport in the bottom panel.
    • (f) PASS. In Cursor Light and Cursor Dark, these are visible and distinguishable: the drawing's step mark (link color, bold, underline), the event buttons, and the keyboard focus ring on Next event (a double ring).

      • The theme was changed with Preferences: Color Theme. The user settings.json was restored byte for byte afterwards (SHA-256 3623747d…86c3 before and after).

    Region 2 comparison (n51-cursor-a.png against the PNG). The VS Code comment's differences 2 to 8 hold here as well. The differences specific to Cursor:

    • The summary is 440 px wide. It sits in its own secondary-side-bar tab beside the Agent chat's tab, after the Move View step. Allowed by D31 and O6.
    • The transport is in the bottom panel, and Run and Debug sits on the left. That is host chrome.

    No difference outside the allowed classes was found.

    Learning task (not gating).

    • Replay: rethrows authentication errors that are not credential failures, opened at 12:39:09Z from Saved studies.
    • Answer: the result is decided by if (error instanceof AuthError && error.type === 'CredentialsSignin') at app/lib/actions.ts:35. The recorded error.type is AccessDenied, so the return is skipped and throw error at :39 runs.
    • Evidence: the summary's Step 1 text, the Catch Block's error = AuthError in Run and Debug, and the recorded-source label.
    • Moves: 0 (the replay opens on Stop 1).
    • Time: about 37 s from the open to the answer, the Move View step included. That is under the 2-minute target.
    • Confusion: the summary first opens in Run and Debug's place, until the Move View step.

    Found by N51, Cursor. Carried to the next cycle; none is critical.

    • N51-V1, N51-V2 and N51-V3 reproduce in Cursor, so each holds in both hosts. In Cursor, V1 lasts longer (about 300 ms) and adds the sticky-scroll header.
    • N51-C2 (live, browser): the Cursor Agent's browser run of the top page's Log in link found no stop in the top page's chunk. It retried with other stops, and its recording sealed partial ("Runtime interrupted or cleanup incomplete; recorded prefix retained"), with no application frame and no source. The AI explained the path from source and said that the click and LoginForm's render were not observed.
    • Observed, host behavior: a new Cursor Agent chat defaults to Grok 4.7 High and can switch back to it while /codebook is typed.
    • Observed: the preview-tab refusal stopped the live run until the learner kept the tab. This is the designed refusal, but it cost the learner a step.
  16. ryota-murakami commented on Oct 24, 2026

    @ryota-murakami
    ContributorAuthor

    Closing: Cycle 0051 demonstrated, merged (v0.2.39.0)

    Outcome: demonstrated. A saved test replay now opens in the PNG's region-2 composition in VS Code and in Cursor:

    • the Study pane closes;
    • the recorded test output stands above the recorded-source tab;
    • Run and Debug shows the recorded stop;
    • the Learning summary takes the chat's place;
    • one transport serves both replay families.

    5A (the Learning summary button) keeps the moment, the debugger frame and the reading position.

    Carried defects. This feature cycle carries every one of them. The next cycle is a bug-fix cycle, and its Issue takes each item as a task: a fix with a test that fails without it, or recorded evidence.

    N51 (native).

    1. N51-V1: during a moment's pending state, the previous stop's CodeLens label stays beside the pending target. It lasts 2 to 3 frames in VS Code and about 9 frames in Cursor, where the old source's sticky-scroll header also stays 2 frames on a move to an output.
    2. N51-V2: retiring a test replay (retireNodeHistorySelection) does not withdraw the Learning summary before the Live publish. On Return to Live, the summary draws the Live Study content for 1 to 3 frames.
    3. N51-V3: shownReplayFamily() returns test for any summary composition without a recording. While either family's Return to Live leaves the composition, the bottom panel draws a test-replay transport with no history for 1 to 2 frames. This is new in this PR for a browser replay.
    4. N51-V4: after a browser replay, the Application pane's tab title keeps codebook · Recorded application in the Live composition and in a later test replay.
    5. N51-V5 (live): codebook_continue failed with RUNTIME_FAILED on an unavailable required fact (revalidatePath.mock.calls.length).
    6. N51-V6: a browser replay's open and Return to Live each show 1 frame of the Study document in the summary before its own content. Not compared on main; the bug-fix cycle checks it there first.
    7. N51-C2 (live, browser, Cursor): a browser run of the top page's Log in link found no stop in the page's chunk. The recording sealed partial ("Runtime interrupted or cleanup incomplete; recorded prefix retained"), with no application frame and no source. The click and the login form's render could not be observed.

    /ship reviews (feature cycle Skip).

    1. Fixed-time waits in three host tests (gstack-timing-ok).

    2. JSDoc blocks above the wrong functions after the refactor:

      • playTestReplayControl;
      • testReplayTitle;
      • focusSummaryStart and controlEverFocused;
      • the describeNodeTestReplay Show more comment.
    3. Test expectations that use implementation constants (SUMMARY_PLACEMENT_OFFER, STUDY_REMOVAL_REFUSALS.nodeHistory) instead of literal values.

    4. An unanswered one-replay-at-a-time notice holds the entry turn.

    5. Close and Return to Live do not invalidate a waiting entry. With two Open replay entries, closing the workspace lets the second one reopen it later.

    6. A stale-revision Saved studies open can leave an empty summary composition.

    7. Open replay with the summary and the bottom panel both hidden brings back no UI.

    8. A browser study chosen from a test replay's summary bypasses studyAwaitingEditorArea.

    9. showLearningSummary's identity changes during an open (STALE_PRESENTATION).

    10. Every move failure is worded as a debugger failure.

    11. forgetUnopenedComposition, and a Reload racing another open(), can leave or blank the summary.

    12. tagTestReplayDrawing binds the step marks by SVG sibling order.

    13. Show more's expanded state persists across replays.

    14. nodeHistoryRefusal is not sanitized at publish.

    15. Untested state cells:

      • browser replay × another study;
      • browser replay × failed open;
      • the browser Replay from start and Pause clicks.

      The tests are in the carried patch artifacts/cycle-0051/ship/step9-carried-tests.patch (private).

    16. Two stale comments named by the /ship review.

    17. A possible empty editor group in the composition (a fake-editor pin keeps one). N51 saw none in either host; the bug-fix cycle settles it by evidence or by a fix.

    Closed with evidence in this cycle:

    • an older entry's failed open reporting late (a superseded catch returns superseded);
    • the preview retry's revision (intended);
    • deleting the selected test replay, which is refused rather than retired (AC15, findings comment).

    Later candidates: listed under Owner decisions in the body (package-root Vitest and new run profiles, C1, C5, C8 to C12, E8, E9). None of them is a carried defect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cycleOne bounded experiment or product increment

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions