Skip to content

pacectl: navigate the fleet view by machine and open a machine's detail - #1722

Merged
christianparpart merged 7 commits into
masterfrom
design/fleet-operator-analytics
Oct 20, 2026
Merged

christianparpart merged 7 commits into
masterfrom
design/fleet-operator-analytics

Conversation

@christianparpart

@christianparpart christianparpart commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

What

pacectl live-stats fleet gains keyboard navigation and a per-machine detail view, so an operator can investigate one machine without asking anybody to run a command on it.

  • Up / Down move a highlight through the chart's machine lanes and on into the active section's table rows (no wrap). Left/Right, Tab, digits, letter hotkeys, PgUp/PgDn/Home and / are unchanged.
  • The highlighted machine is linked across the two zones: its lane label and its rows in the table below are dressed together.
  • Enter opens a detail view of that machine: its row from every section of the fleet document that names machines (machines, workers, leases, members, conditions, tiers). No new wire traffic — it reads the document the stream already delivers.
  • Esc closes the detail. Esc still quits when nothing is open; q/Ctrl-C quit everywhere. The dashboard loop now asks a view ClaimsEscape() (pure virtual on IDashboardView) before treating Esc as quit.
  • A failed sample does not tell the detail its machine left (the heading shows the absent marker); only a sample that was read and lacks the machine says not in the latest sample.
  • On a short terminal the detail drops whole sections from the bottom instead of refusing with a size message.

This is Part B of the fleet operator analytics design. Part A (client reporting: why a build was not distributed, toolchain census, usage per machine) is a separate plan. Operator actions (tier management, machine labels) are deferred to #1720.

How

  • src/apps/pacectl/FleetFocus.{hpp,cpp} — a pure focus model: StepFocus, ClampFocus, and MachineColumnOf (an EnumTable<FleetSection, …>, each column checked against the leader's FleetColumnNames).
  • DashboardPanel.{hpp,cpp} — FocusStepKeys / DetailKeys tables; one row matcher (WriteMatchingRows) shared by the table, the highlight and the detail; the lanes are read over the window the chart actually drew.
  • DashboardLoop.{hpp,cpp} — EscapeKey named once; ClaimsEscape on every view, test fakes included.
  • docs/tools/pacectl.md — the new keys and the detail view.
  • .gitignore / mkdocs.yml — docs/superpowers/ (the agent workflow's local design and plan files) is never tracked, and is excluded from a local strict site build.

Testing

  • Windows cl-debug: whole pacectl-tests binary, 700 cases passing.
  • scripts/local-gate.sh in WSL (clang-format 22.1.8 and clang-tidy 22.1.8 pinned): clang-debug leg passed (build with clang-tidy, full ctest). gcc-release leg passed — LOCAL GATE PASSED. (An earlier run on a host whose g++ was an update-alternatives chain failed dist-compile-e2e on a launcher/worker fingerprint disagreement, in code this PR does not touch; filed as Toolchain fingerprint differs between launcher and worker when g++ is an update-alternatives chain #1721.)
  • Manual check against the live fleet (Windows, real pseudo-console): Down twice selected LAT-260401-04, Enter showed only its rows from every section, Esc returned, q exited 0.
  • Every task and the whole branch were reviewed; neutered-fix runs show the new tests fail without their fixes.

@christianparpart christianparpart added the type/feature New capability, or a user-visible extension of one label Oct 20, 2026
@github-actions github-actions Bot added area/protocol Protocol/, Auth/ - memcached, RESP, autodetect, the auth gate area/observability Metrics/, logging, stats and scrape surfaces labels Oct 20, 2026
Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
… and rows

Up and Down walk the fleet view's chart lanes, then the active section's
matched rows (StepFocus), over the counts the last frame drew. The machine
the highlight names is dressed as Selected wherever it appears: its band's
label and the first cell of every table row whose machine column names it,
plus the focused row itself. Each frame clamps the focus to the lanes and
rows it has before drawing, so a sample or filter that removes the focused
row moves the highlight rather than losing it; a section switch or filter
edit restarts a row focus on the first row, and a focused row is scrolled
into view.

Row matching is lifted into WriteMatchingRows, so the drawn table and the
highlight count the same rows. FocusedMachine is public for the detail view
that follows.

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
The lanes Up and Down walk were read over the whole history while a text
chart bands only the samples its cells hold. A machine that fell silent
between the two spans was lane 0 in the list and in no band: the first
Down dressed nothing and the last drawn band could not be reached. The
view now records the chart's window with its band count and reads the
lanes over it.

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
…returns

Enter on a highlight that names a machine draws that machine's detail in
place of the tiles, chart, strip and table: a `machine <endpoint>` heading
with its name, then every tabular section that names machines, restricted
to that machine's rows through WriteMatchingRows (TableState gains
restrictToMachine). A section with none of its rows writes the absent
marker under its name, and a machine the latest sample no longer lists
says `not in the latest sample`. Esc closes the detail and the focus is
where it was; while it is open no other key acts.

IDashboardView gains a pure ClaimsEscape, implemented by every view: the
loop hands Esc (now the named EscapeKey) to a view that claims it rather
than quitting. The strip's hint names the keys that select and open a
machine, yielding first for width, and the rung glyphs spell the arrows
as ASCII where the terminal is.

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
…d samples right

The final review of the fleet navigation branch found six things:

- A failed sample nulls the latest document, and the detail heading read
  that as `not in the latest sample`. The note is now said only when a
  machines section was read and lists no such machine; with none read the
  heading carries the absent marker.
- Every detail section was Essential, so a terminal of about 21 rows or
  fewer drew the minimum-size line. Each section is now one table item,
  its name a heading line above its columns (Item::heading), at a
  priority below Essential: tables shrink, then whole sections drop from
  the bottom, keeping the heading. A restricted table with no rows is the
  absent marker without the column-width check.
- The detail dressed every row Selected. The restriction now travels as
  TableState::only (a RowMachine), never as the highlight's machine.
- Docs say the detail's tables do not scroll; the QuitKeys and NamedKeys
  comments no longer contradict what Esc and the arrows now do; the
  filter's Esc row spells EscapeKey.
- Tests pin that no key but Esc acts while a detail is open, that a
  second Esc quits, and that a focused row past the page is scrolled in.

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
clang-tidy 22.1.8 refused two things on this branch: PlacedFrame's
cognitive complexity (62, threshold 60) and EscapeClaimingView's public
`offered` beside a private member. The per-frame clamp of the highlight
and the machine it names is now FocusForFrame, a pure function over the
frame's inputs and the walk state (FocusWalk -> FramedFocus); the fake
keeps every member public, as the file's other recording fakes do.

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
…off the site

docs/superpowers/ holds the design and plan documents the agent workflow
writes. They are local working files: ignored, never tracked, and excluded
from the site so a local strict mkdocs build does not refuse them.

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
@christianparpart
christianparpart force-pushed the design/fleet-operator-analytics branch from 6fda414 to c459f3f Compare October 20, 2026 18:44
@christianparpart
christianparpart merged commit 16fb5b7 into master Oct 20, 2026
35 checks passed
@christianparpart
christianparpart deleted the design/fleet-operator-analytics branch October 20, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/observability Metrics/, logging, stats and scrape surfaces area/protocol Protocol/, Auth/ - memcached, RESP, autodetect, the auth gate type/feature New capability, or a user-visible extension of one

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant