rebuild_f5.py creates a nested `<topic>-f5-f5` when run from inside an f5 worktree nf-kiwe ← Beads

closed priority 2 task unassigned activesession:f5-docs

Twinned from https://github.com/cfsh/ninefold/issues/648 by tools/beads/import_github.py's reconcile pass.

The bork-f5-f5 in #602 has a mechanism, and it is one keystroke wide. I reproduced it by accident while working #641, and then had to reap my own reaper-f5-f5.

What happens

rebuild_f5.py derives its worktree path from its own repo_root(__file__), as a sibling with -f5 appended. Every worktree holds a copy of the script — including the f5 worktree itself — so:

```bash cd ~/nf/devs/<topic>-f5 # e.g. to resolve the conflict rebuild_f5 just asked you to resolve ./tools/pr/rebuild_f5.py # ← this copy's root is <topic>-f5 ```

builds in ~/nf/devs/<topic>-f5-f5, registers it as a worktree, and leaves it behind. Measured just now:

``` Ninefold.Tests -> /root/nf/devs/reaper-f5-f5/tests/bin/Debug/net8.0/Ninefold.Tests.dll ```

⚠️ The path in is the tool's own instructions. On a conflict it prints cd /root/nf/devs/<topic>-f5 && git add -A && git commit --no-edit, then *"re-run this script from anywhere"* — and the cheapest re-run from where you now stand is ./tools/pr/rebuild_f5.py, which is the wrong copy. That is how I got there.

A second, subtler consequence: the f5 worktree is detached at f5/integration, so its copy of the script is whatever logic the integration branch merged in, not main's. My accidental run used #604's not-yet-merged docs-inertness rule and reported f5/integration = main (5 branches outside the build); the same command from the real clone merged all five. Two runs, two answers, neither wrong about the code it was running.

The fix, roughly

ensure_worktree should refuse when its own root is already an f5 worktree — the check is cheap (root.name.endswith(WORKTREE_SUFFIX), or the stronger "root is a detached worktree whose path is <something>-f5") and the refusal should name the right invocation:

git -C <main clone> ... ./tools/pr/rebuild_f5.py

spawn_dev.py's main_clone() already exists for exactly this class of mistake — every worktree holds a copy of every tool, so repo_root(__file__) is not the clone. Anchoring the f5 path on the *main working tree* rather than on __file__'s root would remove the nesting entirely, not just refuse it.

Why it is worth fixing at the source

#640/#641 (wrap_up.py, tools/office/reap.py) now *reap* -f5-f5 residue — nflib.sessions.base_topic strips the suffix repeatedly, precisely because of this issue. Reaping it is the cleanup; not creating it is the fix. Related: #534 (needs:direction) asks whether f5 should use one shared directory instead of a worktree per clone, which would delete this failure mode along with half of #602.

Unclaimed, unlabelled. Found while working #641; not folded into it because it is a correctness fix in another tool on the merge path.

Dependencies

None.

Comments

No comments.

Add a comment