workspace: show a repo's linked worktrees in work-diff #123
No reviewers
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
allod/tools!123
Loading…
Reference in a new issue
No description provided.
Delete branch "agent/worktree-aware-collector"
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?
work-diffis the cross-repo view of uncommitted work, and it was blind to agent worktrees: three live/tmp/allod-change-*worktrees exist on this VM today and none of them appeared. This addsworkspace_collect_worktreestolib/workspace.shand renders each repo's linked worktrees under it inwork-diff, attributed to their branch.Contracts implemented, both unchanged by this PR:
git -C <repo> worktree list --porcelain, never a filesystem glob; the first record is the main checkout and is skipped positionally. Nothing depends on where worktrees are sited, so the/tmpto~/changesmove in allod/tools#116 needs no change here.workspace_collect_reposis untouched, sopull-all,flake-status, andflake-update-cascadekeep seeing exactly the registry checkouts.Also included:
show_tree_state(extracted fromshow_repo) now returns 0 explicitly. Its last statement was a trailing[[ -n "$unstaged" ]] && printf ..., so underset -eany repo with untracked-only changes made the function return 1 and aborted the whole run —work-diffexited 1 with the report truncated at that repo. This was pre-existing and reproducible on master; the worktree loop would have hit it constantly, since an agent worktree with only untracked files is the common case.Risk
R1. Additive library function plus a read-only renderer; no tool that mutates a repo consumes the new entry point.
Residual: a linked worktree sited under
$WORK_DIRwould render twice — once as a repo, becauseworkspace_is_repo_rootaccepts it, and once nested under its owner. C1 forbids that siting and allod/tools#116 owns it, so this PR does not filter for it. Filtering inwork-diffwas considered and rejected: when the owning repo is outside$WORK_DIR, dropping the top-level entry would hide the work entirely, which is the opposite of what this tool is for.Output volume grows by one line per worktree even when clean. That is deliberate — a lingering worktree awaiting
allod change cleanupis worth seeing.Validation
Also run green:
tests/allod-change.sh,tests/allod-patch.sh,tests/flake/*,tests/git-hooks/protected-refs-policy.sh,tests/forge/*.New coverage: a worktree with staged, unstaged, and untracked changes rendered under its owning repo with its branch; a detached worktree labelled; a prunable worktree skipped; ordering proving the worktree is nested under its own repo rather than appended after the next one;
workspace_collect_worktreesskipping the main checkout;workspace_collect_reposreturning exactly the registry checkouts for a workspace whose repos have worktrees;pull-allnever invokingworktreeat all against its mock git; and the untracked-only truncation regression.Per
architecture.mdprinciple 11, every new assertion was verified to fail on sabotaged input rather than merely to pass. Eight mutations, each checked to have actually applied and to still parse, and the assertion each one broke:show_tree_stateloses itsreturn 0record > 0)workspace_collect_worktreesskips the main checkout[[ -d "$path" ]]guard removedshow_worktreescall removed${branch:-detached}reduced to$branchworkspace_collect_reposemits worktrees tooworkspace_collect_reposreturns exactly the registry checkouts, andpull-all: never enumerates worktreesManual check against the real workspace:
work-diffnow lists all three liveagent/*worktrees underallod/tools, including this change's own.Closes allod/tools#117
Refs allod/tools#115
Independent verification pass, run from a clean checkout of the branch rather than from the authoring worktree.
C5 holds. The
lib/workspace.shdiff is purely additive —workspace_collect_worktreesis new andworkspace_collect_reposhas no changed lines, sopull-all,flake-status, andflake-update-cascadesee an identical set.The
set -etruncation bug is real and was pre-existing. Reproduced against7a16f26with a two-repo fixture where the first repo has only untracked files:work-diffexits 1, renders the first repo, and never renders the second. Same fixture on this branch exits 0 and renders both. The report was silently truncating, which is the failure mode worth naming in review — it looked like a short workspace rather than an aborted run.Suites pass from the clean checkout:
tests/workspace/work-diff.sh,tests/workspace/pull-all.sh,tests/allod-change.sh, andtests/git-hooks/protected-refs-policy.shall green.Sabotage spot-check reproduced independently, per architecture principle 11. Changing the main-checkout skip from
record > 1torecord > 0applied cleanly, still parsed, and made the suite fail — so that assertion is load-bearing rather than vacuous. I checked one of the eight rather than all of them.Two things for human judgement, neither a defect:
$WORK_DIR. allod/tools#117's goal "a worktree is never treated as a repo to pull or switch" is satisfied by construction once allod/tools#116 lands C1, not by anything in this PR. That is the right call under C5 — an exclusion filter insideworkspace_collect_reposis exactly what C5 forbids — but it means the guarantee rests on siting discipline alone. If a defensive guard is wanted it is a separate change with its own blast radius.