Skip to content

Treat a redundant harness-path guard exclusion as a note, not a startup error - #62

Open
TON14 wants to merge 4 commits into
AMAP-ML:mainfrom
TON14:fix/guard-exclude-redundant
Open

Treat a redundant harness-path guard exclusion as a note, not a startup error#62
TON14 wants to merge 4 commits into
AMAP-ML:mainfrom
TON14:fix/guard-exclude-redundant

Conversation

@TON14

@TON14 TON14 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

What this does

Stops a run from refusing to start over a redundant guard_exclude_paths entry, and makes the .git refusal explain itself.

The annoyance

Operators reasonably list .lh-harness (or a run directory) in guard_exclude_paths for completeness — and the run died at startup with guard exclude path may not cover harness state. But harness-owned paths (config dir, runs root, logs, prompts) are already hidden from the snapshot unconditionally; the guard never watches them in the first place. A line that duplicates built-in behaviour is not a hole in the audit — failing the whole run over it is hostile.

Behaviour now

  • An exclusion equal to, or inside, a harness-owned path is skipped with a stderr note naming what it duplicates. The run starts.
  • An exclusion that covers harness state and sibling workspace content (runs over runs/run-1) is still fatal: that is wider than what the harness hides on its own — a real blind spot, not redundancy.
  • The .git refusal stands unchanged in substance: exclusion switches off the witness, not the agents' Bash access, and an unwatched .git means hooks, refs and history can be rewritten with no audit trace. The message now says that, and points out that the auditor's own legitimate git noise is already silenced via GIT_OPTIONAL_LOCKS=0.

Testing

Suite: 405 passed, 2 skipped. The old "harness path is rejected" test is split into its two real cases: redundant → note + run proceeds; covering-more → still rejected.

(CI here is ubuntu-only until the Windows platform work in #57 lands, same as #58/#59.)


Update (second commit): live runs surfaced two more guard/.git realities, both now addressed:

  1. Audits died over git lock traffic. The entire evidence in the failing episodes was changed: ['.git'] — one directory row, zero children. Since every child is manifested separately, a dir whose only delta is its own mtime with a clean subtree proves only that a transient entry (an index.lock) came and went. That's now a recorded note (verifier_workspace_dir_mtime_only), not an audit-invalidating mutation. A dir with dirty children stays a violation.
  2. Deliberate .git exclusion can now be said out loud. With several runs legitimately sharing one repository (each writing its own files, protection delegated to git history), every sibling commit lands in .git during someone's audit window — the guard turns parallelism into serial false alarms. The list form still refuses .git, but guard_exclude_git = true / --guard-exclude-git makes the trade-off explicitly: unmissable console line, and the effective exclusions are already recorded in every audited episode's metadata.

TON14 added 4 commits August 23, 2026 11:29
…up error

Operators reasonably list `.lh-harness` (or a run directory) in
guard_exclude_paths for completeness -- and the run refused to start,
even though harness-owned paths are never snapshotted in the first
place: the same set is already hidden unconditionally. A redundant line
is not a hole, so it is now skipped with a stderr note naming the path
it duplicates. What stays fatal is an exclusion that covers harness
state *and* sibling workspace content ("runs" over runs/run-1): that is
wider than what the harness hides on its own, a real blind spot rather
than redundancy.

The .git refusal stands -- exclusion switches off the witness, not the
agents' Bash access, and an unwatched .git means hooks, refs and history
can be rewritten with no audit trace -- but the message now explains
that instead of just forbidding, and points at GIT_OPTIONAL_LOCKS=0
already silencing the auditor's own legitimate git noise.
The PR's own history is the argument: the branch was verified green on each
platform by hand, and each round of hand-verification still found something
the other platform could not see (a POSIX-only test guard, a cmd.exe-only
command-line limit). A matrix of ubuntu + windows at both ends of
requires-python (3.10 and 3.14) makes that check automatic for every push and
pull request.

The suite needs no Node toolchain -- the Web bundle is a packaging artifact --
so the job is checkout, setup-python, `pip install -e ".[test]"`, pytest. The
Windows symlink fixtures skip themselves on runners without
SeCreateSymbolicLinkPrivilege, which is expected and green.
…ands

The windows-latest lanes exercise platform support this branch does not
carry: it is based on a main whose supervisor still calls os.killpg and
whose agent stubs are #!/bin/sh scripts, so those lanes fail on known
pre-existing breakage rather than on anything in this change. AMAP-ML#57 brings
the Windows support together with the full two-platform matrix; when it
merges, its version of this workflow supersedes this one.
… out loud

Live translation runs kept dying with "Auditor read-only violation" whose
entire evidence was `changed: ['.git']` -- one directory row, no children.
The snapshot manifests every child separately, so a directory whose only
difference is its own mtime with a clean subtree proves nothing durable
happened: a transient entry (a git lock, created and removed inside the
window) came and went. That is now a recorded note
(`verifier_workspace_dir_mtime_only`), not a mutation; a directory whose
children did change stays a violation, and the directory row rejoins the
mutation list alongside them.

Lock traffic was only half of the operator's reality. With several runs
legitimately sharing one repository -- each translating its own page,
protection deliberately delegated to git history -- every sibling commit
lands real objects in .git during someone's audit window, and the guard
turns parallelism into serial false alarms. The list form still refuses
".git" (a silent one-liner is too easy to cargo-cult), but the trade-off
can now be made out loud: `guard_exclude_git = true` /
--guard-exclude-git drops .git from snapshots, prints an unmissable
console line, and every audited episode already records the effective
exclusions in its metadata. The refusal message points at the switch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant