Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions evidence/dm-initial-publication-20261008/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -935,3 +935,26 @@ without gaps/references and checking default executable symlinks:282680401bytes.
Current, immediate rollback and backend runtimes remain; source, wheels, proof,
publication and raw results are retained. Cleanup original evidence:
disk-cleanup-owner-20261002/Parent-caption-superseded-runtimes-retired-20261008.json.

## Independent scroll intent and unchanged notification title

Native125,154f41637, preserves Widget's original scroll request when layout is
also pending. Both intents reach Screen, whose existing held/actionable-source
decision owns full versus visible reflow. Reviewed exact source; affected
native held/committed/released geometry control passed. No new flag or policy.

Toad578,d44f4868, compares its fresh derived notification title against the
original native title using Content.is_same before publishing. Detail-only
result/error changes still update expanded details and busy/error styling.
Changed summary/count/priority continue publishing. Explicit native mutable
title/span publication remains unchanged.705 modules parse without omissions.
Actual native disclosure and installed title layout/detail checks passed;
read-only source review found no semantic blocker.

Combined installed native-driver workload passed160 wheel packets/3 reversals
and20 incoming messages, all input ordered, no provider/public input. Frame
p95~98.7ms/max270.6ms remains unacceptable. Full reflow24calls/382.4CPUms,
worst39.9ms; visible53/170.1/worst6.71ms. No broad latency improvement claim.
Exact raw checks: title-scroll-installed.log, title-scroll-wheel.log and
title-scroll-wheel/ under existing dm-native-caption scratch. Published the
reviewed combined cohort for new launches; backend and existing windows remain.
8 changes: 4 additions & 4 deletions src/toad/widgets/viewport_body.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ def retire_native_body(self, current):
return BodyMeasurement.retire(current, self)
if self.lock.is_locked or self._body_viewport is None:
return BodyMeasurement.retire(current, self)
if self in self._body_viewport.protected():
if self._body_viewport.requires_body(self):
return BodyMeasurement.retire(current, self)
children = self.reconstructible_children()
if not children:
Expand Down Expand Up @@ -824,9 +824,10 @@ async def measured():
return measured()

def retirement_current(self, current):
"""Borrow current viewport demand again after asynchronous capture."""
return (self._body_measurement is current and self.is_attached and not self._closing
and self._body_viewport is not None
and self not in self._body_viewport.protected())
and not self._body_viewport.requires_body(self))

async def release_native_body(self, current):
if not self.body_ready or not self.retirement_current(current):
Expand All @@ -835,8 +836,7 @@ async def release_native_body(self, current):
if not children:
return False
async with self.retirement_custody() as can_commit:
if (not can_commit or not self.retirement_current(current)
or self._body_viewport.requires_body(self)):
if not can_commit or not self.retirement_current(current):
return False
self._update_body_measurement(MeasuredBody(current.width, current.rows, current.widgets))
self.retire_body_resources()
Expand Down
53 changes: 53 additions & 0 deletions tests/viewport_body_lifetime_pilot.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,57 @@ def observe(frame, event, argument):
print(json.dumps(receipt), flush=True)


async def retirement_visibility(output: Path):
"""A captured offscreen body keeps its native tree after real exposure."""
output.mkdir(parents=True, exist_ok=True)
with TemporaryDirectory(prefix="retirement-visible-", dir=output) as directory:
root = Path(directory)
os.environ.update(AGENT_COMMS_ROOT=str(root / "wire"),
XDG_CONFIG_HOME=str(root / "config"),
XDG_STATE_HOME=str(root / "state"),
XDG_DATA_HOME=str(root / "data"))
app = ToadApp(project_dir=str(root))
async with app.run_test(size=(100, 35)) as pilot:
await app.selected_session.wait_content_ready()
view = app.selected_session.conversation
window, manager = view.window, view.window.document_viewport
first = AgentResponse("Original body\n\nActual retained paragraph.")
await view.contents.mount(first)
async with asyncio.timeout(15):
while not first.body_ready or not first.prepared_paint_is_current(first.prepared_paint_sources()):
await pilot.pause(.02)
# Suspend original housekeeping so this check owns one retirement.
await manager.suspend_source()
second = AgentResponse("\n\n".join("Later original paragraph " * 8 for _ in range(30)))
await view.contents.mount(second)
window.scroll_end(animate=False, immediate=True)
await pilot.pause()
assert not manager.requires_body(first)
children = first.reconstructible_children()
assert children and first.prepared_paint_is_current(first.prepared_paint_sources())
operation = first.retire_body()
# Actual scrolling exposes the body after synchronous acquisition,
# before the returned operation measures/commits its captured rows.
window.release_anchor()
window.scroll_to_widget(first, animate=False, immediate=True, top=True)
await pilot.pause()
assert manager.requires_body(first)
assert await operation is False
assert first.reconstructible_children() == children and not first.body_dormant
assert all(child.is_attached for child in children)
assert first.body_ready
assert await first.retire_body() is False
window.scroll_end(animate=False, immediate=True)
await pilot.pause()
assert not manager.requires_body(first)
assert await first.retire_body() is True
assert first.body_dormant and not any(child.is_attached for child in children)
manager.resume_source()
assert app._exception is None
await asyncio.get_running_loop().shutdown_default_executor()
print("PASS: real exposure revokes captured retirement; native body retained; offscreen retirement still completes")


async def main():
with TemporaryDirectory(prefix="toad-viewport-body-", dir=os.environ.get("VIEWPORT_EVIDENCE")) as directory:
root = Path(directory)
Expand Down Expand Up @@ -328,6 +379,8 @@ async def switch_during_transaction():
if __name__ == "__main__":
if len(sys.argv) == 3 and sys.argv[1] == "--worker-custody-only":
asyncio.run(worker_custody(Path(sys.argv[2]).resolve()))
elif len(sys.argv) == 3 and sys.argv[1] == "--retirement-visibility-only":
asyncio.run(retirement_visibility(Path(sys.argv[2]).resolve()))
elif len(sys.argv) == 1:
asyncio.run(main())
else:
Expand Down
Loading