From d1c8ed73a05d37f06f0ff6b1aa3076b5664a56a7 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Sun, 12 Jul 2026 03:55:12 -0400 Subject: [PATCH] =?UTF-8?q?Titles=20speak=20one=20language:=20Sentence=20c?= =?UTF-8?q?ase,=20no=20emoji,=20=E2=80=94=20for=20subjects?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every screen and dialog title now follows the same three rules. Titles are sentence-cased ("Trace — YUL-Poly", "Dashboard — mesh overview", "Nodes"), never bare lowercase ("trace · x", "nodes", "command line · x", "path width", "admin login" and a dozen siblings). An em dash introduces a title's subject or qualifier while middle dots stay for chained status atoms ("Map · z12 · 34 nodes · 2 km across"), so the two separators mean different things instead of being used at random. And no title carries an emoji — the icon belongs to the menu row; a content-sized floating dialog whose title emoji the terminal draws a cell narrower than Rich measures leaves the border short (the bug the Send advert popup already documented), so the Watchtower, Courier, Time machine, identity-key, reboot, sync, restore, location, factory reset, and advert dialogs all drop theirs. Co-Authored-By: Claude Opus 4.8 --- meshterm/ui/atlas_screen.py | 2 +- meshterm/ui/config_editor.py | 20 ++++++++++---------- meshterm/ui/courier_screen.py | 16 ++++++++-------- meshterm/ui/dashboard_screen.py | 2 +- meshterm/ui/map_screen.py | 2 +- meshterm/ui/nodes_screen.py | 2 +- meshterm/ui/path_composer.py | 2 +- meshterm/ui/remote_cli.py | 2 +- meshterm/ui/repeater_admin.py | 18 +++++++++--------- meshterm/ui/timemachine_screen.py | 6 +++--- meshterm/ui/trace_screen.py | 30 ++++++++++++++++-------------- meshterm/ui/tx_screen.py | 12 ++++++------ meshterm/ui/watchtower_screen.py | 6 +++--- tests/test_atlas.py | 2 +- tests/test_config_editor.py | 2 +- tests/test_topology.py | 2 +- 16 files changed, 64 insertions(+), 62 deletions(-) diff --git a/meshterm/ui/atlas_screen.py b/meshterm/ui/atlas_screen.py index 6973e36..e02c58a 100644 --- a/meshterm/ui/atlas_screen.py +++ b/meshterm/ui/atlas_screen.py @@ -384,7 +384,7 @@ class AtlasScreen(Screen): def _compose_title(self, links: list[Link], matches: list[str]) -> str: """The status title: counts, the zoom level, and the find tally when active.""" nodes = len(self._layout_nodes(links)) - title = f"Mesh Atlas · {nodes} nodes · {len(links)} links" + title = f"Mesh atlas · {nodes} nodes · {len(links)} links" if self._zoom > _ZOOM_MIN: title += f" · {self._zoom:.1f}×" if self._filter: diff --git a/meshterm/ui/config_editor.py b/meshterm/ui/config_editor.py index 0daadbf..b0d6caa 100644 --- a/meshterm/ui/config_editor.py +++ b/meshterm/ui/config_editor.py @@ -490,7 +490,7 @@ async def _stage_advert_cadence( else: prompt = "How often this node announces itself to neighbours in range:" selected = await ctx.ui.select( - "📡 Flood advert" if flood else "📡 Direct advert", + "Flood advert" if flood else "Direct advert", items, prompt=prompt, default=current, @@ -515,7 +515,7 @@ async def _stage_location( choice = await ctx.ui.dialog( f"Advertised location: {_format_coords(lat, lon)}", [("Pick on map", "map"), ("Type coordinates", "type"), ("Clear", "clear")], - title="📍 Location", + title="Location", ) if choice is None: return @@ -834,7 +834,7 @@ async def _reboot(ctx: "AppContext", device: "Device", snapshot: dict) -> bool: choice = await ctx.ui.dialog( "Reboot the device now?", [("Cancel", None), ("Reboot", "reboot")], - title="🔄 Reboot device", + title="Reboot device", default=1, danger=True, ) @@ -895,7 +895,7 @@ async def _sync_clock(ctx: "AppContext", device: "Device", snapshot: dict) -> No choice = await ctx.ui.dialog( prompt, [("Cancel", None), ("Sync", "sync")], - title="🕒 Sync clock", + title="Sync clock", default=1, ) if choice == "sync": @@ -948,7 +948,7 @@ async def _restore_now(ctx: "AppContext", device: "Device", snapshot: dict) -> b choice = await ctx.ui.dialog( "Apply the backup now, or preview the changes first?", [("Cancel", None), ("Preview", "preview"), ("Apply", "apply")], - title="📂 Restore from backup", + title="Restore from backup", default=1, ) if choice == "preview": @@ -956,7 +956,7 @@ async def _restore_now(ctx: "AppContext", device: "Device", snapshot: dict) -> b choice = await ctx.ui.dialog( "Apply these changes to the device?", [("Cancel", None), ("Apply", "apply")], - title="📂 Restore from backup", + title="Restore from backup", default=1, ) if choice != "apply": @@ -973,7 +973,7 @@ async def _identity_key_menu(ctx: "AppContext", device: "Device", snapshot: dict its snapshot. """ choice = await ctx.ui.select( - "🔐 Identity key", + "Identity key", [ *menu_rows( [ @@ -994,7 +994,7 @@ async def _identity_key_menu(ctx: "AppContext", device: "Device", snapshot: dict "The private key IS the node's identity — anyone who sees it can impersonate " "this node. Show it on screen?", [("Cancel", None), ("Show key", "show")], - title="🔐 Show private key", + title="Show private key", default=1, danger=True, ) @@ -1024,7 +1024,7 @@ async def _identity_key_menu(ctx: "AppContext", device: "Device", snapshot: dict "Importing a key permanently overwrites this device's identity. Contacts and " "messages keyed to the old identity will no longer match it.", "IMPORT", - title="🔐 Import private key", + title="Import private key", ) if not confirmed: return False @@ -1043,7 +1043,7 @@ async def _factory_reset(ctx: "AppContext", device: "Device", snapshot: dict) -> "This erases EVERYTHING on the device — identity, contacts, channels, and every " "setting — and cannot be undone.", "RESET", - title="⚠ Factory reset", + title="Factory reset", ) if not confirmed: return False diff --git a/meshterm/ui/courier_screen.py b/meshterm/ui/courier_screen.py index ff625a9..a0af3d0 100644 --- a/meshterm/ui/courier_screen.py +++ b/meshterm/ui/courier_screen.py @@ -117,7 +117,7 @@ async def open_courier(ctx: "AppContext") -> Optional[dict[str, Any]]: while True: items = _menu_items(ctx, store.entries()) menu = SelectScreen( - "📨 Courier — store-and-forward outbox", + "Courier — store-and-forward outbox", items, default=cursor, wrap=False, @@ -225,7 +225,7 @@ async def _queue_flow(ctx: "AppContext", contacts: list[Contact]) -> None: "No contacts available — connect a device that knows some nodes first.", style="muted", ), - title="queue a message", + title="Queue a message", ) return @@ -246,7 +246,7 @@ async def _queue_flow(ctx: "AppContext", contacts: list[Contact]) -> None: row.append(f" heard {_format_age(secs)}", style="muted") items.append(Choice(row, contact)) contact = await session.select( - "✉ Courier — recipient", + "Courier — recipient", items, prompt="The message waits in the outbox until this node can take it:", ) @@ -265,7 +265,7 @@ async def _queue_flow(ctx: "AppContext", contacts: list[Contact]) -> None: if key is None: await session.message_dialog( Text(f"{contact.name!r} has no usable key to address.", style="err"), - title="queue a message", + title="Queue a message", ) return ctx.courier_store.queue(key, contact.name, text, not_before=not_before) @@ -325,14 +325,14 @@ async def _entry_actions(ctx: "AppContext", ident: int) -> None: f"{'s' if message.attempts != 1 else ''}", style="muted", ) - await session.message_dialog(body, title=f"📨 {message.node_name}") + await session.message_dialog(body, title=message.node_name) return items = [ Choice("📤 Send now — one forced attempt", "send"), Choice(Text.assemble(("✗ ", "err"), "Cancel this message"), "cancel"), ] picked = await session.select( - f"📨 {message.node_name} — “{_shorten(message.text, 28)}”", + f"{message.node_name} — “{_shorten(message.text, 28)}”", items, filterable=False, footer_hint="↑↓ move · Enter select · Esc back", ) @@ -344,7 +344,7 @@ async def _entry_actions(ctx: "AppContext", ident: int) -> None: outcome = await ctx.courier.attempt_now(ident) except Exception as exc: # noqa: BLE001 - surface the failure, keep the queue await session.message_dialog( - Text(f"send failed: {exc}", style="err"), title="courier" + Text(f"send failed: {exc}", style="err"), title="Courier" ) return notes = { @@ -362,5 +362,5 @@ async def _entry_actions(ctx: "AppContext", ident: int) -> None: "gone": Text("this entry is no longer queued", style="muted"), } await session.message_dialog( - notes.get(outcome, Text(outcome)), title="courier" + notes.get(outcome, Text(outcome)), title="Courier" ) diff --git a/meshterm/ui/dashboard_screen.py b/meshterm/ui/dashboard_screen.py index 751f6ca..032bd5e 100644 --- a/meshterm/ui/dashboard_screen.py +++ b/meshterm/ui/dashboard_screen.py @@ -155,7 +155,7 @@ class DashboardScreen(Screen): so it can attempt to decrypt an overheard channel-text packet. """ super().__init__() - self.title = "dashboard · mesh overview" + self.title = "Dashboard — mesh overview" self._session = session self._resolve = resolve self._activity = activity diff --git a/meshterm/ui/map_screen.py b/meshterm/ui/map_screen.py index b6a2046..7cb098b 100644 --- a/meshterm/ui/map_screen.py +++ b/meshterm/ui/map_screen.py @@ -415,7 +415,7 @@ class LocationPickScreen(MapScreen): """A live status title: the coordinates under the crosshair and the scale.""" base = super()._title(vp) scale = base.rsplit("·", 1)[-1].strip() - return f"set location · {vp.center_lat:.5f}, {vp.center_lon:.5f} · z{vp.zoom} · {scale}" + return f"Set location · {vp.center_lat:.5f}, {vp.center_lon:.5f} · z{vp.zoom} · {scale}" def handle(self, action: str, data: str = "") -> None: """Commit the centre on Enter; ``Home`` returns to the initial spot; else map keys.""" diff --git a/meshterm/ui/nodes_screen.py b/meshterm/ui/nodes_screen.py index c40e0b5..2d5abe0 100644 --- a/meshterm/ui/nodes_screen.py +++ b/meshterm/ui/nodes_screen.py @@ -49,7 +49,7 @@ class NodesScreen(Screen): sort: The initial sort; mutated in place as the user presses the arrows. """ super().__init__() - self.title = "nodes" + self.title = "Nodes" self._self_name = self_name self._self_key = self_key self._contacts = contacts diff --git a/meshterm/ui/path_composer.py b/meshterm/ui/path_composer.py index 9a6b317..cbbeace 100644 --- a/meshterm/ui/path_composer.py +++ b/meshterm/ui/path_composer.py @@ -137,7 +137,7 @@ class PathComposerScreen(Screen): them, the *fetch neighbours* row appears. """ super().__init__() - self.title = f"compose path · {target_label}" if target_label else "compose path" + self.title = f"Compose path — {target_label}" if target_label else "Compose path" self._target_id = target_id self._target_hash = (target_hash or "").lower().removeprefix("0x") self._target_label = target_label diff --git a/meshterm/ui/remote_cli.py b/meshterm/ui/remote_cli.py index 99163d6..9f0ce29 100644 --- a/meshterm/ui/remote_cli.py +++ b/meshterm/ui/remote_cli.py @@ -61,7 +61,7 @@ class RemoteCliScreen(Screen): session: The running TUI session (for repaints). """ super().__init__() - self.title = f"command line · {node_label}" + self.title = f"Command line — {node_label}" self._node_label = node_label self._send = send self._session = session diff --git a/meshterm/ui/repeater_admin.py b/meshterm/ui/repeater_admin.py index 43d847d..1ba5481 100644 --- a/meshterm/ui/repeater_admin.py +++ b/meshterm/ui/repeater_admin.py @@ -126,7 +126,7 @@ async def _login(ctx: "AppContext", device: "Device", node: Contact) -> bool: + "try again to enter a new one.", style="err", ), - title="admin login", + title="Admin login", ) return False ctx.admin_store.remember(node, password) @@ -175,14 +175,14 @@ async def _admin_session( elif choice == _ADVERT: await _simple_action( ctx, device, node, "advert", - title="📡 Send advert", + title="Send advert", prompt=f"Ask {node.name} to announce itself (flood) now?", commit="Send", ) elif choice == _CLOCK: await _simple_action( ctx, device, node, "clock sync", - title="🕒 Sync clock", + title="Sync clock", prompt=f"Set {node.name}'s clock from this companion's time?", commit="Sync", ) @@ -191,7 +191,7 @@ async def _admin_session( elif choice == _REBOOT: await _simple_action( ctx, device, node, "reboot", - title="🔄 Reboot node", + title="Reboot node", prompt=f"Reboot {node.name} now? It drops off the mesh while booting.", commit="Reboot", danger=True, @@ -375,7 +375,7 @@ async def _apply( if i < total: await asyncio.sleep(ctx.settings.trace_cooldown_s) - aborted = await _run_under_dialog(ctx, f"applying · {node.name}", work) + aborted = await _run_under_dialog(ctx, f"Applying — {node.name}", work) ctx.repo.finish_run( run_id, "error" if aborted else "ok", {"applied": applied, "staged_left": len(pending)}, @@ -387,7 +387,7 @@ async def _apply( summary.append(" (aborted — the rest stay staged)", style="warn") await ctx.ui.session.message_dialog( Text("\n").join([summary, Text(), *outcomes]) if outcomes else summary, - title=f"apply · {node.name}", + title=f"Apply — {node.name}", ) return applied @@ -420,7 +420,7 @@ async def _read_all(ctx: "AppContext", device: "Device", node: Contact) -> None: if i < len(specs): await asyncio.sleep(ctx.settings.trace_cooldown_s) - aborted = await _run_under_dialog(ctx, f"reading · {node.name}", work) + aborted = await _run_under_dialog(ctx, f"Reading — {node.name}", work) ctx.repo.finish_run( run_id, "error" if aborted else "ok", {"read": read, "asked": len(specs)} ) @@ -517,7 +517,7 @@ async def _change_password(ctx: "AppContext", device: "Device", node: Contact) - confirmed = await ctx.ui.dialog( f"Change {node.name}'s admin password now? You will need the new one everywhere.", [("Cancel", None), ("Change", "go")], - title="🔐 Admin password", + title="Admin password", default=1, danger=True, ) @@ -538,7 +538,7 @@ async def _change_password(ctx: "AppContext", device: "Device", node: Contact) - ) else: body = Text(reply.strip(), style="err") - await ctx.ui.session.message_dialog(body, title="admin password") + await ctx.ui.session.message_dialog(body, title="Admin password") # --- the command line --------------------------------------------------------------- diff --git a/meshterm/ui/timemachine_screen.py b/meshterm/ui/timemachine_screen.py index 90d3baf..2b93e86 100644 --- a/meshterm/ui/timemachine_screen.py +++ b/meshterm/ui/timemachine_screen.py @@ -165,7 +165,7 @@ class TimeMachineScreen(Screen): def _set_title(self) -> None: name, _delta = _WINDOWS[self._window_index] - self.title = f"⏳ {self._label} · {name}" + self.title = f"{self._label} · {name}" def handle(self, action: str, data: str = "") -> None: """Scroll, cycle the window, or dismiss.""" @@ -742,7 +742,7 @@ async def open_timemachine(ctx: "AppContext") -> None: "MeshTerm listens. Come back after the mesh has talked a while.", style="muted", ), - title="⏳ Time machine", + title="Time machine", ) return # Stored names first, the contact resolver filling the blanks (the app-wide @@ -770,7 +770,7 @@ async def open_timemachine(ctx: "AppContext") -> None: ) ) picked = await session.select( - "⏳ Time machine — pick a subject", + "Time machine — pick a subject", items, prompt="Everything the recorder ever heard, explorable:", ) diff --git a/meshterm/ui/trace_screen.py b/meshterm/ui/trace_screen.py index 5ab1e26..0e8b151 100644 --- a/meshterm/ui/trace_screen.py +++ b/meshterm/ui/trace_screen.py @@ -148,7 +148,7 @@ class TracingDialog(Screen): """Build the dialog. Args: - title: Heading for the dialog border (e.g. ``tracing · YUL-Poly``). + title: Heading for the dialog border (e.g. ``Tracing — YUL-Poly``). spinner: The spinner to animate (shared with the owner's ticker). on_abort: Invoked when the user asks to abort (idempotent expected). """ @@ -289,7 +289,7 @@ class TraceScreen(Screen): the screen never claims a route the radio wasn't given. """ super().__init__() - self.title = f"trace · {target}" if mode == "target" else "trace path" + self.title = f"Trace — {target}" if mode == "target" else "Trace path" self._target = target self._mode = mode self._flight_label = target if mode == "target" else "path" @@ -364,7 +364,7 @@ class TraceScreen(Screen): """ total = max(1, int(self._sample_count())) dialog = TracingDialog( - f"tracing · {self._flight_label}", spinner=self._spinner, on_abort=self.cancel + f"Tracing — {self._flight_label}", spinner=self._spinner, on_abort=self.cancel ) self._flight = dialog self._session.push(dialog) @@ -1047,7 +1047,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: f"{target!r} isn't a known contact or a hex key prefix, so a forced " "path can't end at it. Trace it device-routed, or pick a contact.", ), - title="no destination hash", + title="No destination hash", ) async def fetch_neighbours_via(repeater: Contact, repeater_id: str) -> bool: @@ -1083,7 +1083,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: ) spinner = Spinner() dialog = TracingDialog( - f"neighbours · {repeater.name}", spinner=spinner, on_abort=lambda: None + f"Fetch neighbours — {repeater.name}", spinner=spinner, on_abort=lambda: None ) dialog.show_last = False # a fetch has no streaming replies to echo dialog.status = f"logging in to {repeater.name}…" @@ -1138,7 +1138,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: run_id, "error", {"error": str(error) or type(error).__name__} ) await session.message_dialog( - Text(str(error), style="err"), title="fetch neighbours" + Text(str(error), style="err"), title="Fetch neighbours" ) return False ctx.repo.record_neighbours(run_id, repeater_id, entries) @@ -1154,7 +1154,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: "it relearns neighbours from received adverts, so ask again later.", style="muted", ), - title="fetch neighbours", + title="Fetch neighbours", ) return False return True @@ -1251,7 +1251,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: items.append(Choice(title=title, value=w)) picked = await session.run_screen( SelectScreen( - "path width", + "Path width", items, prompt="Forced hops are addressed by this many leading key bytes.", default=width_bytes, @@ -1288,7 +1288,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: items.append(Choice(title=title, value=n)) picked = await session.run_screen( SelectScreen( - "sample count", + "Sample count", items, prompt=f"One Trace action runs this many traces, {pace:g} s apart.", default=sample_count, @@ -1367,7 +1367,9 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: ctx.profile_name, ) spinner = Spinner() - dialog = TracingDialog(f"probing · {target_label}", spinner=spinner, on_abort=lambda: None) + dialog = TracingDialog( + f"Probing — {target_label}", spinner=spinner, on_abort=lambda: None + ) dialog.status = f"path 1/{len(candidates)} · one trace each" def on_result(index: int, done: int, result: TraceResult) -> None: @@ -1431,7 +1433,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: run_id, "error", {"error": str(error) or type(error).__name__} ) await session.message_dialog( - Text(f"probe failed: {error}", style="err"), title="path probe" + Text(f"probe failed: {error}", style="err"), title="Path probe" ) return None best = outcomes[0] if outcomes else None @@ -1460,7 +1462,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: await session.message_dialog( Text("no observed evidence involving this target yet — run a trace or " "let monitoring accumulate paths first.", style="muted"), - title="explore paths", + title="Explore paths", ) return None @@ -1481,7 +1483,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: items.extend(back_rows(("back", None))) picked = await session.run_screen( SelectScreen( - f"reach {target_label} · scenarios", + f"Explore paths — {target_label}", items, prompt="Choose the outbound leg — the return mirrors it.", footer_hint="↑↓ move · Enter adopt/probe · Esc back", @@ -1512,7 +1514,7 @@ async def _open_session(ctx: "AppContext", target: Optional[str]) -> int: result_items.append(Choice(title="Keep current path", value=None)) # the exit: no adoption adopted = await session.run_screen( SelectScreen( - f"probe results · {target_label}", + f"Probe results — {target_label}", result_items, footer_hint="↑↓ move · Enter adopt path · Esc keep current", wrap=False, diff --git a/meshterm/ui/tx_screen.py b/meshterm/ui/tx_screen.py index 55e38f1..0b4ac84 100644 --- a/meshterm/ui/tx_screen.py +++ b/meshterm/ui/tx_screen.py @@ -126,7 +126,7 @@ class TxSweepScreen(Screen): pick_samples: Floats the per-level sample-count dialog. """ super().__init__() - self.title = f"tx optimize · {admin_label} → {target_label}" + self.title = f"TX optimize — {admin_label} → {target_label}" self._admin_label = admin_label self._target_label = target_label self._device_label = device_label @@ -671,7 +671,7 @@ async def open_tx_optimize( ] picked = await session.run_screen( SelectScreen( - "sweep range", + "Sweep range", items, prompt="The TX window the sweep explores:", default=(screen.tx_min, screen.tx_max), @@ -710,7 +710,7 @@ async def open_tx_optimize( ] picked = await session.run_screen( SelectScreen( - "coarse step", + "Coarse step", items, prompt="The coarse sweep measures the window at this spacing, then refines.", default=screen.step, @@ -735,7 +735,7 @@ async def open_tx_optimize( ] picked = await session.run_screen( SelectScreen( - "samples per level", + "Samples per level", items, prompt=f"Each TX level is measured with this many traces, {pace:g} s apart.", default=screen.samples, @@ -779,7 +779,7 @@ async def open_tx_optimize( "The saved password was cleared; sweep again to enter a new one.", style="err", ), - title="admin login", + title="Admin login", ) return False ctx.admin_store.remember(admin_node, password) @@ -831,7 +831,7 @@ async def open_tx_optimize( spinner = Spinner() flight = TracingDialog( - f"sweeping · {admin_node.name} → {target_label}", + f"Sweeping — {admin_node.name} → {target_label}", spinner=spinner, on_abort=screen.cancel, ) diff --git a/meshterm/ui/watchtower_screen.py b/meshterm/ui/watchtower_screen.py index 2ee77ba..eafbdcb 100644 --- a/meshterm/ui/watchtower_screen.py +++ b/meshterm/ui/watchtower_screen.py @@ -88,7 +88,7 @@ async def open_watchtower(ctx: "AppContext") -> Optional[dict[str, Any]]: while True: items = _menu_items(store.alerts(), store.watched(), store.new_node_alerts) menu = SelectScreen( - "🚨 Watchtower — alerts & watched nodes", + "Watchtower — alerts & watched nodes", items, default=cursor, wrap=False, @@ -206,7 +206,7 @@ async def _pick_node(ctx: "AppContext", contacts: list[Contact]) -> None: if contacts else "No contacts available — connect a device that knows some nodes first." ) - await session.message_dialog(Text(message, style="muted"), title="watch a node") + await session.message_dialog(Text(message, style="muted"), title="Watch a node") return def recency(pair: tuple[str, Contact]) -> float: @@ -221,7 +221,7 @@ async def _pick_node(ctx: "AppContext", contacts: list[Contact]) -> None: row.append(f" heard {_format_age(_age_seconds(contact.last_seen))}", style="muted") items.append(Choice(row, (key, contact))) picked = await session.select( - "⭐ Watch a node", + "Watch a node", items, prompt="Silence and SNR rules will watch it from now on:", ) diff --git a/tests/test_atlas.py b/tests/test_atlas.py index 2622617..be90d75 100644 --- a/tests/test_atlas.py +++ b/tests/test_atlas.py @@ -127,7 +127,7 @@ def test_atlas_renders_graph_and_overview_panel() -> None: assert "Homestead" in body and "YUL-Cartierville" in body and "Alice" in body assert "trace 1" in body and "packet 1" in body assert "rings = hops out" in body # the overview hint row - assert "Mesh Atlas · 3 nodes · 2 links" == screen.title + assert "Mesh atlas · 3 nodes · 2 links" == screen.title def test_atlas_empty_graph_renders_guidance() -> None: diff --git a/tests/test_config_editor.py b/tests/test_config_editor.py index 459a9bc..12da1ea 100644 --- a/tests/test_config_editor.py +++ b/tests/test_config_editor.py @@ -218,7 +218,7 @@ def test_location_picker_draws_a_live_crosshair_without_keeping_it() -> None: body = _plain(screen.render_body(80)) assert "⌖" in body and "45.5" in body # crosshair + its live coordinates assert screen._markers == markers # not accumulated across frames - assert "set location" in screen._title(screen._viewport) + assert "Set location" in screen._title(screen._viewport) def test_location_picker_without_nodes_or_initial_shows_the_world() -> None: diff --git a/tests/test_topology.py b/tests/test_topology.py index 72ac872..ec12f14 100644 --- a/tests/test_topology.py +++ b/tests/test_topology.py @@ -396,7 +396,7 @@ def test_composer_path_mode_opens_us_to_us_without_auto() -> None: the device to route to. """ screen = _composer(_topo(), target=False) - assert screen.title == "compose path" # no target to name + assert screen.title == "Compose path" # no target to name preview = screen._route_preview() assert preview.plain == "Us (aa) → Us (aa)" # endpoints carry our hash faint = sum(