From fcddb3c81c023555723d87358708e097572a1354 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 8 Oct 2026 09:29:30 -0400 Subject: [PATCH 1/4] Record delivered receipt admission, native title fix and cleanup --- .../dm-initial-publication-20261008/README.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/evidence/dm-initial-publication-20261008/README.md b/evidence/dm-initial-publication-20261008/README.md index 6b20db475..cf6915319 100644 --- a/evidence/dm-initial-publication-20261008/README.md +++ b/evidence/dm-initial-publication-20261008/README.md @@ -843,3 +843,40 @@ route and existing loaded windows: `.artifacts/dm-body-publication-delivery-20261008/live-publication.json`. Raw source/installed/build/burst/publication: `/home/ts/.cache/agent-scratch/dm-body-publication-20261008/`. + +## Supplied native titles and settled receipts — delivered + +Reviewed merged native123 preserves supplied Collapsible titles instead of +publishing its default Toggle first. Same-text Content span/metadata changes +reach the original child. Native constructor/subclass watchers, arbitrary +children and collapsed events retain their original contracts. The installed +original supplied-title control and actual notification disclosure control +passed. The native-supplied-title runtime was published for new launches. + +Toad576 now starts painted-read work only while the original history has tail, +channel or historical receipts. No flag/copy/queue/cache was added. Actual +pending acknowledgments retain their source/currentness/paint witnesses. +The existing private App partial-paint control passed against source and the +installed wheel: unseen bodies remain unread; scrolling acknowledges the rest; +50 settled visibility calls start no acknowledgment work; both style changes +retain original row/read identity. Production changes only mark_visible;705 +modules parse with0 omissions. Read acquisition/publication remains independent. + +New-launch frontend is published through its existing owner: +`.artifacts/settled-wire-receipts-delivery-20261008/live-publication.json`. +Raw checks/build/publication: +`/home/ts/.cache/agent-scratch/settled-wire-receipts-20261008/`. +Backend defaults/route/running owners remain unchanged. Existing windows retain +their loaded modules. Broad frame-time acceptance is still incomplete. + +The custom thread-time cProfile experiment returned impossible negative totals, +including after UI-thread restriction. Those timing results are rejected and +remain raw in native-supplied-title scratch; no speedup is inferred from them. +The recorder retains UI-thread gating and uses its original monotonic profiler +clock again; enclosing CPU spans remain separate measurements. + +Three superseded unused runtime directories were removed after a fresh225-process +census with no gaps/references and checking all default symlinks:173008144bytes. +Wheels/source/proofs/raw and current/immediate rollback/backend runtimes remain. +Original cleanup evidence is under disk-cleanup-owner-20261002: +`Parent-superseded-dm-runtimes-retired-20261008.json`. From 0969624f240d709e7b7e270046e18b9663b5ba1e Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 8 Oct 2026 09:39:57 -0400 Subject: [PATCH 2/4] Paint wire timestamps on their owning message rows --- src/toad/widgets/irc_message.py | 23 +++++++++++++++++++---- tests/divider_unread_paint_pilot.py | 10 +++++----- tests/message_dividers_pilot.py | 26 +++++++++++++------------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/toad/widgets/irc_message.py b/src/toad/widgets/irc_message.py index 5d4992a83..34b7849cf 100644 --- a/src/toad/widgets/irc_message.py +++ b/src/toad/widgets/irc_message.py @@ -16,7 +16,8 @@ from toad.widgets.inline_message import IRCMessageSource from toad.widgets.worker_static import WorkerStatic from contextlib import asynccontextmanager -from toad.widgets.message_divider import MessageDivider, MessageClock +from toad.widgets.message_divider import MessageClock +from textual.content import Content from toad.widgets.message_notifications import MessageNotifications @@ -93,6 +94,19 @@ class WireMarkdownMessage(CoreEventReceiver, ConversationBlock, VerticalGroup): CACHE_SUBTREE_GEOMETRY = True DEFAULT_CLASSES = "block" + DEFAULT_CSS = """ + WireMarkdownMessage { + margin-top: 1; + border-top: solid $foreground 60%; + border-title-align: center; + border-title-color: $text-muted; + border-title-style: bold; + } + WireMarkdownMessage:ansi { + border-top: solid ansi_bright_black; + border-title-color: ansi_bright_black; + } + """ BINDINGS = [ ("enter", "open_sender", "Open sender"), ("shift+enter", "open_destination", "Open destination"), @@ -108,9 +122,10 @@ def __init__(self, message: Message, *, direction: str = "Inbound"): f"History · {message.source.original_root} · @{message.sender} incarnation {message.sender_created_at}" if isinstance(message, HistoricalMessage) else direction ) + clock, self.tooltip = MessageClock.recorded(message.timestamp).display() + self.border_title = Content(f"{self.direction} · {clock}") def compose(self) -> ComposeResult: - yield MessageDivider(self.direction, clock=MessageClock.recorded(self.message.timestamp)) yield from self.compose_body() self.notifications = MessageNotifications() yield self.notifications @@ -162,7 +177,7 @@ class IRCMessage(WireMarkdownMessage, can_focus=True): DEFAULT_CLASSES = "" DEFAULT_CSS = """ IRCMessage { - width: 1fr; height: auto; margin: 0; padding: 0; + width: 1fr; height: auto; margin: 1 0 0 0; padding: 0; IRCMessageText { width: 1fr; height: auto; text-wrap: wrap; } } """ @@ -172,7 +187,7 @@ def compose_body(self) -> ComposeResult: yield self.body def read_ack_widget(self) -> Widget | None: - """Only the text block can authorize a read, never its divider.""" + """Only the text block can authorize a read, never its caption.""" body = self.body return body if body is not None and body.is_attached and body.paint_ready else None diff --git a/tests/divider_unread_paint_pilot.py b/tests/divider_unread_paint_pilot.py index 373c55c9a..cf5618a70 100644 --- a/tests/divider_unread_paint_pilot.py +++ b/tests/divider_unread_paint_pilot.py @@ -15,7 +15,7 @@ from runtime_fixture import ToadApp from toad.widgets.comms_chat import CommsChatView from toad.widgets.irc_message import IRCMessageText -from toad.widgets.message_divider import MessageDivider +from textual.geometry import Region async def main() -> None: @@ -45,22 +45,22 @@ async def main() -> None: while not (chat.message_history.reader is not None and not chat.message_history.reader.source.loading): await pilot.pause(.02) block = next(widget for message, widget in chat.message_history.rows if message.seq == last.seq) - divider = block.query_one(MessageDivider) body = block.query_one(IRCMessageText) await pilot.pause() + caption = Region(block.region.x, block.region.y, block.region.width, 1) viewport = chat.window.content_region chat.window.scroll_to( - y=chat.window.scroll_y + divider.region.bottom - viewport.bottom, + y=chat.window.scroll_y + caption.bottom - viewport.bottom, animate=False, immediate=True, ) await pilot.pause() - assert divider.region.overlaps(chat.window.content_region) + assert Region(block.region.x, block.region.y, block.region.width, 1).overlaps(chat.window.content_region) assert not body.region.overlaps(chat.window.content_region) assert last.seq not in {seq for source, seq in chat.message_history.painted_keys() if not source} page = await chat.message_history.reader.page(after=last.seq - 1, limit=chat.message_history.reader.source.page_limit) chat.message_history.channel_receipts[last.seq] = page - mark_visible(chat) + mark_visible(chat.message_history) await pilot.pause(.2) assert comms.views.viewer_snapshot(str(root)).channel_unread["#team"] == 1 assert app._exception is None diff --git a/tests/message_dividers_pilot.py b/tests/message_dividers_pilot.py index e738daf38..696bb685f 100644 --- a/tests/message_dividers_pilot.py +++ b/tests/message_dividers_pilot.py @@ -25,6 +25,8 @@ from toad.widgets.irc_message import IRCMessage, WireMarkdownMessage from toad.widgets.message_divider import MessageDivider from toad.widgets.tool_call import ToolCall +from toad.acp.status import ToolCallStatus +from acp import schema as protocol from toad.widgets.user_input import UserInput @@ -307,7 +309,7 @@ async def main() -> None: assert reply is not None incoming = await native.post(IncomingMessage(IncomingTranscript(sent.body, route=MessageRoute(sent.sender, (sent.target,)), source=sent.reference, timestamp=sent.timestamp))) thought = await native.post(AgentThought("not a displayed message")) - tool = await native.post(ToolCall({"toolCallId": "tool-one", "title": "Read source"})) + tool = await native.post(ToolCall(ToolCallStatus.from_acp(protocol.ToolCall.model_validate({"toolCallId": "tool-one", "title": "Read source"}, strict=True)))) await pilot.pause() assert len(user.query(MessageDivider)) == 1 assert "User" in user.query_one(MessageDivider).render().plain @@ -350,31 +352,29 @@ async def main() -> None: wire_block = next(widget for message, widget in chat.message_history.rows if message.seq == sent.seq) assert isinstance(wire_block, IRCMessage) - assert len(wire_block.query(MessageDivider)) == 1 - expected_time = time.strftime("%H:%M:%S", time.localtime(sent.timestamp)) - inbound_divider = wire_block.query_one(MessageDivider) + assert not wire_block.query(MessageDivider) + expected_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(sent.timestamp)) wire_block.scroll_visible(animate=False, immediate=True) await pilot.pause() - assert expected_time in inbound_divider.render().plain, ( - expected_time, inbound_divider.clock, inbound_divider.size.width, - inbound_divider.render().plain, - ) - assert "Inbound" in wire_block.query_one(MessageDivider).render().plain + assert expected_time in wire_block.border_title + assert "Inbound" in wire_block.border_title + rows = app.screen._compositor.render_strips() + assert expected_time in rows[wire_block.region.y].text outgoing_block = next(widget for message, widget in chat.message_history.rows if message.seq == outbound.seq) - assert "Outbound" in outgoing_block.query_one(MessageDivider).render().plain + assert "Outbound" in outgoing_block.border_title await chat.message_history.toggle_style() await pilot.pause() wire_block = next(widget for message, widget in chat.message_history.rows if message.seq == sent.seq) assert isinstance(wire_block, WireMarkdownMessage) - assert len(wire_block.query(MessageDivider)) == 1 + assert not wire_block.query(MessageDivider) assert len(wire_block.query(AgentResponse)) == 1 assert len(wire_block.query(AgentResponse).first().query(MessageDivider)) == 0 - assert expected_time in wire_block.query_one(MessageDivider).render().plain + assert expected_time in wire_block.border_title assert app._exception is None await asyncio.get_running_loop().shutdown_default_executor() - print("timestamped full-width user, inbound, agent and IRC/Markdown dividers; no thought divider") + print("timestamped native dividers and wire row borders; no nested wire or thought divider") if __name__ == "__main__": From 21f87a8019a11a979ed12330c499a4dfb68ed345 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 8 Oct 2026 09:43:50 -0400 Subject: [PATCH 3/4] Preserve full wire row spacing under application stylesheet --- src/toad/toad.tcss | 4 ++++ tests/message_dividers_pilot.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/toad/toad.tcss b/src/toad/toad.tcss index 00165b041..fb42054d6 100644 --- a/src/toad/toad.tcss +++ b/src/toad/toad.tcss @@ -2,6 +2,10 @@ margin: 0 1 1 0; } +WireMarkdownMessage.block { + margin: 1 1 1 0; +} + Markdown { layout: stream; diff --git a/tests/message_dividers_pilot.py b/tests/message_dividers_pilot.py index 696bb685f..ee5a33d29 100644 --- a/tests/message_dividers_pilot.py +++ b/tests/message_dividers_pilot.py @@ -369,6 +369,9 @@ async def main() -> None: if message.seq == sent.seq) assert isinstance(wire_block, WireMarkdownMessage) assert not wire_block.query(MessageDivider) + assert wire_block.styles.margin.top == 1 + assert wire_block.styles.margin.right == 1 + assert wire_block.styles.margin.bottom == 1 assert len(wire_block.query(AgentResponse)) == 1 assert len(wire_block.query(AgentResponse).first().query(MessageDivider)) == 0 assert expected_time in wire_block.border_title From 7a18b91fc94f6ff5c2eeceb43f736636573c2ea6 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 8 Oct 2026 09:45:31 -0400 Subject: [PATCH 4/4] Record message-owned caption checks and remaining pacing limit --- .../dm-initial-publication-20261008/README.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/evidence/dm-initial-publication-20261008/README.md b/evidence/dm-initial-publication-20261008/README.md index cf6915319..1bc41cb47 100644 --- a/evidence/dm-initial-publication-20261008/README.md +++ b/evidence/dm-initial-publication-20261008/README.md @@ -880,3 +880,30 @@ census with no gaps/references and checking all default symlinks:173008144bytes. Wheels/source/proofs/raw and current/immediate rollback/backend runtimes remain. Original cleanup evidence is under disk-cleanup-owner-20261002: `Parent-superseded-dm-runtimes-retired-20261008.json`. + +## Message-owned timestamp caption + +Compact and Markdown wire messages now paint their timestamp/direction on the +original row border, deleting one MessageDivider child per message. MessageClock +still owns dates; body paint alone owns read acknowledgment. Notification +disclosure, links, clipboard and historical identity remain distinct contracts. +Timestamp tooltip also appears over the row through native ancestor lookup. + +Actual private Apps passed compact/Markdown caption/direction, caption-only +unread protection, wrapping/routing, and reader preservation under body growth +and tail replacement. Final installed caption/spacing and reader checks passed. +705 Python modules parsed without omissions. Review caught application .block +margin precedence; the owning stylesheet preserves top/right/bottom spacing. +Initial CSS color refusal and stale ToolCall fixture input remain in raw logs. + +An older reader fixture acquired startup predecessor rows before source page +acceptance and waited on a retired body. The corrected acquisition waits the +existing source_checkpoint_available; no production exemption was added. + +One installed private native-driver burst delivered160 wheel packets/3 reversals +and20 incoming messages over48 rows in order, provider/public inputs zero. +Frame p95 remained92.8ms and maximum225ms: pacing remains unacceptable. +This removes48 widget lifetimes, not a broad performance pass. Raw checks and +negatives: /home/ts/.cache/agent-scratch/dm-native-caption-20261008/. +New-launch delivery uses the original reviewed frontend owner; existing user +windows are not restarted.