Skip to content

Preserve live reader position through tab return - #1419

Merged
trissim merged 5 commits into
mainfrom
fix/1418-reader-tab-return
Nov 2, 2026
Merged

trissim merged 5 commits into
mainfrom
fix/1418-reader-tab-return

Conversation

@trissim

@trissim trissim commented Nov 2, 2026 •

Copy link
Copy Markdown

Summary

Five commits, six files, +126/-12 on one reader-return issue. Current head c045ad6313170c3bee0c3f9c2400e6073b780d56 includes the source correction for the prior hosted gate's three findings and rebases onto current main. The first commit repairs the shared frame fixture and adds the row control; the second implements native-holder lifetime requirements through the existing resource budget; the third covers pending End's retained pager identities; the fourth removes redundant mounted-state validation and an unused base release declaration; the fifth supplies the already-admitted native Screen to the requirement query, resolving its typed Conversation from that screen rather than dereferencing an optional stored widget. No new cache, retention ledger or tab-specific scroll reset.

Tracks #1418. Combined affected UI execution passed9/9 on exact 502e078d878fee3cb0cf567b4f25552097c594c7. The fourth and fifth commits' deltas are detailed below; no new9-case run is claimed. Corrected-head source judgment, hosted green and installed physical acceptance remain open. These admitted controls do not retrospectively certify every original field observation.

Before / after

Before:

  • BlockPosition and ArrivalPosition retained native Widget/page identities.
  • ParkedPosition preserved those holders while a tab was hidden.
  • The native budget knew only the selected view/sidebar were required, so it could remove a tree still addressed by a parked reader.
  • RetainedSessionViewState then restored that old holder into a rebuilt view. Geometry cannot place a detached old widget.
  • Conversation/sidebar resources supplied the same undeclared cost/release contract; the sidebar separately repeated zero source/paint costs.

After:

  • NativeReaderHolder supplies the lifetime requirement once. BlockPosition(NativeReaderHolder, OffsetPosition) and ArrivalPosition(NativeReaderHolder, OffsetPosition) compose native identity with their existing offset behavior. LatestPosition(NativeReaderHolder, HeldReaderDestination, TailPosition) composes the same requirement with pending End: its sources retain actual pager identities whose advance cannot be observed through an evicted old tree.
  • UnreachedPosition carries the wrapped position's requirement; ParkedPosition inherits it. Source-addressed FragmentPosition, RowPosition and TailPosition retain the default empty requirement.
  • NativePresentation declares shared costs and the required-resource query with concrete empty-resource defaults. Both OperationalSessionPresentation and SessionThreadSidebar inherit it; duplicate sidebar zero declarations are deleted. Their actual release operations remain on the concrete lifetime owners; the shared budget value does not import MainScreen or declare an unused release no-op.
  • The mounted conversation derives its required resource from its actual reader. NativeSessionSurface includes those resources in the existing PresentationBudget.fit call. The normal cost accounting remains intact; there is no competing store or silent raw-offset fallback.

PresentationBudget already permits explicitly protected resources to exceed its nominal budget: source data is not discarded to satisfy a widget budget. A native holder is now correctly one of those protected requirements. Saved-key and tail positions remain evictable and reconstructable. A native-holder reader must release that requirement through the existing position lifecycle before its tree can be discarded.

Frame fixture

RecordedHistoryScreen previously iterated WorkspaceScreen.CSS_PATH directly. After1412 changed that declaration from a list to a string, the fixture tried to load its characters (screens/m). It now uses Textual's existing _css_path_type_as_list boundary normalization and resolves relative to the declaring WorkspaceScreen. Derived TopRowScreen receives the same corrected path set.

Authored behavior controls

The reader control uses the existing real wheel route to move inside a response below a thought. It opens another session and returns, retaining named publication observations. It compares the actual row only in frames where that window is shown: painting another tab is not a preservation failure.

The two admitted policy cases are the ordinary budget and real budget pressure (minimum_widgets=1, widgets_per_row=0). They invoke the existing reconciliation owner with actual widget costs, not a replacement eviction method or fabricated counts. Both require the native reader's original tree and its row to survive. Existing saved-tab eviction/editor-document/undo/draft restoration remains the counterexample to blanket retention.

