ADR 025 — Unborn-HEAD worktree creation fails loud, never degrades to no isolation¶
Status¶
Accepted
Context¶
Every task in snodo runs inside a fresh git worktree
(.snodo-worktrees/task_<id>/) branched off the resolved base branch, so the
agent cannot write to the operator's real working tree. On a repository with
no commits the base branch is unborn and does not resolve:
fatal: invalid reference: main
WARNING: Worktree creation failed — running WITHOUT isolation.
WARNING: No task branch will be created. Files change current working tree.
create_worktree propagated the git failure up to setup_for_task, which
swallowed it (except Exception → return None). The CLI path interpreted
None as "warning, continue", and the background-job path printed
Worktree: skipped (...). Both then executed the task in the operator's
working tree — a safety property lost by default, on the state every
greenfield repository starts in. The runbook (docs/runbooks/01) reproduced it
and recommended making an initial commit first; snodo kept running anyway.
Decision¶
-
A structural isolation failure raises, it never degrades.
create_worktreedetects an unborn HEAD (no resolvableHEADcommit) before issuing any git command and raisesWorktreeIsolationErrorwith actionable guidance (make an initial commit; or pass--no-isolation).setup_for_taskno longer swallows worktree-creation errors and returnsNone— the exception propagates to the caller. -
The CLI refuses to run without isolation unless the operator says so.
snodo runaborts (exit 1) with the guidance when no worktree could be established and--no-isolationwas not passed. The flag exists exactly so the degradation is an explicit human decision, never an implicit default. The run also records aworktree_isolation_failedaudit event. -
A background job is refused up front.
JobManager.submithas no operator at a console to read a warning, so when the worktree cannot be created the job is markedfailedandsubmit()raises — it is never spawned un-isolated in the project tree. -
--no-isolationis explicit only. It is a new CLI flag (snodo run --no-isolation); nothing sets it automatically.
Alternatives considered¶
- Create the initial commit automatically. Rejected: snodo's consent
boundary is
snodo init(ADR 014); committing on the operator's behalf outside that boundary is a write they did not request. - Keep the warning but require
--no-isolationon failure. Rejected as the primary behaviour: a warning that degrades a safety property is the failure mode this ADR is closing. Aborting is the honest default.
Consequences¶
snodo runon a fresh repository (no commits) now stops with guidance instead of running the agent against the user's real working tree.--no-isolationlets an operator deliberately accept a degraded run.- Background dispatch on a repository with no commits fails the job immediately and visibly rather than silently running un-isolated.
WorktreeIsolationErroris a distinct, catchable type; transient git failures still propagate as ordinary exceptions (the CLI fails loud on any worktree-creation failure, not just unborn HEAD).- Test suites that exercise job submission without a real git repo now mock
create_worktree.