This repository has been archived on 2026-08-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
pi-web/.pi-web/relays/worktree-autodetect/status.md
T

5.6 KiB

Status — relay "worktree-autodetect"

🏁 FINISHED — the relay reached its finish line

All three legs are complete and committed on feat/worktree-autodetect. npm run verify is green. No further leg was spawned; leg 3 was the last one by design.

Remaining human action: review the branch and merge it. Nothing is blocked.

Post-relay review fix

A human review question after leg 3 ("do we have pragmatic reasonable and stable code?") found one real gap, fixed in 79577e4: applyProjectWorkspaces replaced the list but left selectedWorkspace pointing at the old object, so a branch switched inside a worktree outside PI WEB showed the new name in the list and the old one in the collapsed Workspaces header and mobile context bar. Now re-pointed by id, and skipped entirely when metadata is unchanged so a normal resume does not churn identity. Two tests added (9 total in workspaceController.test.ts), each mutation-checked in both directions. npm run verify green: 1842 passed, 2 skipped (1843 after the two follow-up fixes below).

The other two review nits were then fixed as well, after the human asked:

  • 8f060d1 removed the unused GitWorktreeInfo.locked flag. The parser test still feeds a real locked porcelain line and asserts it is ignored, so the keep-locked-worktrees policy stays covered without a speculative field.
  • f8c3fdb fixed what turned out to be a correctness bug, not the cosmetic nit I first rated it. The resume path and the plugin-facing app refresh call refreshSelectedProjectTopology independently, and the stale guards check machine and project but not ordering — so a slower earlier response landing last overwrote a newer list and a just-created worktree disappeared again. Reproduced with a scratch test before fixing. Now routed through TrailingRefreshCoordinator keyed by machine+project.

Note for anyone extending this: TrailingRefreshCoordinator does not collapse two overlapping calls into one HTTP request. It runs the second as one trailing pass after the first completes, so the newest response is always applied last. An assertion of toHaveBeenCalledOnce() will hang against it.

Current position

Every charter finish-line condition is satisfied:

  1. Prunable worktrees hidden266f941. discoverGitWorktrees parses prunable; WorkspaceService filters those worktrees out, while always keeping the project's own worktree so a project is never empty.
  2. Non-disruptive client refreshd0f8f9f. WorkspaceController.refreshSelectedProjectTopology() applies results through applyProjectWorkspaces only, never selectWorkspace, so selection, session, file tree, git status, and terminal selection survive. A vanished selected workspace is left alone for the existing deletion path to handle.
  3. Wired to the existing resume path84545fb. Called from PiWebApp.refreshAfterBrowserResume and refreshAppData. No new timer, watcher, process, endpoint, or push channel. Remote machines work through the existing machinePrefix + FEDERATED_HTTP_ROUTES plumbing.
  4. Tests — prunable parsing/filtering (gitWorktreeDiscovery.test.ts, workspaceService.test.ts), refresh-preserves-selection and refresh-when-selected-workspace-disappeared (workspaceController.test.ts, 7 tests), resume + app-data wiring (PiWebApp.workspaceTopology.test.ts, 3 tests).
  5. npm run verify green (228 files / 1843 passed, 2 skipped) and .changeset/worktree-autodetect.md exists.

Nothing in this work touched src/server/sessiond.ts, session runtime ownership, or the daemon protocol. No manual session daemon restart is required.

Leg tracking

  • Last completed leg: 3 (final — wiring, docs, changeset, full verify)
  • Next leg to run: none. Relay complete; do not spawn another runner.

Shipped behavior, as a user sees it

A worktree created or deleted outside PI WEB shows up in (or disappears from) the workspace list the next time the browser tab regains focus or becomes visible. Detection is resume-scoped, not instant, by explicit human decision. A worktree whose checkout directory was rm -rfed no longer appears as a selectable workspace. Documented in docs/faq.html under #worktree-list-out-of-date.

Relevant context if anyone picks this branch up

  • Commits: 266f941 (server filter), d0f8f9f (client refresh method), 84545fb (wiring + docs + changeset), 79577e4 (selected-workspace freshness fix), 8f060d1 (drop unused locked), f8c3fdb (serialize overlapping refreshes), plus the docs(relay) packet commits.
  • Second invariant, added by 79577e4: re-pointing selectedWorkspace is safe only while it is keyed by id and skipped on unchanged metadata. Keying it by anything that can differ between two lists would change the selection on a background refresh; dropping the unchanged-metadata guard would push a new object into state on every browser focus.
  • The invariant to protect on any future edit: never route a background topology refresh through selectWorkspace. It calls clearActiveSession() and resetWorkspaceScopedState() with no already-selected guard, which would close the session socket and blank the chat on every browser resume. workspaceController.test.ts was mutation-checked against exactly that regression in leg 2.
  • The relay packet lives under .pi-web/, which is gitignored; packet commits used git add -f.

Blockers

None. No intervention signal fired in any leg. The one serious known risk — visible UI churn on refresh — did not materialize and needed no workaround.