mirror of
https://github.com/kunchenguid/no-mistakes.git
synced 2026-09-19 07:53:54 +08:00
7186c4b2ae
* feat(daemon): place run worktrees per repository Pipeline run worktrees are created under <NM_HOME>/worktrees/<repo>/<run>, outside every checkout. Directory-scoped toolchain configuration - mise, direnv - resolves by path ancestry, so none of it ever reaches a run worktree: an operator whose repositories are configured that way gets a run environment that does not match the one they develop in, and there is no way to move the worktree without moving NM_HOME for everything. Add a worktree_roots map to the global config: keys are registered checkout paths, values are absolute directories. A repository with an entry gets its run worktrees at <value>/<runID>. Placement is decided in exactly one place, internal/worktrees, and every consumer of a worktree path goes through it: run creation, parked-run resume, the fix-review step diff, startup cleanup, the run-cleanup and startup process sweeps, gate context classification, and eject. That package also owns the single path canonicalization the feature compares with, so a spelling that matches in one consumer matches in all of them. A configured root is the operator's own directory - it holds the mise.local.toml or .envrc that motivated pointing runs at it - so what may be touched there is bounded twice over. Cleanup and the process sweep consider only directories named like a run ID (uppercase ULIDs, as this daemon mints them); eject goes further and removes only the directories this repository's own run rows name, so a leftover from anything else survives. Validation makes the config incapable of expressing the case that would defeat both: two checkouts sharing a root, two spellings of one checkout, a non-absolute key or value, or a root equal to its checkout are all rejected at load time. `init --worktree-root` refuses a root inside the repository or inside <NM_HOME>/worktrees, and daemon startup reports a key that matches no registered checkout, which would otherwise silently place nothing. With no worktree_roots entries the resolved paths, the directories walked, and the processes matched are exactly what they were before. * no-mistakes(review): reject unusable worktree roots and record run placement * no-mistakes(review): sweep recorded run worktrees instead of configured roots * no-mistakes(review): bound startup sweep set and tighten placement validation * no-mistakes(review): resolve recorded run worktrees without consulting config * no-mistakes(review): sweep resumed run worktrees and refuse in-checkout roots * no-mistakes(review): align init placement checks and scope run validation * no-mistakes(review): detect worktree_roots key in document, narrow classifier * no-mistakes(review): tell operators to replace a re-pointed worktree_roots entry * no-mistakes(review): sweep before every worktree removal, compare paths by identity * no-mistakes(review): sweep at eject and tolerate unmigrated preflight schema * no-mistakes(review): sweep eject placements from one bounded process snapshot * no-mistakes(review): sweep startup cleanup from one process snapshot * no-mistakes(review): guide worktree_roots edits by document shape * no-mistakes(review): match the worktree_roots block's own indentation * no-mistakes(document): document configurable run worktree placement in stale doc owners * no-mistakes(review): refuse init registering configured roots; sweep default tree * no-mistakes(review): never rewrite a worktree_roots key nobody could read * no-mistakes(review): read block indent from unparseable config; refuse unloadable init * no-mistakes(review): drop unreachable unparsed-config guidance path * no-mistakes(document): document every-init worktree_roots refusals and root cleanup * no-mistakes: apply CI fixes * fix(daemon): fail closed when the registered-checkout list is unreadable The placement guard validated against an empty protected set when RepoWorkingPaths errored, so a configured root inside an unlisted registered checkout passed startup and run-creation validation and the run worktree dirtied that checkout. A guard that cannot see the set it protects must refuse: startup now reports the read failure instead of starting, and run creation fails that run with the cause recorded. The database is already open and migrated by the time either caller runs, so the failure is never routine. Raised by Greptile on the pull request; addressed as a follow-up commit per run custody. * no-mistakes(document): document unusable worktree_roots startup refusal in troubleshooting