Evidence, including failures

  • Original run61 failed before application startup because the fixture attempted screens/m. Its patch and private root remain retained.
  • Run62 after the fixture correction:1 passed,14.34s, rc0, host lease released. Its exact patch starts at a block boundary; it is not evidence for the revised interior/wheel or pressure cases.
  • Epoch67 caught a metaclass conflict when the new resource contract used ABC beside the native sidebar. This is retained as a failed import, not a green test. The shared resource now has concrete empty defaults rather than another metaclass.
  • Epoch68: cold imports/C3, actual OperationalSessionPresentation construction,3 native-holder cases,3 source-addressed controls and empty-resource behavior passed, rc0. Exact MROs, source patch and runtime04c174 are recorded. This is a finite source/interpreter proof, not UI or physical evidence.
  • Epoch72 extends the finite source proof to pending End and its parked wrapper:5 native-holder cases and3 source-addressed controls passed, rc0; actual LatestPosition C3 is retained. This still claims no application or physical behavior.
  • Commander ran the full requested combined selection on the exact502e archive:9 collected/9 passed in136.84s, process rc0. Complete log/result independently read: warm and budget-pressure interior return; retained blocks/draft; evicted saved-tab first published frame; initial prompt/draft/undo across eviction; and four sidebar restoration/retirement cases. Total218.88s includes lease acquisition. Artifacts: /home/ts/.cache/agent-scratch/pi-commander/reader-502e-selection-01/{pytest.log,result.json}. No duplicate holder pytest/NRA/full-suite run was launched; prepared63 remains unlaunched. This is headless affected-path execution, not installed physical proof.

Evidence: /home/ts/.cache/agent-scratch/pi-ui-performance/reader-return-{61,62}/ and reader-holders-{67,68,72}/. Earlier runs keep their original Core5f12/source-patch scope; later installations are not assigned retroactively.

Hosted source correction

The cf933 hosted NRA epoch failed with NoneAbsence +1 in session_presentation.py and StringIdentity +2 / TypeCheckingImport +1 in presentation_window.py. Those failed results remain retained. The correction deletes my second mounted-state assertion: MainScreen.retained_native_presentations already admits only non-None conversations, and NativeSessionSurface collects and queries the admitted owners synchronously before any eviction await. Both admitted classes implement evict; the empty base evict had no caller, so deleting it also deletes the circular MainScreen dependency. Python3.14's native deferred annotation resolves the unquoted NativePresentation return type; finite AST extraction/get_type_hints verified that exact declaration without importing the application. No reader retention or resource accounting was removed. Epoch87 publication/rebase/push completed rc0 with remote=HEAD; no local NRA or pytest rerun.

The d4d9 hosted epoch caught a new union-attr error after assertion removal: widget's declared Conversation | None type still permitted absence. That failed result is retained in reader-gate-90.log. The fifth commit changes required_presentations to receive the existing admitted Screen and resolves its actual typed Conversation through native query_one; both resource families share the same Screen contract/default. The budget passes the screen already paired with each resource. No optional-state cast, extra absence probe, cache, duplicate membership or circular MainScreen type dependency is added. The new affected risk is resolving the hidden mounted screen's own conversation under ordinary and pressured reconciliation; the two interior-return cases specifically exercise it. Existing9/9 remains evidence for502e, not a claimed rerun of this corrected head.

Remaining acceptance

  • Combined interior/wheel, saved-tab rebuild, initial-prompt and sidebar execution is complete at502e as recorded above; carry its scope through the unchanged-source rebase rather than rerunning it for reassurance.
  • Read the final hosted gate and exact-head source judgment.
  • Verify the installed real app's row/selection/End/tab-return/native-editor continuity, with actual frontend build identity and preserved original source/input evidence.

Assumed:1408's body is a report/sketch, not an executed certificate for this head. Existing old-window captures remain retained, not relabeled as installed1393 acceptance. No new stable source identity is fabricated for a live widget.

Copilot AI balanced review requested due to automatic review settings November 2, 2026 18:54
@trissim trissim linked an issue Nov 2, 2026 that may be closed by this pull request

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@trissim
trissim force-pushed the fix/1418-reader-tab-return branch from 72aeebb to b67ec21 Compare November 2, 2026 19:13
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

debt-src at c045ad6 passes.

@trissim
trissim force-pushed the fix/1418-reader-tab-return branch from 502e078 to cf933e5 Compare November 2, 2026 19:57
@trissim
trissim force-pushed the fix/1418-reader-tab-return branch from cf933e5 to d4d9e9a Compare November 2, 2026 21:11
@trissim
trissim merged commit e1ad68b into main Nov 2, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preserve the live reader position on tab return

2 participants