change record: refuse a moved checkout and an unnamed sweep #231

Merged
vnprc merged 2 commits from agent/record-guards into master 2026-09-27 04:36:57 +01:00
Member

allod change record now refuses two things it used to do silently. If the checkout was switched to another branch after begin set it up, record names the branch it expected and the one actually checked out, and stops. In a shared checkout with no --files named, it lists the modified tracked files it would have swept in and stops; inside a begin -d worktree, which belongs to one agent, the bare record still stages every tracked change as before. Both refusals happen before anything is staged, so a refused record leaves the tree as it found it. The in-place default-branch flow with no begin is unchanged. The shell suite proves each case and the flake's go-checks passes. If it is wrong, revert the one commit.

Closes allod/tools#118

What changes

  • cmd/allod/change.go: changeRecord reads <git-dir>/allod-change-branch, the file begin -d and begin --resume write, and refuses on a mismatch with the current branch (exit 3). A missing file means begin was never called there, so nothing changes for the in-place flow. With no --files and in a main checkout (not a linked worktree, decided by the existing mainRepoDir helper), it refuses when git diff --name-only is non-empty, listing the paths (exit 7). This is the first reader of the handoff file; until now it was write-only.
  • cmd/allod/main.go, README.md: the usage text and the "Making a change" section state both refusals in plain words.
  • tests/allod-change.sh: new assertions for the moved checkout (refusal, both branch names, tree unchanged, no commit) and the sweep (refusal, paths named, nothing staged, no commit; allowed when named; unchanged in a worktree). Eight existing tests that modified a tracked file in a plain checkout with no --files now pass --files, since that is exactly what the guard refuses; two tests whose point is the bare git add -u default now run inside a begin -d worktree, where that default survives. No assertion was weakened.

Risk

R1. Two preflight refusals in one function; nothing new is staged, committed, or pushed. Rollback is a straight revert. One stated limit: the sweep check reads unstaged modifications, as the issue specified, so a change another agent had already staged with git add would still be included in a bare record. Naming files covers that case too.

Behavior change for existing habits: a bare allod change record -m ... in a shared checkout with unnamed edits now fails where it used to commit. git-workflow.md already instructs naming files there, so this moves that rule from prose into the tool.

Validation

  • nix build .#checks.x86_64-linux.go-checks: passed (Go tests for every package plus the shell suites against the built binary).
  • tests/allod-change.sh against a local build: 231 passed, 14 new assertions.
  • gofmt -l, go vet ./cmd/allod/: clean.
  • Not run: the --resume interaction beyond the existing resume test, which records on a resumed branch and still passes.
`allod change record` now refuses two things it used to do silently. If the checkout was switched to another branch after `begin` set it up, `record` names the branch it expected and the one actually checked out, and stops. In a shared checkout with no `--files` named, it lists the modified tracked files it would have swept in and stops; inside a `begin -d` worktree, which belongs to one agent, the bare `record` still stages every tracked change as before. Both refusals happen before anything is staged, so a refused `record` leaves the tree as it found it. The in-place default-branch flow with no `begin` is unchanged. The shell suite proves each case and the flake's `go-checks` passes. If it is wrong, revert the one commit. Closes allod/tools#118 ## What changes - `cmd/allod/change.go`: `changeRecord` reads `<git-dir>/allod-change-branch`, the file `begin -d` and `begin --resume` write, and refuses on a mismatch with the current branch (exit 3). A missing file means `begin` was never called there, so nothing changes for the in-place flow. With no `--files` and in a main checkout (not a linked worktree, decided by the existing `mainRepoDir` helper), it refuses when `git diff --name-only` is non-empty, listing the paths (exit 7). This is the first reader of the handoff file; until now it was write-only. - `cmd/allod/main.go`, `README.md`: the usage text and the "Making a change" section state both refusals in plain words. - `tests/allod-change.sh`: new assertions for the moved checkout (refusal, both branch names, tree unchanged, no commit) and the sweep (refusal, paths named, nothing staged, no commit; allowed when named; unchanged in a worktree). Eight existing tests that modified a tracked file in a plain checkout with no `--files` now pass `--files`, since that is exactly what the guard refuses; two tests whose point is the bare `git add -u` default now run inside a `begin -d` worktree, where that default survives. No assertion was weakened. ## Risk R1. Two preflight refusals in one function; nothing new is staged, committed, or pushed. Rollback is a straight revert. One stated limit: the sweep check reads unstaged modifications, as the issue specified, so a change another agent had already staged with `git add` would still be included in a bare `record`. Naming files covers that case too. Behavior change for existing habits: a bare `allod change record -m ...` in a shared checkout with unnamed edits now fails where it used to commit. `git-workflow.md` already instructs naming files there, so this moves that rule from prose into the tool. ## Validation - `nix build .#checks.x86_64-linux.go-checks`: passed (Go tests for every package plus the shell suites against the built binary). - `tests/allod-change.sh` against a local build: 231 passed, 14 new assertions. - `gofmt -l`, `go vet ./cmd/allod/`: clean. - Not run: the `--resume` interaction beyond the existing resume test, which records on a resumed branch and still passes.
allod change record could commit into a checkout another agent had moved
to a different branch, and in a shared checkout its default staging step
could sweep a concurrent agent's tracked edits into the commit, both
silently. record now compares the current branch against the branch
'begin' (or '--resume') recorded in the git-dir's handoff file and refuses
on a mismatch, and in a main checkout (not a linked worktree) it refuses
to stage tracked modifications that were not named with --files. Both
checks run before anything is staged, so a refusal leaves the tree
exactly as found. A missing handoff file means 'begin' was never called
there, so the in-place default-branch flow is unaffected, and 'git add -u'
stays the default inside a linked worktree, whose tree belongs to one
agent by construction.

Several existing record tests exercised the unnamed 'git add -u' sweep in
a plain checkout; they now pass --files, or run in a worktree where that
default still applies, since a bare checkout with tracked modifications
and no --files is exactly the case being refused.

Refs allod/tools#118
Author
Member

Owner request before merge: the added source comments are too verbose. Documentation moves to the README and usage text, not the source; remaining comments shrink to at most one line each, contract or trap only.

Owner request before merge: the added source comments are too verbose. Documentation moves to the README and usage text, not the source; remaining comments shrink to at most one line each, contract or trap only.
The comment blocks added for the moved-checkout and sweep guards
restated why the checks exist and what a caller should do about it,
which belongs in the README and usage text, not in source. Cut them to
nothing or to the one line that names a trap the obvious edit falls
into; the README and usage text already carry the rest.

Refs allod/tools#118
vnprc merged commit a5ca56137a into master 2026-09-27 04:36:57 +01:00
vnprc deleted branch agent/record-guards 2026-09-27 04:36:57 +01:00
Sign in to join this conversation.
No description provided.