The operator, 2026-10-11 ~01:05Z, on the v1 draft of the re-take at dev 00b6f2aa6a (the first take whose close carries the sibling leaves' reveal and diagonal strokes): the drag-scroll inside the grid is far too slow, the grid's visible area in the room is tiny, he would have torn the matrix out and made the popup bigger (the film shows no window resize anywhere), and the drag-scroll should be fast and use the grid's own "throw" — on a fast release the grid keeps scrolling.
Design authority: the operator's design input (a peer design input, derived here: the hand-tempo rule sized the strokes like a walk, but a pan is a flick; the matrix at ≈ 300 px of width in the room can show neither its rows nor its canvas columns at scale; GridDragScroll's momentum is the grid's own feature and the film never shows it); the 2026-09-23 pacing rule (a real gesture at hand tempo, never a held frame — a flick is a hand gesture; momentum is the content moving, not a held frame); the approved A6 close (M08 the midpoint and the rest of the room breathing, M09 "The content never stopped living", E09 "And the work keeps going"), which a side-by-side ending fits unchanged — no spoken return is bound to the picture.
The Problem
The current film-signature scene (after the sibling leaves) brings the matrix and the feed in front, jumps the matrix to its midpoint, and pans it with three strokes of (−260, −120) at 36 samples × 33 ms — 1.2 s per stroke, ≈ 5 s in all — inside a pane ≈ 300 px wide. On film (take 2026-10-11T00-55-16-516Z, the #15252 re-take comment) the close reads as a slow crawl in a small box: the rows are legible only in the pane's strip, the sparkline column enters at ≈ 93 s after three strokes, and nothing demonstrates the two things a desktop user would do with that grid — tear it out into a window of its own and flick it.
The Architectural Reality
Tear-out and native return exist as film cues: apps/workstation/tour/fiveBeatFilm.mjsfilm-second-window uses {type: 'tear-out', itemId, sourceNodeId, options: filmPace} (NativeGestureDriver#executeTearOutStep, the vessel born under the pointer beyond the window's bottom-right, the pane's footprint); film-reintegration uses {type: 'native-return', ownerItemId, previewNodeId, options: {attempts, moveDelay, moveSteps}} (NativeGestureDriver#executeNativeReturnStep, which resolves the vessel's owner-granted route via Neo.manager.Window#resolveNativeRoute({capability: 'position', ownerWindowId, windowId}), reads the frame with Neo.Main.windowNativeGetGeometry, and moves it with Neo.Main.windowNativeMoveTo({...route, windowId: route.ownerWindowId, x, y}), a verified outcome per step).
Vessels are granted {close: true, position: true, resize: true} (src/dashboard/dock/Workspace.mjs:1127); Neo.Main#windowNativeResizeTo({nativeHandleKey, targetWindowId, windowId, width, height}) (src/Main.mjs:1244) resizes the OUTER frame through the same owner grant and verifies outerWidth/outerHeight reached the request (#resizeWindow, src/Main.mjs:974); the dock's NativeVesselTransaction uses the move for the park re-show, nothing uses the resize yet. The display's available area is readable through Neo.Main.getWindowData (screen.availLeft/Top/Width/Height, src/Main.mjs:343).
GridDragScroll (src/main/addon/GridDragScroll.mjs): the content follows the hand 1:1 during the drag; on release the velocity over the last 100 ms (px per 16 ms frame) decays with friction 0.95 until below 0.1 px/frame — a tail of ≈ 20 × v px, ≈ 2 s for a flick. GestureDriver#executeGridDragScrollStep already waits for that tail to settle and judges the travel against min(requested, room) (the #19580 Contract Ledger), so a throw's observed travel exceeds the request on the free axis and clamps at the room on the bounded one.
The witness test/playwright/e2e/workstation/WorkstationFilmTourNL.spec.mjs asserts ≥ 4 popups born and all closed at the end; the signature's final topology-assert pins split-main = ['scale-tabs', 'heavy-tabs'] with scale active — both hold when the matrix window comes home before the readout.
The Fix
Rewrite the film-signature steps after the two reveal ops (scale-tabs → scale, bottom-tabs → feed):
tear-out of scale from scale-tabs (existing cue): the matrix leaves the room, a window born under the hand, the same instance riding along.
New cue vessel-resize{type: 'vessel-resize', itemId: 'scale', frame: {anchor: 'right-of-main', gap, width, height}, options: {moveDelay, moveSteps}} → NativeGestureDriver#executeVesselResizeStep: resolves the vessel's owner route (capability resize, and position for the move), reads the frame, derives the target OUTER rect from the main window's frame (top-aligned, gap px right of its right edge; height defaults to the main frame's height; the display's available area from getWindowData clamps the target so a smaller display gets the biggest frame that fits, recorded in the proof), then walks position and size together from the birth frame to the target in moveSteps samples at moveDelay (windowNativeMoveTo + windowNativeResizeTo per sample, each a verified outcome; the film cursor is not involved — this is the window, not the hand). Receipt below. Listed in both cue vocabularies; TourController#executeCue routes it.
scroll to index 50000 (existing cue) — the midpoint jump, now in a window with room.
grid-drag-scroll as one throw: {paneId: 'scale', anchor: {x: 0.8, y: 0.85}, deltaX: -360, deltaY: -480, strokes: 1, options: {attempts: 300, curve: 'throw', moveDelay: 33, moveSteps: 24, showCursor: true}} — the samples share the travel eased in (quartic) at the film's 33 ms rhythm, so the stroke winds up and whips and the addon's momentum reads the last hundred milliseconds' speed; then the rows run on for ≈ 2 s; the x axis clamps at the matrix's right room (the sparkline and action columns in view), the y axis runs well past the hand. The pane cache entry's windowId follows the pane into the vessel, so the existing executor dispatches into the popup window.
native-return of scale home — measured out (2026-10-11 02:xxZ, headless at the branch head): a vessel holding one item torn out alone carries a tab-keyed detached record (dockGroupNodeId: null), so the dock's native return adopts nothing from it (the frame moved through the targets, no transfer row appeared); the stack-return of its grip never settles (an active gesture, the main refresh pending, 200 s); a window close is an undoable close, not a return (windowNativeClose succeeded, the home held nothing); an undo of the tear-out brings the matrix home but leaves the emptied window open (the #19583 class). The film ends side by side instead: the room breathing and the matrix streaming in its own window, which the approved A6 close fits unchanged. A road home for a lone vessel is the product's open gap (two defect-notes filed; Ada's headless witness hit the same stack-return stall under #19583); no manual grip return has been verified either way, so none is claimed.
The final topology-assert pins the stored home's survival (scale-tabs stays a tabs node — Security holds it) and the feed in front; the living close stays.
Captions name what each beat shows; the scene's beats list follows. targetSeconds stays a budget (10 s; the picture ≈ 12–14 s).
Contract Ledger
Cue{type: 'vessel-resize', itemId, frame, options?} — consumed by TourController#executeCue → NativeGestureDriver#executeVesselResizeStep({itemId, frame}, options); listed in WORKSTATION_CUE_TYPES and filmCueTypes.
itemId (String, required): an item currently committed in its own vessel (the tear-out's receipt), else applied: false by name.
frame (Object, required): {anchor: 'right-of-main', gap: Number px (default 24), width: Number px (required), height: Number px (default: the main window's outer height)} — the target OUTER frame, derived at run time from the main window's frame and contained within the display's available area (getWindowData) on all four edges — past the right edge it shifts left over the main window, past the left edge it shifts right, above the top it comes down, past the bottom it keeps its top and shrinks, wider than the area it shrinks to it; the origin may be negative and the main frame partly outside; the clamp recorded, an unknown display clamps nothing.
options.moveDelay (ms between samples, default 33), options.moveSteps (samples, default 16).
Receipt{applied, errors, proof}; proof = {before: {x, y, width, height}, target: {x, y, width, height, clamped: Boolean}, after: {x, y, width, height}, samples: Number, route: {windowId}}.
applied: true only when every sample's move and resize were verified by the main thread and the final frame is within 2 px of the target on every side.
Failures by name: no committed vessel for the item; no owner-granted route; a refused sample — the receipt's after is the frame as it stands, read back after the refusal (before stays the birth frame); when that readback itself fails, after is null and errors names the blind observation; a final frame off the target.
The throw reuses grid-drag-scroll's ledger (#19580) plus one option: options.curve ('linear' default | 'throw' = the samples share the travel eased in, quartic); per axis expected = min(requested, room), observed ≥ expected − slack; the witness pins the momentum (observed.y ≥ 2 × requested.y) because that is what the beat claims.
Decision Record impact: aligned-with ADR 0029 (native window operations through the owner grant; no placement-rule change — the grow is a scripted frame operation like the park re-show, not a drag).
Acceptance Criteria
vessel-resize is handled by TourController#executeCue, listed in both cue vocabularies, and the screenplay validates (fiveBeatFilm.spec); unit controls on NativeGestureDriver.spec: the frame walks to the derived target (move + resize per sample, verified), a display clamp is recorded and honoured, a refused sample fails by name with the frame as it stands, a missing vessel fails by name.
The headless film witness: the vessel-resize receipt applied with after within 2 px of target and after.width × after.height ≥ 4 × the frame it was born with; the throw's grid-drag-scroll receipt applied, strokes: 1, after.settled, travel.observed.y ≥ 2 × travel.requested.y (momentum), travel.met both axes; ≥ 5 popups born, every one but the matrix's closed; the final readout pins the stored home's survival and the feed in front. (Reconciled with the measured shape: no return home — see The Fix, 5.)
The scene's picture at the headless clock: tear-out + grow + jump + throw ≈ 11–12 s; no sample slower than hand tempo, no held frame (the pause floors stay concurrent with their cues).
Post-merge, deferred to #15252: the take's frames show the matrix window growing beside the room, the rows streaming after the flick with the sparkline column in frame, and the living close holding the room and the window together.
AC-1–AC-3 evidence: PR #19587 (AC Evidence table; GestureDriver.spec 67/67, fiveBeatFilm.spec 7/7, WorkstationFilmTourNL 3/3 headless, the close ≈ 11.5 s at the headless clock), approved by Emmy (review 5481660094 at 541781bebd), merged as dd870ec227 on 2026-10-11. AC-4 stays with #15252: the take at a head that also carries the fix for #19588 (the popup's Canvas-worker connection before the offscreen transfer).
Out of Scope
Any engine change to the dock, the vessel birth size (the pane's footprint stays the product contract), the drag-scroll addon or its friction.
The vessels of the journey scene and their choreography.
Narration: A6 stays whole; the edit layer re-binds the close only.
Avoided Traps
Growing the vessel at birth (a product change to the dock's footprint contract) instead of a scripted window operation after it.
Faking the throw by a scroll jump: the beat's claim is the grid's own momentum, measured by the receipt.
Bringing the matrix home by any cue that only looks right: the native return, the stack return, a close and an undo were each measured at the branch head and each failed by name (The Fix, 5); the witness's invariant became "every window but the matrix's closed" and the readout pins the stored home's survival, rather than asserting a return the dock does not perform.
Hard-coding the stage display's coordinates into the screenplay: the target frame derives from the main window and the display at run time.
Related
#15252 (the film epic; the take and the edit) · #19579 / #19580 (the sibling close leaves, merged as #19581 / #19582 at 00b6f2aa6a) · #19571 (take holds) · #19568 (hand tempo) · ADR 0029
Live latest-open sweep: the latest 20 open issues at 01:07Z, no equivalent (#19569 / #19583 concern re-born windows, not the close). A2A claim sweep (last 30, all read-states): no claim on the close. MC sweep ("film close drag-scroll slow, matrix tiny, tear out, bigger popup, throw"): only this lane's own turns. Own-assignment sweep: #15252 (parent), #19382 — none overlapping.
tobiu referenced in commit dd870ec - "feat(workstation): the film's close tears the matrix out, grows its window and throws the grid (#19584) (#19587) on Oct 11, 2026, 4:58 AM
Context
The operator, 2026-10-11 ~01:05Z, on the v1 draft of the re-take at dev
00b6f2aa6a(the first take whose close carries the sibling leaves' reveal and diagonal strokes): the drag-scroll inside the grid is far too slow, the grid's visible area in the room is tiny, he would have torn the matrix out and made the popup bigger (the film shows no window resize anywhere), and the drag-scroll should be fast and use the grid's own "throw" — on a fast release the grid keeps scrolling.Design authority: the operator's design input (a peer design input, derived here: the hand-tempo rule sized the strokes like a walk, but a pan is a flick; the matrix at ≈ 300 px of width in the room can show neither its rows nor its canvas columns at scale;
GridDragScroll's momentum is the grid's own feature and the film never shows it); the 2026-09-23 pacing rule (a real gesture at hand tempo, never a held frame — a flick is a hand gesture; momentum is the content moving, not a held frame); the approved A6 close (M08 the midpoint and the rest of the room breathing, M09 "The content never stopped living", E09 "And the work keeps going"), which a side-by-side ending fits unchanged — no spoken return is bound to the picture.The Problem
The current
film-signaturescene (after the sibling leaves) brings the matrix and the feed in front, jumps the matrix to its midpoint, and pans it with three strokes of (−260, −120) at 36 samples × 33 ms — 1.2 s per stroke, ≈ 5 s in all — inside a pane ≈ 300 px wide. On film (take2026-10-11T00-55-16-516Z, the #15252 re-take comment) the close reads as a slow crawl in a small box: the rows are legible only in the pane's strip, the sparkline column enters at ≈ 93 s after three strokes, and nothing demonstrates the two things a desktop user would do with that grid — tear it out into a window of its own and flick it.The Architectural Reality
apps/workstation/tour/fiveBeatFilm.mjsfilm-second-windowuses{type: 'tear-out', itemId, sourceNodeId, options: filmPace}(NativeGestureDriver#executeTearOutStep, the vessel born under the pointer beyond the window's bottom-right, the pane's footprint);film-reintegrationuses{type: 'native-return', ownerItemId, previewNodeId, options: {attempts, moveDelay, moveSteps}}(NativeGestureDriver#executeNativeReturnStep, which resolves the vessel's owner-granted route viaNeo.manager.Window#resolveNativeRoute({capability: 'position', ownerWindowId, windowId}), reads the frame withNeo.Main.windowNativeGetGeometry, and moves it withNeo.Main.windowNativeMoveTo({...route, windowId: route.ownerWindowId, x, y}), a verified outcome per step).{close: true, position: true, resize: true}(src/dashboard/dock/Workspace.mjs:1127);Neo.Main#windowNativeResizeTo({nativeHandleKey, targetWindowId, windowId, width, height})(src/Main.mjs:1244) resizes the OUTER frame through the same owner grant and verifiesouterWidth/outerHeightreached the request (#resizeWindow,src/Main.mjs:974); the dock'sNativeVesselTransactionuses the move for the park re-show, nothing uses the resize yet. The display's available area is readable throughNeo.Main.getWindowData(screen.availLeft/Top/Width/Height,src/Main.mjs:343).GridDragScroll(src/main/addon/GridDragScroll.mjs): the content follows the hand 1:1 during the drag; on release the velocity over the last 100 ms (px per 16 ms frame) decays with friction 0.95 until below 0.1 px/frame — a tail of ≈ 20 × v px, ≈ 2 s for a flick.GestureDriver#executeGridDragScrollStepalready waits for that tail to settle and judges the travel againstmin(requested, room)(the #19580 Contract Ledger), so a throw's observed travel exceeds the request on the free axis and clamps at the room on the bounded one.test/playwright/e2e/workstation/WorkstationFilmTourNL.spec.mjsasserts ≥ 4 popups born and all closed at the end; the signature's finaltopology-assertpinssplit-main=['scale-tabs', 'heavy-tabs']withscaleactive — both hold when the matrix window comes home before the readout.The Fix
Rewrite the
film-signaturesteps after the two reveal ops (scale-tabs → scale,bottom-tabs → feed):tear-outofscalefromscale-tabs(existing cue): the matrix leaves the room, a window born under the hand, the same instance riding along.vessel-resize{type: 'vessel-resize', itemId: 'scale', frame: {anchor: 'right-of-main', gap, width, height}, options: {moveDelay, moveSteps}}→NativeGestureDriver#executeVesselResizeStep: resolves the vessel's owner route (capabilityresize, andpositionfor the move), reads the frame, derives the target OUTER rect from the main window's frame (top-aligned,gappx right of its right edge;heightdefaults to the main frame's height; the display's available area fromgetWindowDataclamps the target so a smaller display gets the biggest frame that fits, recorded in the proof), then walks position and size together from the birth frame to the target inmoveStepssamples atmoveDelay(windowNativeMoveTo+windowNativeResizeToper sample, each a verified outcome; the film cursor is not involved — this is the window, not the hand). Receipt below. Listed in both cue vocabularies;TourController#executeCueroutes it.scrollto index 50000 (existing cue) — the midpoint jump, now in a window with room.grid-drag-scrollas one throw:{paneId: 'scale', anchor: {x: 0.8, y: 0.85}, deltaX: -360, deltaY: -480, strokes: 1, options: {attempts: 300, curve: 'throw', moveDelay: 33, moveSteps: 24, showCursor: true}}— the samples share the travel eased in (quartic) at the film's 33 ms rhythm, so the stroke winds up and whips and the addon's momentum reads the last hundred milliseconds' speed; then the rows run on for ≈ 2 s; the x axis clamps at the matrix's right room (the sparkline and action columns in view), the y axis runs well past the hand. The pane cache entry'swindowIdfollows the pane into the vessel, so the existing executor dispatches into the popup window.— measured out (2026-10-11 02:xxZ, headless at the branch head): a vessel holding one item torn out alone carries a tab-keyed detached record (native-returnofscalehomedockGroupNodeId: null), so the dock's native return adopts nothing from it (the frame moved through the targets, no transfer row appeared); thestack-returnof its grip never settles (an active gesture, the main refresh pending, 200 s); a window close is an undoable close, not a return (windowNativeClosesucceeded, the home held nothing); an undo of the tear-out brings the matrix home but leaves the emptied window open (the #19583 class). The film ends side by side instead: the room breathing and the matrix streaming in its own window, which the approved A6 close fits unchanged. A road home for a lone vessel is the product's open gap (two defect-notes filed; Ada's headless witness hit the same stack-return stall under #19583); no manual grip return has been verified either way, so none is claimed.topology-assertpins the stored home's survival (scale-tabsstays a tabs node — Security holds it) and the feed in front; the living close stays.Captions name what each beat shows; the scene's
beatslist follows.targetSecondsstays a budget (10 s; the picture ≈ 12–14 s).Contract Ledger
Cue
{type: 'vessel-resize', itemId, frame, options?}— consumed byTourController#executeCue→NativeGestureDriver#executeVesselResizeStep({itemId, frame}, options); listed inWORKSTATION_CUE_TYPESandfilmCueTypes.itemId(String, required): an item currently committed in its own vessel (the tear-out's receipt), elseapplied: falseby name.frame(Object, required):{anchor: 'right-of-main', gap: Number px (default 24), width: Number px (required), height: Number px (default: the main window's outer height)}— the target OUTER frame, derived at run time from the main window's frame and contained within the display's available area (getWindowData) on all four edges — past the right edge it shifts left over the main window, past the left edge it shifts right, above the top it comes down, past the bottom it keeps its top and shrinks, wider than the area it shrinks to it; the origin may be negative and the main frame partly outside; the clamp recorded, an unknown display clamps nothing.options.moveDelay(ms between samples, default 33),options.moveSteps(samples, default 16).Receipt
{applied, errors, proof};proof = {before: {x, y, width, height}, target: {x, y, width, height, clamped: Boolean}, after: {x, y, width, height}, samples: Number, route: {windowId}}.applied: trueonly when every sample's move and resize were verified by the main thread and the final frame is within 2 px of the target on every side.afteris the frame as it stands, read back after the refusal (beforestays the birth frame); when that readback itself fails,afterisnullanderrorsnames the blind observation; a final frame off the target.The throw reuses
grid-drag-scroll's ledger (#19580) plus one option:options.curve('linear'default |'throw'= the samples share the travel eased in, quartic); per axisexpected = min(requested, room),observed ≥ expected − slack; the witness pins the momentum (observed.y ≥ 2 × requested.y) because that is what the beat claims.Decision Record impact: aligned-with ADR 0029 (native window operations through the owner grant; no placement-rule change — the grow is a scripted frame operation like the park re-show, not a drag).
Acceptance Criteria
vessel-resizeis handled byTourController#executeCue, listed in both cue vocabularies, and the screenplay validates (fiveBeatFilm.spec); unit controls onNativeGestureDriver.spec: the frame walks to the derived target (move + resize per sample, verified), a display clamp is recorded and honoured, a refused sample fails by name with the frame as it stands, a missing vessel fails by name.vessel-resizereceiptappliedwithafterwithin 2 px oftargetandafter.width × after.height ≥ 4 ×the frame it was born with; the throw'sgrid-drag-scrollreceiptapplied,strokes: 1,after.settled,travel.observed.y ≥ 2 × travel.requested.y(momentum),travel.metboth axes; ≥ 5 popups born, every one but the matrix's closed; the final readout pins the stored home's survival and the feed in front. (Reconciled with the measured shape: no return home — see The Fix, 5.)AC-1–AC-3 evidence: PR #19587 (AC Evidence table;
GestureDriver.spec67/67,fiveBeatFilm.spec7/7,WorkstationFilmTourNL3/3 headless, the close ≈ 11.5 s at the headless clock), approved by Emmy (review 5481660094 at 541781bebd), merged as dd870ec227 on 2026-10-11. AC-4 stays with #15252: the take at a head that also carries the fix for #19588 (the popup's Canvas-worker connection before the offscreen transfer).Out of Scope
Avoided Traps
scrolljump: the beat's claim is the grid's own momentum, measured by the receipt.Related
#15252 (the film epic; the take and the edit) · #19579 / #19580 (the sibling close leaves, merged as #19581 / #19582 at
00b6f2aa6a) · #19571 (take holds) · #19568 (hand tempo) · ADR 0029Live latest-open sweep: the latest 20 open issues at 01:07Z, no equivalent (#19569 / #19583 concern re-born windows, not the close). A2A claim sweep (last 30, all read-states): no claim on the close. MC sweep ("film close drag-scroll slow, matrix tiny, tear out, bigger popup, throw"): only this lane's own turns. Own-assignment sweep: #15252 (parent), #19382 — none overlapping.
Origin Session ID: 9f6cd919-c61d-434d-a709-c700109af56b
Retrieval Hint: "film signature vessel-resize tear-out matrix throw grid momentum native return home"