Context
PR #17557 resolved #17554 by landing Neo.list.Buffered. Its first real product adoption is #17550: the Fleet activity history binds 500 producer-owned records into a fixed-height pooled list.
The live adoption exposed a post-merge engine defect before #17550 could encode its headed witness. On this branch at 2b281a7639 plus the #17550 working delta, the activity list's DOM viewport measured 139.10px with itemHeight: 52 (three visible rows), while App-Worker truth remained viewportHeight: 52, availableRows: 1, and a nine-row pool. Calling addResizeObserver(true) again did not change that state.
The Problem
Neo.list.Buffered never receives its initial real viewport size in the live app. Its pool stays sized from the one-row fail-visible fallback, so a taller seat under-mounts the intended viewport-plus-buffer range. A sufficiently tall pane can expose blank or late-rebound history during scroll even though Store truth is complete.
The registration payload explains the miss:
src/list/Buffered.mjs:156-160 calls the main-thread addon with {id, windowId}.
src/main/addon/ResizeObserver.mjs:361-376 records data.componentId as the App-Worker delivery target.
src/manager/DomEvent.mjs:121-132 is the working contract: {componentId: component.id, id: targetId, windowId}.
Without componentId, native size delivery has no component recipient.
The Architectural Reality
The bug belongs to Neo.list.Buffered, not its first consumer. The list owns viewportHeight, availableRows, pool cardinality, and its ResizeObserver lifecycle. #17550 must consume that contract; adding app-local DOM measurement or a second observer would duplicate the engine primitive the ticket explicitly waited for.
This is a narrow repair to an existing public engine method. No new module or directory choice is introduced.
The Fix
- Send
{componentId: id, id, windowId} from Buffered#addResizeObserver() on register and unregister.
- Strengthen the unit receipt from “addon called” to the exact routing envelope.
- Add a mounted consumer witness: a viewport spanning three fixed rows updates
availableRows to three and mounts viewport + both buffer sides over a 500-record Store.
- Re-run #17550's live activity seat and preserve its existing prepend-anchor and bounded-pool contracts.
Contract Ledger
| Target surface |
Source of authority |
Proposed behavior |
Fallback |
Docs |
Evidence |
Neo.list.Buffered#addResizeObserver(mounted) |
ResizeObserver#register + DomEvent#addResizeObserver |
register/unregister names both DOM target id and App recipient componentId |
invalid/missing DOM target keeps the addon's bounded retry behavior |
JSDoc clarifies routing identity |
exact-envelope unit + live mounted-size receipt |
availableRows / pool cardinality |
Buffered#onResize |
real viewport height drives ceil(height/itemHeight); pool stays bounded to viewport + 2 * bufferRowRange |
one-row fallback only before first real delivery |
existing class JSDoc remains authority |
500-record consumer witness |
Decision Record impact
None — restores the shipped fixed-height windowing contract.
Acceptance Criteria
Out of Scope
- A repo-wide rewrite of other ResizeObserver consumers.
- Variable-height list rows.
- Fixed-DOM-order recycling beyond the current no-insert/remove guarantee; #17563 owns that follow-up.
- Any app-local observer or manual DOM measurement workaround.
Avoided Traps
- Hard-code the activity pane height. Works at one dock split and breaks on resize/tear-out.
- Measure from the app. Creates a second geometry authority beside the engine list.
- Reopen #17554. It was resolved by PR #17557; this is a new post-merge defect and therefore a new successor.
Related
#17550 · #17554 · #17563 · PR #17557 · historical external-target routing repair #9316.
Live latest-open sweep: checked latest 20 open issues at 2026-08-22T21:50:45.051Z; no equivalent found.
A2A in-flight sweep: checked latest 30 all-state messages at 2026-08-22T21:50:45.051Z; no overlapping claim.
Origin Session ID: f47f948b-743b-4c11-84a8-fa60a567a148
Retrieval Hint: query_raw_memories("list.Buffered ResizeObserver componentId viewportHeight availableRows activity 500")
🪡 Emmy (GPT-5.6 Sol Ultra, Codex)
Context
PR #17557 resolved #17554 by landing
Neo.list.Buffered. Its first real product adoption is #17550: the Fleet activity history binds 500 producer-owned records into a fixed-height pooled list.The live adoption exposed a post-merge engine defect before #17550 could encode its headed witness. On this branch at
2b281a7639plus the #17550 working delta, the activity list's DOM viewport measured 139.10px withitemHeight: 52(three visible rows), while App-Worker truth remainedviewportHeight: 52,availableRows: 1, and a nine-row pool. CallingaddResizeObserver(true)again did not change that state.The Problem
Neo.list.Bufferednever receives its initial real viewport size in the live app. Its pool stays sized from the one-row fail-visible fallback, so a taller seat under-mounts the intended viewport-plus-buffer range. A sufficiently tall pane can expose blank or late-rebound history during scroll even though Store truth is complete.The registration payload explains the miss:
src/list/Buffered.mjs:156-160calls the main-thread addon with{id, windowId}.src/main/addon/ResizeObserver.mjs:361-376recordsdata.componentIdas the App-Worker delivery target.src/manager/DomEvent.mjs:121-132is the working contract:{componentId: component.id, id: targetId, windowId}.Without
componentId, native size delivery has no component recipient.The Architectural Reality
The bug belongs to
Neo.list.Buffered, not its first consumer. The list ownsviewportHeight,availableRows, pool cardinality, and its ResizeObserver lifecycle. #17550 must consume that contract; adding app-local DOM measurement or a second observer would duplicate the engine primitive the ticket explicitly waited for.This is a narrow repair to an existing public engine method. No new module or directory choice is introduced.
The Fix
{componentId: id, id, windowId}fromBuffered#addResizeObserver()on register and unregister.availableRowsto three and mounts viewport + both buffer sides over a 500-record Store.Contract Ledger
Neo.list.Buffered#addResizeObserver(mounted)ResizeObserver#register+DomEvent#addResizeObserveridand App recipientcomponentIdavailableRows/ pool cardinalityBuffered#onResizeceil(height/itemHeight); pool stays bounded to viewport +2 * bufferRowRangeDecision Record impact
None — restores the shipped fixed-height windowing contract.
Acceptance Criteria
componentId: list.id,id: list.id, and the exactwindowId.itemHeight: 52yieldsavailableRows: 3; a 500-record Store mounts exactly three visible rows plus the configured leading/trailing buffer, never 500 components.Out of Scope
Avoided Traps
Related
#17550 · #17554 · #17563 · PR #17557 · historical external-target routing repair
#9316.Live latest-open sweep: checked latest 20 open issues at 2026-08-22T21:50:45.051Z; no equivalent found. A2A in-flight sweep: checked latest 30 all-state messages at 2026-08-22T21:50:45.051Z; no overlapping claim.
Origin Session ID: f47f948b-743b-4c11-84a8-fa60a567a148
Retrieval Hint:
query_raw_memories("list.Buffered ResizeObserver componentId viewportHeight availableRows activity 500")🪡 Emmy (GPT-5.6 Sol Ultra, Codex)