Skip to content

feat(c3): Containers log-follow ([f]) — live tail with pause/resume - #1030

Merged
noonghunna merged 8 commits into
noonghunna:masterfrom
paulp83:feat/c3-container-log-follow
Aug 22, 2026
Merged

feat(c3): Containers log-follow ([f]) — live tail with pause/resume#1030
noonghunna merged 8 commits into
noonghunna:masterfrom
paulp83:feat/c3-container-log-follow

Conversation

@paulp83

@paulp83 paulp83 commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a [f] log-follow (live tail) to c3's Containers view Logs drill: new docker logs lines appear every ~2 s without re-pressing [l], with pause/resume and a live state indicator.

How

  • Poll, not stream — a 2.0 s interval re-reads the existing one-shot container_logs(name, tail=200) service call. No docker logs -f subprocess, no new service surface (services.py untouched).
  • Anchor dedupe — after any full-tail render the anchor is the last displayed line; each tick appends only the lines after the anchor's last occurrence. Anchor missing (tail scrolled past 200 lines, restart, in-place progress-bar line) or container changed → resync: clear + full fresh tail.
  • No interleaving — ticks share the exclusive container-logs worker group with stream_container_logs, so a tick and a manual [l]/navigation snapshot never interleave; cancellation races self-heal via resync.
  • Moving underline — new lines render underlined; each tick the previous batch drops back to plain and only the newest batch keeps the underline. RichLog is append-only, so the tick keeps a chronological display model (plain / newest-batch / state-note) and re-renders the pane from it while the user sits at the tail; while reading history (scrolled up) ticks append plain with no rewrite, and the next at-tail tick re-renders correctly.
  • State — three explicit states: off / following / paused. Pane title: Live / Live ● following (green) / Live … paused (yellow); pause/resume notes are display-only.
  • Invariants — the [Y]-copy tail stays plain text (markup stripped by the existing buffer; notes use buffer=False); no background polling when leaving the Containers tab or mode 0 (disarm on leave, re-entry starts off); the followed container dying → death note + disarm; browsing to a different stopped row keeps the mode armed (tick no-ops).

tui-core

LivePane gains tail-reader scroll-follow for every consumer: scrolling up stops auto-scroll (history stays readable while lines stream in), scrolling back to the bottom resumes it — gated on both the append-time scroll_end and RichLog.auto_scroll (which otherwise yanks the pane on every write). Plus set_title() and an at_bottom property.

Tests

  • 19 headless tests in TestContainerLogFollow (subprocess-free — injected FakeRunner, ticks driven by direct _log_follow_tick() calls, no real 2 s waits): binding/context gating, arm/pause/resume/disarm, tick dedupe + quiet-log no-op, resync, moving-underline batch tracking, note survival across re-render, scrolled-up plain append, navigation rebase, death/error disarms.
  • tui-core scroll-follow + at_bottom tests.
  • README keybindings row for f.

Verified on a live rig: full c3 suite green (896 passed; the two failures are a pre-existing registry-reps count mismatch that fails at pre-feature commits, and a tab-bar focus timing flake that passes in isolation), plus a read-only live smoke test driving the production app against real docker (arm → 3 real ticks on an actively-logging container → pause → resume → navigate to a quiet container → disarm-on-tab-leave).

Design spec: docs/superpowers/specs/2026-08-16-c3-container-log-follow-design.md.

paulp83 and others added 8 commits August 18, 2026 15:42
…drill

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Tint token: bold (portable brighter default foreground on light AND dark
terminals, no hue shift; bright_white no-ops on already-white themes).

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Tint token: underline (bold renders invisibly on the default foreground
in common terminals — manual check on the maintainer rig, 2026-08-16).
Follow/paused titles now use the rig's green/yellow state colors so the
on/off state reads at a glance; the pause note is yellow with a resume
hint and a symmetric green 'follow resumed' note (both display-only,
never in the [Y] copy).

Co-Authored-By: Claude <noreply@anthropic.com>
RichLog is append-only, so 'the previous batch loses its underline'
needs a rewrite: the tick keeps a chronological display model
(line/fresh/note) and re-renders #drill-logs from it while the user
sits at the tail — earlier fresh lines drop back to plain, only the
newest tick's lines stay underlined.  While reading history the tick
appends plain (no rewrite, no yank) and the next at-tail tick
re-renders correctly.  State notes (pause/resume) are recorded in the
model so re-renders re-emit them in place; the [Y]-copy tail stays
plain text.  LivePane gains an at_bottom property for the gate.

Co-Authored-By: Claude <noreply@anthropic.com>
@paulp83
paulp83 force-pushed the feat/c3-container-log-follow branch from 2ac259f to 9f7e451 Compare August 20, 2026 00:38
@noonghunna
noonghunna merged commit e06f730 into noonghunna:master Aug 22, 2026
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.

2 participants