Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0090

ADR-0090: The git sentinel fails a test for its own mutations, not for sibling-worktree activity

field value
Status Proposed
Date 2026-10-11
Register factory (docs/adr, 4-digit ids)
Source docs/adr/0090-the-git-sentinel-fails-a-test-for-its-own-mutations-not-for-sibling-worktree-activity.md — recorded on branch docs/adr-register-0080-0085 at 3f68a11a5, not yet on master
Wiki register entry ADR-0090 (wiki status: Proposed)

← ADR-0089 · ADR-0091 →

The record

Status: Proposed · Date: 2026-10-11

Context

tests/plugins/git_sentinel.py guards the live repository against tests that mutate it, after the 2026-07 incident in which a test corrupted master. At session start it snapshots the bytes of four slots, then re-reads them in every test's teardown. Any byte difference is a hard failure, and its docstring says "do not weaken this check". The four slots:

Two of the four are shared by every worktree of the repository. Ordinary work in a sibling worktree rewrites them while a suite runs:

With up to six worktrees running suites in parallel, each such write fails whichever test happens to be in teardown in every other worktree. These are the "git_sentinel teardown errors" that B2 (feat/shared-ledger) reported and that were waved through as "outside my files". They are false positives, and they are not harmless:

Decision (proposed)

Keep the guard's purpose: no test may mutate the live repository. Change how it decides, from "a shared file's bytes changed" to "this test process mutated the repository":

  1. Prevent at the source. The sentinel installs an audit hook (sys.addaudithook, event subprocess.Popen). It raises immediately, before the process starts, when a test spawns git with a mutating subcommand against the live repository. The live repository is the effective cwd or -C path inside it, or GIT_DIR/GIT_WORK_TREE pointing at it. The mutating subcommands are: commit, config (without --get*/--list), branch with -d/-D/-m/-M/-c/-f or a new name, worktree, update-ref, tag, reset, checkout, switch, restore, merge, rebase, cherry-pick, revert, stash, gc, pack-refs, remote, push, fetch, pull, notes, replace and am.

    The failure names the call site. Today's check can only report a byte diff after the fact.

  2. Per-worktree slots stay byte-exact. HEAD and this branch's loose ref keep exact comparison. No sibling worktree can legitimately write them.

  3. Shared slots compare only what concerns this worktree.

    • packed-refs: compare only the line for refs/heads/<this branch>.
    • config: compare the parsed config with branch.<b>.* removed for every b other than this worktree's branch. Every other key stays exact, so a test that writes user.*, core.*, remote.* or this branch's section still fails.

Alternatives rejected

Consequences

Provenance

No other ADR is named in this record.

Rulings cited

None.

Specs cited

None (or no spec page exists for the ones named).