feat(dashboard): the worktree list matches what is on disk #414
No reviewers
Labels
No labels
bug
contract
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
iterative-works/iw-cli!414
Loading…
Reference in a new issue
No description provided.
Delete branch "dashboard-control-plane"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Slice: dashboard-control-plane/01-worktrees-match-disk
Goal (the use). Open the dashboard after the server was down — including after making
worktrees while it was down — and see every worktree actually on disk, with no re-registration
by hand.
Fit test. Stop the server,
./iw starta worktree, bring the server up, read the list athttp://localhost:9876againstgit worktree listin each registered project. It closes on thehuman's read: nothing known is missing, nothing foreign is present.
Fit passed on 2026-08-03 — measured across 17 registered projects: 60 live worktrees on
disk, 60 registered, 0 missing, 0 foreign.
What ships
The sweep. The server reads
git worktree list --porcelainfor every registered project atstartup and on
/, throttled to one pass per 30s, and registers what state is missing. Disk isread, never written: no worktree is created, moved, or removed. Registration still flows through
the one
WorktreeRegistrationService.registerthat./iw startdrives — the sweep is a recoveryfor that path, not a second copy of it.
Foreign entries are decided by git, not by
os.exists. A directory left behind after aworktree is removed loses its card; a worktree of a project that is not registered keeps one; a
scan that reached no project concludes nothing.
Every worktree of a registered project gets a card.
WorktreeKind.Plainnames a worktreewith neither a tracker issue nor a framed effort — a release or hotfix checkout — keyed on its
branch and badged "Branch". Checks that read "is an effort" now read "has no tracker issue".
Grouping stopped guessing.
WorktreeRegistration.projectPathrecords the owning repository,sent by
./iw start,iw registerand the dashboard's own create path. The field is optionaland the sweep fills it in for registrations that predate it.
Any command can start the server.
DashboardJar.locateresolves the jar fromIW_INSTALL_DIRin the orderiw-runuses — environment override, the jar a release ships, thejar a dev checkout builds.
ProcessManagerno longer requiresIW_DASHBOARD_JAR, whichiw-runsets only on the dashboard command paths.
Root-cause fix found on the way
WorktreeRegistrationService.registerandupdateLastSeenrebuiltServerStatefrom theworktrees map alone, dropping all four caches and every registered project. The HTTP endpoint had
masked this for as long as it existed by reading one registration out of the result and throwing
the state away; the sweep stored it, and the loss surfaced immediately. Both carry the state over
now, with regression tests at the register and the reconcile level.
Review
Seven skills, 4 critical findings, all fixed in loop — see
project-management/efforts/dashboard-control-plane/slices/01-worktrees-match-disk/review-slice-20260803-210757.md.updateLastSeenpassed itsstatePathinto the newprojectPathparameter, so everyiw issue/iw openoverwrote the recorded project with the path ofstate.json.v1.9.15could never beswapped in — the dots parse as class names.
os.Paththrow inside the sweep, which runs in the serverconstructor — one bad
PUTwould have stopped the dashboard from starting.projectPathwiring iniw registerhad no test.Gates
Follow-ups (parked in the effort map, none blocking)
withLockhelper inServerStateService— nine copies of lock/mutate/persistCaskServeris a god object; the sweep adds another responsibilitydashboard/jvm/src/domain/andapplication/are the target layoutWorktreeRegistration.createis bypassed forkindandprojectPathcore/test/under the pre-commit-WerrorcompileGET /only, not from the project or worktree pagesplainKeycan collapse two branches to one key