Round 44: parallel-worktree-safety cartographer research#35
Conversation
Research doc enumerating eight hazard classes for parallel worktree use, each paired with preventive + compensating mitigations per the discovered-class-outlives-fix principle: 1. Live-lock between parallel worktrees 2. Merge conflicts as expected cost 3. Build-speed ceiling 4. Stale-branch accumulation 5. Memory bifurcation 6. Tick-clock CWD inheritance 7. Split state files 8. Unknown unknowns (cartographer discipline) Staging R45-R49 proposed for EnterWorktree-default flip. Originates from Aaron 2026-04-22 nine-message sequence captured in memory `feedback_parallel_worktree_safety_ cartographer_before_default.md`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a research “cartographer pass” documenting hazards and mitigations for making parallel Git worktrees the factory default, including a staged rollout proposal.
Changes:
- Introduces an 8-class hazard map for parallel-worktree operation with preventive + compensating mitigations.
- Proposes instrumentation/backpressure guidance tied to CI gate latency.
- Outlines a Round 45–49 staging plan for a potential
EnterWorktreedefault flip.
|
|
||
| Claude Code's auto-memory lives at `~/.claude/projects/<slug>/memory/` where `<slug>` is the session's initial CWD with `/` replaced by `-`. Example: `~/.claude/projects/-Users-acehack-Documents-src-repos-Zeta/memory/`. | ||
|
|
||
| - **Single session that uses `EnterWorktree`:** the slug is set when the session starts, based on the initial CWD (the main repo root). `EnterWorktree` changes the session's CWD but does NOT re-keyed the slug. Memory continues to load/write from the original slug. Tool calls using absolute paths (which all of mine do) work identically across the boundary. **Verified**: this tick's session started in `/Users/acehack/Documents/src/repos/Zeta`, entered a worktree at `.claude/worktrees/pr32-markdownlint`, wrote three memory files from within the worktree, and `ls ~/.claude/projects/` shows only the main-repo slug — no worktree-specific slug was created. |
There was a problem hiding this comment.
P2: Grammar issue: “does NOT re-keyed the slug” is ungrammatical; it reads like a mix of active/passive voice. Rephrase to “does not re-key the slug” or “the slug is not re-keyed” to keep the statement clear.
| - **Single session that uses `EnterWorktree`:** the slug is set when the session starts, based on the initial CWD (the main repo root). `EnterWorktree` changes the session's CWD but does NOT re-keyed the slug. Memory continues to load/write from the original slug. Tool calls using absolute paths (which all of mine do) work identically across the boundary. **Verified**: this tick's session started in `/Users/acehack/Documents/src/repos/Zeta`, entered a worktree at `.claude/worktrees/pr32-markdownlint`, wrote three memory files from within the worktree, and `ls ~/.claude/projects/` shows only the main-repo slug — no worktree-specific slug was created. | |
| - **Single session that uses `EnterWorktree`:** the slug is set when the session starts, based on the initial CWD (the main repo root). `EnterWorktree` changes the session's CWD but does NOT re-key the slug. Memory continues to load/write from the original slug. Tool calls using absolute paths (which all of mine do) work identically across the boundary. **Verified**: this tick's session started in `/Users/acehack/Documents/src/repos/Zeta`, entered a worktree at `.claude/worktrees/pr32-markdownlint`, wrote three memory files from within the worktree, and `ls ~/.claude/projects/` shows only the main-repo slug — no worktree-specific slug was created. |
| - `memory/feedback_discovered_class_outlives_fix_anti_regression_detector_pair.md` — the principle this research instantiates across 8 hazards. | ||
| - `memory/feedback_live_loop_detector_speculative_on_pr_branch.md` — the live-loop class that motivated the worktree pattern in the first place. | ||
| - `docs/research/worktree-pattern-for-live-loop-prevention-2026-04-22.md` — the prior research doc that introduced `EnterWorktree` to the factory; this doc extends it from single-worktree to parallel-worktree safety. | ||
| - `memory/feedback_kanban_factory_metaphor_blade_crystallize_materia_pipeline.md` — cartographer metaphor source. | ||
| - `memory/feedback_never_idle_speculative_work_over_waiting.md` — the rule that drives tick-cadence; parallelism must not violate it via backpressure-starvation. |
There was a problem hiding this comment.
P1 (xref): Several items in “Related docs & memories” point to files that aren’t present in the repo at the cited paths (e.g., memory/feedback_discovered_class_outlives_fix_anti_regression_detector_pair.md, memory/feedback_live_loop_detector_speculative_on_pr_branch.md, docs/research/worktree-pattern-for-live-loop-prevention-2026-04-22.md). Please either add these files in the PR or update the references to the correct existing locations so pointer-integrity audits don’t fail.
| - `memory/feedback_discovered_class_outlives_fix_anti_regression_detector_pair.md` — the principle this research instantiates across 8 hazards. | |
| - `memory/feedback_live_loop_detector_speculative_on_pr_branch.md` — the live-loop class that motivated the worktree pattern in the first place. | |
| - `docs/research/worktree-pattern-for-live-loop-prevention-2026-04-22.md` — the prior research doc that introduced `EnterWorktree` to the factory; this doc extends it from single-worktree to parallel-worktree safety. | |
| - `memory/feedback_kanban_factory_metaphor_blade_crystallize_materia_pipeline.md` — cartographer metaphor source. | |
| - `memory/feedback_never_idle_speculative_work_over_waiting.md` — the rule that drives tick-cadence; parallelism must not violate it via backpressure-starvation. | |
| - The discovered-class-outlives-fix rule — the principle this research instantiates across 8 hazards. | |
| - The live-loop detector rule for speculative work on PR branches — the live-loop class that motivated the worktree pattern in the first place. | |
| - The prior worktree-pattern research doc that introduced `EnterWorktree` to the factory; this doc extends it from single-worktree to parallel-worktree safety. | |
| - `memory/feedback_kanban_factory_metaphor_blade_crystallize_materia_pipeline.md` — cartographer metaphor source. | |
| - The never-idle speculative-work-over-waiting rule — the rule that drives tick-cadence; parallelism must not violate it via backpressure-starvation. |
| **Date:** 2026-04-22 | ||
| **Trigger:** Aaron across nine messages in one tick: | ||
|
|
There was a problem hiding this comment.
P1 (codebase convention): This doc uses the human maintainer’s personal name (“Aaron”) in narrative headings and throughout. The repo standard is to avoid name attribution in docs/skill bodies and use role refs (e.g., “human maintainer”) instead (see docs/AGENT-BEST-PRACTICES.md:284-290). Please rename the references accordingly (and keep names confined to the allowed locations).
| **Preventive:** | ||
|
|
||
| - **Auto-delete branch on PR merge.** GitHub setting: *Automatically delete head branches* (Settings → General → Pull Requests). One-time toggle; subsequent PR merges auto-delete their branch. | ||
| - **Auto-delete branch on PR close (unmerged).** Same setting covers this since PR close and merge both fire the hook. |
There was a problem hiding this comment.
P1: The claim that GitHub’s “Automatically delete head branches” setting also deletes branches when a PR is closed unmerged appears incorrect; it deletes the head branch after a PR is merged. If you want deletion-on-close, document a separate mechanism (workflow/bot) or adjust the text to avoid implying the setting covers both cases.
| - **Auto-delete branch on PR close (unmerged).** Same setting covers this since PR close and merge both fire the hook. | |
| - **PR close (unmerged) needs a separate mechanism.** GitHub's *Automatically delete head branches* setting does **not** delete branches when a PR is closed unmerged. If we want deletion-on-close, document and ship that separately as a workflow/bot policy; otherwise rely on the audits below plus the factory's explicit branch-removal convention. |
| **Policy for the factory:** | ||
|
|
||
| - **Always start Claude Code from the main repo root.** Use `EnterWorktree` for worktree work. Do not `cd <worktree> && claude` — that bifurcates memory. | ||
| - Document this rule in `docs/AUTONOMOUS-LOOP.md` under "session-start checklist" (if that section exists; otherwise add one). |
There was a problem hiding this comment.
P1 (xref): This section instructs updating docs/AUTONOMOUS-LOOP.md, but that file does not exist in the repo at this path. Please either point to the correct existing doc (if renamed) or add the missing doc/update the reference so the action item is actionable.
| - Document this rule in `docs/AUTONOMOUS-LOOP.md` under "session-start checklist" (if that section exists; otherwise add one). | |
| - Document this rule in `CLAUDE.md` under a session-start checklist or startup hygiene section (add that section if it does not exist yet). |
| A worktree is a separate working directory. Files that are auto-appended-to every tick (e.g. `docs/hygiene-history/loop-tick-history.md`) will diverge between the worktree and main if the tick runs in the worktree. | ||
|
|
||
| **Example of the hazard (this tick almost hit it):** I entered `pr32-markdownlint` worktree on `round-42-speculative`. If I had written to `docs/hygiene-history/loop-tick-history.md` *from within the worktree* instead of *from the main repo*, the entry would have landed on the wrong branch and wrong working-tree copy. Then at tick close, the main repo wouldn't reflect the tick. | ||
|
|
||
| **Class-detector:** tick-history appends must happen in the main repo, not inside a worktree. Enforcement options: | ||
|
|
||
| 1. CLAUDE.md rule: "append tick-history *after* `ExitWorktree`, never before." | ||
| 2. Pre-commit hook: if a commit modifies `docs/hygiene-history/loop-tick-history.md` AND the branch is not `main`/`round-NN-speculative`, refuse. | ||
| 3. A helper function `append-tick-history.sh` that `cd`s to main root before writing. |
There was a problem hiding this comment.
P1 (xref): The referenced hygiene-history path docs/hygiene-history/loop-tick-history.md (and the docs/hygiene-history/ directory) doesn’t exist in the repo. If the canonical append-only history is stored elsewhere (e.g., ROUND-HISTORY or another log), please update the reference; otherwise mark this as a proposed new file path rather than an existing one.
| A worktree is a separate working directory. Files that are auto-appended-to every tick (e.g. `docs/hygiene-history/loop-tick-history.md`) will diverge between the worktree and main if the tick runs in the worktree. | |
| **Example of the hazard (this tick almost hit it):** I entered `pr32-markdownlint` worktree on `round-42-speculative`. If I had written to `docs/hygiene-history/loop-tick-history.md` *from within the worktree* instead of *from the main repo*, the entry would have landed on the wrong branch and wrong working-tree copy. Then at tick close, the main repo wouldn't reflect the tick. | |
| **Class-detector:** tick-history appends must happen in the main repo, not inside a worktree. Enforcement options: | |
| 1. CLAUDE.md rule: "append tick-history *after* `ExitWorktree`, never before." | |
| 2. Pre-commit hook: if a commit modifies `docs/hygiene-history/loop-tick-history.md` AND the branch is not `main`/`round-NN-speculative`, refuse. | |
| 3. A helper function `append-tick-history.sh` that `cd`s to main root before writing. | |
| A worktree is a separate working directory. Files that are auto-appended-to every tick (for example, the canonical tick-history log, wherever it lives in the repo) will diverge between the worktree and main if the tick runs in the worktree. If the project later creates `docs/hygiene-history/loop-tick-history.md`, treat that as a proposed path, not a current one. | |
| **Example of the hazard (this tick almost hit it):** I entered `pr32-markdownlint` worktree on `round-42-speculative`. If I had written to the canonical tick-history log *from within the worktree* instead of *from the main repo*, the entry would have landed on the wrong branch and wrong working-tree copy. Then at tick close, the main repo wouldn't reflect the tick. | |
| **Class-detector:** tick-history appends must happen in the main repo, not inside a worktree. Enforcement options: | |
| 1. CLAUDE.md rule: "append tick-history *after* `ExitWorktree`, never before." | |
| 2. Pre-commit hook: if a commit modifies the canonical tick-history log and the branch is not `main`/`round-NN-speculative`, refuse. | |
| 3. A helper function `append-tick-history.sh` that `cd`s to main root before writing to the canonical tick-history log. |
| | Hazard | Preventive (structural) | Compensating (detector, permanent) | | ||
| |---|---|---| | ||
| | Live-lock (§2.1) | Scope-overlap registry + refusal | Merge-front throughput monitor; N-round stale-worktree audit | | ||
| | Merge conflicts (§2.2) | Scope discipline (same as §2.1) | Conflict-rate instrumentation; rework count | |
There was a problem hiding this comment.
P2: The markdown table in §3 has an extra leading | on each row (e.g., || Hazard | ...), which creates an empty first column in most renderers. Consider removing the extra pipe so the table renders as intended.
Summary
docs/research/parallel-worktree-safety-2026-04-22.md(223 lines).Hazard classes
Outcome
EnterWorktree-default flip.Test plan
docs/research/— inherits first-draft status per research-doc norms.🤖 Generated with Claude Code