Commit a5f1618eb6c9d5faa4227234afe4e7338f686a38
1 parent
5098fbe4
Rewrite CLAUDE.md to reflect current repo state, not PH0-era scaffolding
The original CLAUDE.md described a pre-scaffolding repo with no commits and open questions about A-2/critical path -- stale since PH0. Updates it to point at git log as the actual status record, document the two independent unittest discover roots (src/ and supervisor/), the real backend_server.py CLI, the .graphlemon-worktrees/ isolation mechanism and its three real incident notes, and a full repo layout reflecting what's actually there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Showing
1 changed file
with
134 additions
and
63 deletions
CLAUDE.md
| 1 | # CLAUDE.md | 1 | # CLAUDE.md |
| 2 | 2 | ||
| 3 | -This file orients Claude Code when working in this repository. Read this first, then follow the | ||
| 4 | -pointers below — do not start writing code before reading `docs/development-plan.md` and the | ||
| 5 | -current Unit's coverage references in `docs/sdd/`. | 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + | ||
| 5 | +Read this first, then follow the pointers below — do not start writing code before reading | ||
| 6 | +`docs/development-plan.md` and the current Unit's coverage references in `docs/sdd/`. | ||
| 6 | 7 | ||
| 7 | ## What this is | 8 | ## What this is |
| 8 | 9 | ||
| @@ -18,80 +19,125 @@ the MVCP (Model/View/Controller/Process) methodology from `docs/graphlemon_archi | @@ -18,80 +19,125 @@ the MVCP (Model/View/Controller/Process) methodology from `docs/graphlemon_archi | ||
| 18 | equivalent input that produced the SDD. When they conflict, the SDD wins (it's newer and more | 19 | equivalent input that produced the SDD. When they conflict, the SDD wins (it's newer and more |
| 19 | detailed); if a conflict looks unresolved, stop and ask rather than picking one silently. | 20 | detailed); if a conflict looks unresolved, stop and ask rather than picking one silently. |
| 20 | 21 | ||
| 22 | +## Status: all 43 planned Units (U-001~U-043, PH0~PH5) are implemented and committed | ||
| 23 | + | ||
| 24 | +`docs/development-plan.md` and `docs/sdd/unit_matrix.json` describe the plan as it read at | ||
| 25 | +inception (2026-07-29) — they were **not** kept updated with "done" checkmarks as work landed, so | ||
| 26 | +don't treat their prose as a live status board. `git log --oneline` is the actual record: every | ||
| 27 | +Unit from U-001 through U-043 has a matching commit, plus many `U-0XX fix:`/`U-0XX follow-up:` | ||
| 28 | +commits for bugs found during real (not mocked) runs, plus a long tail of `graphlemon: <artifact | ||
| 29 | +type> for task <uuid>` / `graphlemon: auto-commit uncommitted changes for <id>` / `graphlemon: | ||
| 30 | +merge <id>` commits — those are graphlemon **actually self-hosting**: running its own | ||
| 31 | +Planner→Coder→Validator loop against its own repo (`target_folder_path` == this checkout, | ||
| 32 | +`src/paths.is_self_target()`), with the Deploy Supervisor (`supervisor/`) staging, health-checking, | ||
| 33 | +and cutting over its own code changes. PH5 (self-modification / auto-rollback) is real and running, | ||
| 34 | +not future work — see "Two things named Supervisor" below and `supervisor/self_hosting_e2e.py`. | ||
| 35 | + | ||
| 36 | +When a `development-plan.md` line and the actual code disagree about what's done, trust the code | ||
| 37 | +and `git log`, and — if it matters to the task at hand — flag the doc as stale rather than | ||
| 38 | +silently trusting either source. `development-plan.md`'s per-Unit "实现补充"/"真实 bug" notes | ||
| 39 | +(inline, added after-the-fact) are still valuable: they're a real incident log of bugs found | ||
| 40 | +during self-hosting runs and how they were fixed (e.g. worktree commits being silently dropped, | ||
| 41 | +`memory: project` writes landing on the wrong checkout) — read them before touching | ||
| 42 | +`supervisor/isolation/`, `src/work_node_run.py`, or anything worktree-related. | ||
| 43 | + | ||
| 21 | ## Where to start | 44 | ## Where to start |
| 22 | 45 | ||
| 23 | -1. Read `docs/development-plan.md` — Phase → Sub-phase → Unit breakdown (`docs/sdd/unit_matrix.json` | ||
| 24 | - is the machine-readable mirror). Work is organized as Development Units, each classified | ||
| 25 | - Value Path / Risk Gate / Enabler, each with explicit `depends_on` and a `done` criterion that | ||
| 26 | - references a specific REQ in `docs/sdd/06-验收与测试锚点.md`. | ||
| 27 | -2. The critical path starts at **U-001** (01-M schema) → U-002 → U-004 → ... Follow | ||
| 28 | - `development-plan.md` §3 "关键路径" — do not skip ahead to later Units even if they look more | ||
| 29 | - interesting; most have real `depends_on` edges. | ||
| 30 | -3. **U-004 (A-2 assumption) is the next unvalidated risk on the critical path.** A-1 (dynamic | ||
| 31 | - workflow programmatic invocation) was already spike-validated (`spikes/a1-dynamic-workflows/`, | ||
| 32 | - confirmed 2026-07-29). A-2 (Hermes profile SOUL.md/AGENTS.md migrating cleanly into | ||
| 33 | - `.claude/agents/*.md` without major rewrites) is not yet tested. Validate it early with a | ||
| 34 | - minimal spike (per `development-plan.md`'s explicit recommendation) rather than discovering | ||
| 35 | - problems after U-010/U-011 are fully built on top of it. | 46 | +1. Read `docs/development-plan.md` for the Phase → Sub-phase → Unit breakdown and the *design* |
| 47 | + rationale behind each piece — but see Status above before trusting any "done"/"depends_on" | ||
| 48 | + framing as current. `docs/sdd/unit_matrix.json` is its machine-readable mirror (also static). | ||
| 49 | +2. `docs/sdd/06-验收与测试锚点.md` has REQ-01 through REQ-15, the acceptance anchors every Unit's | ||
| 50 | + Done criterion cites. REQ-15 (PH5, Deploy Supervisor blue-green + auto-rollback) was added | ||
| 51 | + 2026-07-30 after the original REQ-01~14 set. | ||
| 52 | +3. For any specific behavior, prefer reading the actual module in `src/`/`supervisor/`/`agents/` | ||
| 53 | + over the plan doc — the plan doc records intent at write-time and known deviations, the code is | ||
| 54 | + truth. | ||
| 36 | 55 | ||
| 37 | ## Commands | 56 | ## Commands |
| 38 | 57 | ||
| 39 | -No build, lint, or test tooling exists yet — the repo is pre-scaffolding (PH0, no commits made | ||
| 40 | -yet). `supervisor/isolation/` has no test suite of its own (that's U-036); `docs/` and `spikes/` | ||
| 41 | -aren't packages. The one real executable entry point today: | 58 | +Two independent `unittest discover` roots — there is no single top-level `discover` that covers |
| 59 | +both (deliberately: `supervisor/` was added later as PH5 landed, see | ||
| 60 | +`development-plan.md`'s U-036 note): | ||
| 42 | 61 | ||
| 43 | ```bash | 62 | ```bash |
| 44 | -# A-1 spike: verify Claude Code dynamic workflows can be invoked headlessly (already validated, | ||
| 45 | -# kept here for re-running / reference — see spikes/a1-dynamic-workflows/RESULTS.md) | ||
| 46 | -./spikes/a1-dynamic-workflows/run-spike.sh /path/to/some/git/repo | 63 | +# graphlemon's own backend/schema/agent-orchestration code (441 tests as of U-043) |
| 64 | +python3 -m unittest discover -s src | ||
| 65 | + | ||
| 66 | +# Deploy Supervisor + the isolate/diff/apply library it depends on | ||
| 67 | +# (this also picks up supervisor/isolation/test_*.py — no separate invocation needed) | ||
| 68 | +python3 -m unittest discover -s supervisor -p "test_*.py" | ||
| 69 | + | ||
| 70 | +# single test | ||
| 71 | +python3 -m unittest src.test_work_graph_execute.SomeTestClass.test_method | ||
| 72 | +``` | ||
| 73 | + | ||
| 74 | +Both suites skip real-`claude`-subprocess tests by default (`skip_unless_env`, `src/test_support.py`) | ||
| 75 | +— those need `RUN_REAL_AGENT_E2E=1` and real API spend, e.g.: | ||
| 76 | + | ||
| 77 | +```bash | ||
| 78 | +RUN_REAL_AGENT_E2E=1 python3 -m unittest src.test_agent_e2e | ||
| 47 | ``` | 79 | ``` |
| 48 | 80 | ||
| 49 | -Once U-002/U-003 scaffold `src/`, tests run via stdlib `unittest` only (see Testing below) — there | ||
| 50 | -is no repo convention yet for a single-test invocation beyond the standard | ||
| 51 | -`python3 -m unittest path.to.test_module.TestClass.test_method`; don't invent a different pattern. | 81 | +`supervisor/self_hosting_e2e.py`'s own real end-to-end scenario (`run_self_hosting_closed_loop`, |
| 82 | +the literal 9-step self-development-feasibility.md walkthrough) is gated the same way in | ||
| 83 | +`supervisor/test_self_hosting_e2e.py` — do not invoke it casually; it does a real self-targeted | ||
| 84 | +Planner→Coder→Validator→stage→cutover→monitor run against **this repo**. | ||
| 85 | + | ||
| 86 | +No build step, no lint config, no package manager — pure stdlib Python, nothing to install. | ||
| 87 | + | ||
| 88 | +```bash | ||
| 89 | +# A-1 spike (already validated 2026-07-29, kept for reference/re-running) | ||
| 90 | +./spikes/a1-dynamic-workflows/run-spike.sh /path/to/some/git/repo | ||
| 91 | + | ||
| 92 | +# local console (U-007/U-008): backend serves the API, frontend is static no-build HTML/JS | ||
| 93 | +python3 -m src.backend_server --port 8000 # default --port 0 means OS-assigned (fine for tests, not for browsing) | ||
| 94 | +``` | ||
| 52 | 95 | ||
| 53 | ## Hard constraints (do not relitigate these — they're settled decisions) | 96 | ## Hard constraints (do not relitigate these — they're settled decisions) |
| 54 | 97 | ||
| 55 | - **Execution backend**: Claude Code ACP only (`claude -p ... --output-format json --json-schema | 98 | - **Execution backend**: Claude Code ACP only (`claude -p ... --output-format json --json-schema |
| 56 | <schema> --permission-mode auto`, no `--bare`, no `--dangerously-skip-permissions`). See | 99 | <schema> --permission-mode auto`, no `--bare`, no `--dangerously-skip-permissions`). See |
| 57 | - 05 §5.3, §5.3.1, §5.4. | 100 | + 05 §5.3, §5.3.1, §5.4. One documented gotcha: `--agent` + `--json-schema` together silently drop |
| 101 | + `structured_output` — see 05 §5.4.1.1 and `src/work_graph_plan.py`'s ```` ```json ```` fence | ||
| 102 | + parsing workaround. | ||
| 58 | - **Implementation language**: graphlemon's own backend/frontend/Deploy Supervisor are **pure | 103 | - **Implementation language**: graphlemon's own backend/frontend/Deploy Supervisor are **pure |
| 59 | stdlib Python** — no Flask/FastAPI/Express/Node.js, no npm build step. This mirrors the | 104 | stdlib Python** — no Flask/FastAPI/Express/Node.js, no npm build step. This mirrors the |
| 60 | predecessor project graphloop's convention. See 05 §5.7. (This constraint is on graphlemon's | 105 | predecessor project graphloop's convention. See 05 §5.7. (This constraint is on graphlemon's |
| 61 | own implementation only — it does NOT apply to the code graphlemon generates for target | 106 | own implementation only — it does NOT apply to the code graphlemon generates for target |
| 62 | projects, which follows whatever stack that target project uses.) | 107 | projects, which follows whatever stack that target project uses.) |
| 63 | - **Testing**: stdlib `unittest` only, no pytest/fixtures. Mock the `subprocess`/`claude -p` | 108 | - **Testing**: stdlib `unittest` only, no pytest/fixtures. Mock the `subprocess`/`claude -p` |
| 64 | - boundary in normal tests; real end-to-end tests that actually shell out to `claude` should be | ||
| 65 | - gated behind an explicit env var and skipped by default (mirror graphloop's | ||
| 66 | - `RUN_REAL_AGENT_E2E=1` pattern) — this project doesn't have that harness yet, build it as part | ||
| 67 | - of the relevant Unit rather than improvising a different pattern per test file. | ||
| 68 | -- **Isolation**: parallel coding nodes must use `git_worktree_ref`. If `target_folder_path` is | ||
| 69 | - graphlemon's own repo (self-hosting/self-modification, PH5 only), worktree is **unconditionally | ||
| 70 | - mandatory** even for serial single-node changes — see 05 §5.8. | 109 | + boundary in normal tests; real end-to-end tests that actually shell out to `claude` are gated |
| 110 | + behind `RUN_REAL_AGENT_E2E=1` (`src/test_support.py:skip_unless_env`, mirrors graphloop's | ||
| 111 | + precedent) — reuse that helper, don't invent a per-file variant. | ||
| 112 | +- **Isolation**: parallel coding nodes must use `git_worktree_ref` (`src/work_node_run.py`). If | ||
| 113 | + `target_folder_path` is graphlemon's own repo (self-hosting/self-modification), worktree is | ||
| 114 | + **unconditionally mandatory** even for serial single-node changes — see 05 §5.8, | ||
| 115 | + `src/paths.is_self_target()`. Worktree checkouts live at `.graphlemon-worktrees/<node_exec_id>/` | ||
| 116 | + **inside** the main repo's working tree while a node runs (gitignored — never let `git add -A` | ||
| 117 | + on `repo_path` pick one up mid-run). Before touching this code, read the three `U-013` incident | ||
| 118 | + notes in `development-plan.md` (uncommitted worktree changes silently dropped on merge, `memory: | ||
| 119 | + project` writes landing on the main checkout instead of the worktree, and the pathspec-vs-gitignore | ||
| 120 | + conflict that fixing the second one introduced) — `work_node_run.ensure_worktree_committed()` is | ||
| 121 | + the fix for all three; don't re-solve the same problem a fourth way. | ||
| 71 | 122 | ||
| 72 | ## Two things named "Supervisor" — do not confuse them | 123 | ## Two things named "Supervisor" — do not confuse them |
| 73 | 124 | ||
| 74 | 1. **"Supervisor(调度子 Agent)"** — an in-process monitoring node inside the Coder Work Graph | 125 | 1. **"Supervisor(调度子 Agent)"** — an in-process monitoring node inside the Coder Work Graph |
| 75 | (architecture doc, existing concept). Watches Work Node execution, triggers reflection/ | 126 | (architecture doc, existing concept). Watches Work Node execution, triggers reflection/ |
| 76 | rescheduling. Part of the Graph Engine itself. | 127 | rescheduling. Part of the Graph Engine itself. |
| 77 | -2. **"Deploy Supervisor"** — an independent OS process, entirely outside the Graph Engine, that | ||
| 78 | - handles blue-green deployment and automatic rollback when graphlemon modifies its own code | ||
| 79 | - (PH5 only). See `docs/supervisor-auto-rollback-design.md` for the full design and the | ||
| 80 | - disambiguation note at the top of that file. | 128 | +2. **"Deploy Supervisor"** (`supervisor/`) — an independent OS process (`python3 -m |
| 129 | + supervisor.deploy_supervisor`), entirely outside the Graph Engine, that handles blue-green | ||
| 130 | + deployment and automatic rollback when graphlemon modifies its own code. Fully implemented | ||
| 131 | + (U-034~U-043): `deploy_stage.py` (stage a candidate), `deploy_health_check.py` (poll for | ||
| 132 | + startup readiness, not one-shot — see U-038 fix), `deploy_cutover.py`, `deploy_monitor.py`, | ||
| 133 | + `deploy_rollback.py`. Fail-closed, never-auto-restart philosophy adapted (not imported) from | ||
| 134 | + graphloop's `hermes_watchdog.py`. See `docs/supervisor-auto-rollback-design.md` for the full | ||
| 135 | + design and the disambiguation note at the top of that file. | ||
| 81 | 136 | ||
| 82 | These are unrelated components that happen to share a root word in casual English. Identifiers | 137 | These are unrelated components that happen to share a root word in casual English. Identifiers |
| 83 | for #2 are always prefixed `c_deploy_supervisor_*` / `deploy_health_signal` — never abbreviate to | 138 | for #2 are always prefixed `c_deploy_supervisor_*` / `deploy_health_signal` — never abbreviate to |
| 84 | just "supervisor" in code or docs. | 139 | just "supervisor" in code or docs. |
| 85 | 140 | ||
| 86 | -## PH5 (Deploy Supervisor / self-hosting) is not in scope yet | ||
| 87 | - | ||
| 88 | -`docs/development-plan.md` PH5 (Units U-034~U-043) depends on PH4 closing first — self-modification | ||
| 89 | -safety only makes sense once the base system has passed full regression. Don't build any of | ||
| 90 | -U-034~U-043 before PH0-PH4 are done, even though the design (`docs/supervisor-auto-rollback-design.md`) | ||
| 91 | -and its four reusable isolation modules (`supervisor/isolation/`) are already staged. Those modules | ||
| 92 | -were adapted from graphloop and have had exactly one manual smoke test — they still need a real | ||
| 93 | -`unittest` suite (U-036) before anyone should trust them in a real rollback path. | ||
| 94 | - | ||
| 95 | ## Prior art worth reading, not worth copying wholesale | 141 | ## Prior art worth reading, not worth copying wholesale |
| 96 | 142 | ||
| 97 | `/Users/yibo/Documents/lemonAI/graphloop` is an earlier, unmaintained attempt at this same | 143 | `/Users/yibo/Documents/lemonAI/graphloop` is an earlier, unmaintained attempt at this same |
| @@ -104,20 +150,45 @@ worth reading for the "fail-closed, deterministic, never-auto-restart" supervisi | @@ -104,20 +150,45 @@ worth reading for the "fail-closed, deterministic, never-auto-restart" supervisi | ||
| 104 | (graphlemon's Deploy Supervisor deliberately extends this into auto-rollback rather than just | 150 | (graphlemon's Deploy Supervisor deliberately extends this into auto-rollback rather than just |
| 105 | auto-halt — see `docs/supervisor-design-comparison.md` for why). Do not import graphloop code | 151 | auto-halt — see `docs/supervisor-design-comparison.md` for why). Do not import graphloop code |
| 106 | directly; anything worth reusing has already been copied and adapted into this repo | 152 | directly; anything worth reusing has already been copied and adapted into this repo |
| 107 | -(`supervisor/isolation/`). | ||
| 108 | - | ||
| 109 | -## Repo layout (as of PH0, before scaffolding exists) | ||
| 110 | - | ||
| 111 | -- `docs/` — architecture, SDD, development plan (see above) | ||
| 112 | -- `docs/wireframes/` — static no-build HTML prototypes for the PH3 console views (`v_*.html`), referenced | ||
| 113 | - per-page from `docs/sdd/02-V-界面与交互.md` §2.1-2.13 — implementation starting point once PH3 begins, | ||
| 114 | - DOM/class names map 1:1 to that doc's field lists. | ||
| 115 | -- `supervisor/isolation/` — staged utility library (isolate/diff/apply), not yet wired to anything | ||
| 116 | -- `spikes/` — one-off validation spikes (currently just A-1) | ||
| 117 | -- `src/` (created by U-001) — graphlemon's own backend source (schema, then U-007+ HTTP/WebSocket server). | ||
| 118 | - **Not the same `src/` a target project already has in its own repo** — a target project's `src/` is | ||
| 119 | - its own pre-existing source tree; graphlemon does not create or restructure it (see 05-实施约束与依赖.md | ||
| 120 | - §5.7 and architecture doc §13.2 — U-002 only creates `.graphlemon/` inside a target project, corrected | ||
| 121 | - 2026-07-31 after finding development-plan.md's U-002 line had cited the wrong architecture section). | ||
| 122 | -- Everything else (`.claude/agents/`, `skills/`, `runs/`, per-target-project scaffolding) gets created by | ||
| 123 | - U-002/U-003 — it doesn't exist yet, and that's expected at this stage. | 153 | +(`supervisor/isolation/`, adapted verbatim per the U-036 note in `development-plan.md`). |
| 154 | + | ||
| 155 | +## Repo layout | ||
| 156 | + | ||
| 157 | +- `docs/` — architecture doc, SDD (`docs/sdd/`), development plan, self-hosting design docs. See | ||
| 158 | + Status above for how stale the plan/unit-matrix "done" framing is relative to the real code. | ||
| 159 | +- `docs/wireframes/` — static no-build HTML prototypes for the PH3 console views (`v_*.html`), | ||
| 160 | + referenced per-page from `docs/sdd/02-V-界面与交互.md` §2.1-2.13; DOM/class names map 1:1 to | ||
| 161 | + that doc's field lists. | ||
| 162 | +- `src/` — graphlemon's own backend: `schema.py` (17-table SQLite schema — the original 01-M 15 | ||
| 163 | + entities plus PH5's `deployment`/`deploy_health_signal`), `backend_server.py` (stdlib | ||
| 164 | + `http.server` HTTP API + WebSocket-ish log/event streaming, no third-party deps), the Org Graph | ||
| 165 | + layer (`org_node_trigger.py`, `org_node_lifecycle.py`, `org_loop_route.py`, `org_level_loop.py`), | ||
| 166 | + the Work Graph layer (`work_graph_plan.py`, `work_graph_execute.py`, `work_graph_orchestrate.py`, | ||
| 167 | + `work_node_run.py`), root-cause tracing (`root_cause_trace.py`), skills (`skill_update.py`, | ||
| 168 | + `skill_query.py`), budget/scheduling (`budget_guardrail.py`, `scheduler.py`), and `paths.py` | ||
| 169 | + (graphlemon's own runtime home — `~/.graphlemon` by default, override via `GRAPHLEMON_HOME`, | ||
| 170 | + deliberately outside this repo checkout so logs/db never enter this repo's own git history). | ||
| 171 | + **This is not the same kind of `src/` a target project has in its own repo** — a target | ||
| 172 | + project's own `src/` is its pre-existing source tree; graphlemon doesn't create or restructure | ||
| 173 | + it (05 §5.7, architecture doc §13.2). Each `src/x.py` has a same-directory `src/test_x.py` (and | ||
| 174 | + sometimes `src/test_x_e2e.py` for the gated real-agent variant) — that pairing is the repo | ||
| 175 | + convention, keep it when adding modules. | ||
| 176 | +- `supervisor/` — Deploy Supervisor process + its isolation library (`supervisor/isolation/`: | ||
| 177 | + `isolated_workspace.py`, `change_manifest.py`, `selective_apply.py`, `workspace_security.py`, | ||
| 178 | + adapted from graphloop). `supervisor/self_hosting_e2e.py` is the acceptance-scenario glue that | ||
| 179 | + wires Graph Engine scheduling + Deploy Supervisor into one real self-targeted run. | ||
| 180 | +- `agents/{coder,planner,validator}/SOUL.md` — original Hermes-profile identity docs, migrated | ||
| 181 | + 2026-07-31 (A-2 assumption, "部分成立" — Coder's needed real rewriting to drop a hardcoded | ||
| 182 | + Feishu API token and a `--dangerously-skip-permissions` self-invocation; Planner/Validator were | ||
| 183 | + near-verbatim). These are the source-of-truth prose; `.claude/agents/*.md` is the actual | ||
| 184 | + Claude-Code-discoverable wrapper (frontmatter: `skills:`/`memory: project`/`tools:`/`model:`) | ||
| 185 | + that Claude Code loads — if you change agent behavior, both need to move together, and the | ||
| 186 | + `.claude/agents/*.md` frontmatter comment block records exactly what changed between them. | ||
| 187 | +- `frontend/` — the PH3 console: static `index.html`/`app.js`/`style.css`, no build step, no npm. | ||
| 188 | +- `spikes/` — one-off validation spikes (`a1-dynamic-workflows/`, confirmed 2026-07-29). | ||
| 189 | +- `.claude/agent-memory/{coder,planner,validator}/` — per-agent `memory: project` files, tracked | ||
| 190 | + in git on purpose (architecture doc §8 decision: memory must leave a git trail, not be silently | ||
| 191 | + mutable local state). | ||
| 192 | +- `.graphlemon/runs/<task_id>/` — real Artifacts (brd/prd/sdd/benchmark/code_diff/test_report) | ||
| 193 | + from actual self-hosting runs against this repo. `.graphlemon-worktrees/` (gitignored, see | ||
| 194 | + Isolation above) is the transient per-node worktree checkout directory, not persistent state. |