Skip to content

feat(ports): surface listening ports per session in the fleet view - #104

Merged
jitokim merged 1 commit into
mainfrom
feat/ports-surfacing
Jul 31, 2026
Merged

feat(ports): surface listening ports per session in the fleet view#104
jitokim merged 1 commit into
mainfrom
feat/ports-surfacing

Conversation

@jitokim

@jitokim jitokim commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Review

Review complete. I read the full diff (7 files, +742/−27), pivot.md §11, and ran go vet + the three affected packages' tests (all green). Verdict: solid — no blocking issues. Minor notes only:

  • §11 design match: yes, with one deliberate, documented deviation. All of §11's first slice is there: Loop.Ports []int (nil = nothing observed), ListeningPortsByCwd() as two procTimeout-bounded lsof probes, applyPorts right after applyLiveness, the CwdVerified-only gate, exact-match-only v1, the gated probe (recommended option), dim 🌐:3000 FLEET tag + DETAIL PORTS row, and all four honesty rules. The deviation: §11 specified the cwd→loop join as encodeCwd(serverCwd) == Loop.ProjectDir, but the code compares real lsof paths (portsByCwd[loops[i].Cwd]) instead. That's strictly more honest — encodeCwd is many-to-one and could attach one dir's server to another dir's loop — and the applyPorts doc comment explains exactly why. Improvement, not drift.
  • Pure observation: confirmed. Only read-only lsof exec; no open, no spawn/write/backend coupling; State/Stall never touched (pinned by TestApplyPorts_StateNeverTouched); probe failure attaches nothing. The §11 "open :3000" actuation was correctly left out of v1.
  • Seam reuse: good, with mild parser duplication. procs.go now has three sibling p/n record walkers (parseLsofCwds, parseLsofListenPorts, parseLsofPidCwds) with near-identical loop skeletons. §11 anticipated this ("isomorphic to parseLsofCwds"), and each has a real reason to differ (count vs pid-keyed vs port-parsing), so it's acceptable — but a shared p/n record iterator is an easy follow-up if a fourth walker ever appears. TUI side reuses the ACCOUNT-column pattern faithfully (caller-requested, presence-gated, byte-identical rows when absent).
  • Tests via injection seams: yes. Parsers and the join are tested on captured lsof output shapes; applyPorts/anyCwdVerified on injected maps; the width cascade, tag truncation (+N suffix drops, digits never sheared), demo fixture, and both DETAIL presence/absence cases are covered, including failure cases (probe failure, unverified cwd, subdirectory listener, bad pid lines). Only ListeningPortsByCwd itself is untested — consistent with LiveClaudeCwds, which has the same exec-boundary exemption.
  • Nitpick (comment slightly overclaims): both new parsers document "an unparseable p line orphans the n lines under it, never credited to the previous pid," but a bare p line (length 1) is skipped by the len(line) < 2 guard before the switch, leaving pid at its previous value — so its n lines would be credited to the prior pid. Purely theoretical (lsof never emits a bare p; the tested pNOPE case is handled correctly), but if you want the comment to be literally true, reset pid = -1 for short lines starting with p, or soften the comment.
  • Width math checked: the wPort = 10 claim about surviving renderWide's capped panel holds — at inner width 70 with ACCOUNT + PORT requested, the cascade sheds ORACLE and CYCLE and lands NAME exactly at nameGoodWidth (20), so PORT survives; at 12 it would drop. The 🌐:65535 fit claim (8 cols ≤ wPort−1) is also correct.
  • Style/invariants: comment density and narrative style match the codebase; English-only holds throughout (code, comments, commit message); Conventional Commit format ok; demo fixture keeps its "only states the product can produce" discipline (ports ride a verified cwd, pinned by test).

🤖 Generated with Claude Code

The captain runs many worktrees with make local PORT=xxxx e2e servers and
loses track of which port belongs to which session. Surface the observed
listening TCP ports on each loop, per pivot.md §11:

- claude.ListeningPortsByCwd: two bounded lsof probes (system-wide TCP
  listeners, then those pids' cwds), same procTimeout discipline and
  p/n record parsing as LiveClaudeCwds
- claude.applyPorts: enrich after applyLiveness, attaching ports only to
  CwdVerified loops by exact real-path match — probe failure attaches
  nothing, ambiguity attaches nothing, State/Stall never touched
- probe is gated: skipped entirely when no loop has a verified cwd
- FLEET row: optional dim 🌐:3000 tag column (accountTag pattern, shown
  only when >=1 visible loop has ports; drops before ACCOUNT in the
  width cascade); DETAIL panel: PORTS row under CWD with every port
- demo fleet: flaky-tests carries an observed port so --demo shows it

Pure observation, display-only: no actuation, no health claims — a port
present means exactly "a listening socket was observed in this loop's
verified cwd", nothing more.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: jitokim <pigberger70@gmail.com>
@github-actions github-actions Bot added area/claude Claude CLI integration area/domain Core domain types area/tui Terminal UI labels Jul 31, 2026
@jitokim
jitokim marked this pull request as ready for review July 31, 2026 00:18
@jitokim
jitokim merged commit 7b0594d into main Jul 31, 2026
3 checks passed
@jitokim
jitokim deleted the feat/ports-surfacing branch July 31, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/claude Claude CLI integration area/domain Core domain types area/tui Terminal UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant