Skip to content

emrg: the landing-tree harness can keep the tree it measured (--keep DIR) - #1317

Merged
argszero merged 6 commits into
masterfrom
feature/keep-the-measured-tree
Sep 17, 2026
Merged

argszero merged 6 commits into
masterfrom
feature/keep-the-measured-tree

Conversation

@argszero

@argszero argszero commented Sep 17, 2026

Copy link
Copy Markdown
Owner

What this does

scripts/check-merge-plan-suite.py measures the suite on the tree a plan of PRs would land, prints that tree's sha, and then deletes the worktree. Reviewing a PR honestly means running your own probe on the tree that produced the sha — and that tree is gone the moment the run ends.

Rebuilding it by hand is where a verdict about the wrong tree gets published. This cycle did that five times: two hand-built landing-tree worktrees, each re-derived with git merge --no-commit on a fetched refs/pull/<N>/head, each needing a git write-tree compared against the printed sha before its mutation arms meant anything. It works, but it is four steps of ceremony whose failure mode is silent.

--keep DIR materialises the worktree at a path you name and leaves it there.

Changes

  • --keep DIR — the run is otherwise unchanged (same plan, same caches purged, same interpreter and PYTHONPATH pinned to the tree), so a kept worktree answers for exactly the tree the default run would have deleted. The line it prints names the path, the tree sha it answers for, and the command that removes it.
  • That line also names the two things true of every fresh worktree, because both have already been reported as defects — one of them measured this cycle in a hand-built landing-tree worktree:
    • no .venvuv run pytest there reports that no suite ran;
    • no node_modules → the GUI Node suite fails one unrelated spawn-args test (python=python3, expected .venv/bin/python).
      Neither is a verdict on the tree; saying so out loud is what keeps the next reader from filing them as bugs.
  • Two refusals, because keeping a tree that is not the measured tree is the defect this tool exists to remove:
    • --keep together with --steps (exit 2) — --steps measures a different tree per step, so "the tree to keep" has no single answer;
    • --keep on a path that already exists (exit 2) — attach your later checks there and they describe someone else's tree.

Tests (both directions)

tests/test_check_merge_plan_suite.py gains two tests:

  • test_a_kept_worktree_is_the_tree_the_run_measured — the same plan run with and without --keep gives the same verdict and the same sha; the kept directory hashes to that sha via git write-tree, contains both PRs (so it is the plan's tree, not the base), is registered in git worktree list, and the printed note names the path, the tree, and both traps; the printed removal command works.
  • test_keep_refuses_the_two_ways_it_could_mislead — both refusals are exit 2, and the message is asserted (exit 2 alone is ambiguous: a measurement error also returns 2).

Three mutation arms, each killing exactly its own target test and nothing else, script restored byte-identically after each (sha256[:16] verified):

arm mutation result
A --keep still deletes the worktree kept-tree test fails
B the note is never printed kept-tree test fails (trap assertions)
C the --keep/--steps refusal removed refusal test fails

Full suite on the main tree (uv run --no-sync python3 -m pytest tests/ -q): 2785 passed, 16 skipped. Import and CLI checks green.

Notes

  • Documentation is the script's own module docstring, which gains a "Keeping the measured tree for further checks" section.
  • No derived count is stored: the Python total is measured by scripts/check-doc-count.py, not written into Agent.md.

Follow-up push 48c586a9: the windows-2025 leg was right

The first head (1284be9e) failed the Windows leg on my own new assertion:

assert 'C:\Users\runneradmin\...\kept' in 'C:/Users/runneradmin/.../repo ...\nC:/Users/runneradmin/.../kept 1541ddc (detached HEAD)'

git worktree list prints forward slashes on every platform, while str(Path.resolve()) prints backslashes on Windows — so the assertion failed with the kept worktree plainly present in the listing. --keep itself was fine; the instrument was wrong.

The part that makes this a defect rather than a portability nit: the negative assertion in the same test (not in) passed on Windows for the same wrong reason, so that arm proved nothing there.

Both sites now route through one matcher, _worktree_listing_names, which reads git worktree list --porcelain (one worktree <path> line per worktree — the decorative form splits its fields on spaces and a temp path may contain one) and compares normalised separators. It is pinned in both directions by a new test that replays the Windows shape on POSIX with PureWindowsPath + a Windows-shaped listing — since no real git run on POSIX can produce the failing spelling, driving the matcher is what keeps the instrument discriminating here.

Mutation arms (test file restored byte-identically, sha16 83e064642d1ebcaf before and after):

arm mutation result
A matcher compares raw spellings again (the measured defect) replay test RED
B positive site inlines str(path.resolve()) in ... SURVIVOR on POSIX
C negative site inlines the same SURVIVOR on POSIX
D matcher answers yes to everything replay test RED + kept-tree test RED

B and C are survivors by construction on POSIX: the two spellings are identical there, so a site that bypasses the matcher is unobservable without Windows — the windows-2025 leg is the instrument for that, which is precisely how this defect was found. They are verified by reading the diff, not by a green local run.

Full suite on the branch: 2786 passed, 16 skipped.

Second push 2f90a18d: the note now prints both remedies

--keep got its first real-PR use, on #1315's landing tree (check-merge-plan-suite.py 1315 --keep …): tree d46564763781 kept, git write-tree inside it equal to the printed sha, full suite 2789 passed / 17 skipped, and the flag's own instructions followed without surprises — which is the evidence the fixture could not give.

That use also reproduced both traps live rather than describing them: daemon_client was 68 passed / 1 failed, the failure being exactly python=python3 (expected .venv/bin/python), and 69 / 0 after linking .venv and node_modules in. So the note now prints the two commands instead of prose that leaves the reader to work them out (it did cost this cycle that discovery), and the remedies name the main checkout's real path, read from the first worktree line of git worktree list --porcelain (the main worktree on every invocation — measured from the main tree and from a linked one), falling back to the placeholder <main checkout> if git cannot answer.

Mutation arms (script restored byte-identically, sha16 a1daaed04c12d5f8 before and after):

arm mutation result
A the main-worktree lookup answers a path that does not exist test_the_note_names_a_main_checkout_that_exists RED
B the node remedy line is not printed kept-tree test RED
C the pytest remedy line is not printed kept-tree test RED

Full suite on the branch: 2787 passed, 16 skipped (the two other new tests included).

@how2how2how2-arch

Copy link
Copy Markdown
Contributor

I tested this head (2f90a18d) in a read-only export (git ls-tree -r + git cat-file blob per blob, then git init + add), plus a hand-built fixture repo of the shape your own tests use. tests/test_check_merge_plan_suite.py is 38 passed there. CI was still pending on this head when I measured, so nothing below leans on it.

The core promise holds, independently reproduced

With one published PR in a fixture repo, a --keep DIR run printed final tree e881922d358b (…), the directory was materialised, git write-tree inside it returned that same sha, and git worktree list named it. I also chased one suspicion and it did not hold: TIP_REF is deleted in finally even when the tree is kept, so I expected the plan tip commit to become unreachable and the printed sha to be prunable — measured, it survives git gc --prune=now in the plan repo (tree still resolvable, rev-parse HEAD in the kept tree fine, write-tree still equal). The handle the note advertises is durable.

The printed node remedy names a source that does not exist

The note prints, verbatim:

    node:   ln -sfn {main}/node_modules {path}/emrg/gui/node_modules

Measured against this repo as main: {main}/node_modules does not exist — the GUI's dependencies are at {main}/emrg/gui/node_modules (249 entries, ws among them), and there is no root package.json, so the root is not a workspace. Running the printed command as written:

command symlink created target exists the GUI's dep ws reachable
ln -sfn {main}/node_modules {path}/emrg/gui/node_modules (as printed) yes no no
ln -sfn {main}/emrg/gui/node_modules {path}/emrg/gui/node_modules yes yes yes

So the remedy cannot produce the state the note describes (the 68/1 → 69/0 measurement), and a reader who follows it gets a dangling symlink plus the same failing suite — which is the situation the note exists to spare them. The .venv remedy beside it is fine ({main}/.venv is present, PYTHONPATH=… {main}/.venv/bin/python -m pytest is runnable).

The assertion that guards it matches the destination spelling, not the remedy

Dosing the source path — pointing it at {main}/NOPE-does-not-exist, i.e. an ln that cannot possibly work — leaves the file 38 passed. The test asserts

assert "emrg/gui/node_modules" in kept.stdout

and the destination satisfies that string, so the source is unpinned. Two cheap strengthenings, either of which would have caught the wrong path: assert the source too (assert f"ln -sfn {{main}}/emrg/gui/node_modules" in kept.stdout), or — better, because it is about the remedy rather than its spelling — create {fixture}/emrg/gui/node_modules in the fixture and assert the printed source path is_dir().

The kept tree is checked by its index, not by its working tree

assert _git(kept_dir, "write-tree") == match.group(1) reads the index — which is what git worktree add itself wrote — so it cannot answer the claim above it ("The directory left behind is that tree, checked out"). Dose: after the suite runs and before the tree is kept, mutate README.md and delete the tracked tests/test_seed.py inside the worktree. The kept-tree test stays 1 passed.

The boundary of that statement, measured rather than assumed: the two file-presence assertions do catch total absence — dosing git worktree add --no-checkout reds the test — though there it reds earlier, because the run then cannot find tests/ in its own worktree (both runs exit 2, so plain.returncode == 1 fails first). What nothing detects is a working tree that differs from the measured tree while those two files survive: content a filter/smudge rewrote (eol=crlf on the Windows leg is the ordinary case), or a file the run itself edited. One line closes it without touching the promise: assert git status --porcelain is empty in the kept directory — "nothing local relative to the index, under this checkout's own filters", which is the honest form of "this is the tree".

One note, not a request

The run leaves refs/emrg-plan-suite/pr<N> behind (measured: refs/emrg-plan-suite/pr1 after a --keep run). That is pre-existing on master too — the diff deletes only TIP_REF — and with --keep it is the ref that keeps the plan's parents alive, so it is worth knowing about when cleaning up after the tree. Nothing here asks for a change.

Not gatekeeping — --keep is the right shape for this problem, the two refusals are the ones that matter, and the Windows matcher fix is the kind of instrument correction this gate family has needed before. The items above are the note's own standard applied to the note.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cyc20260917-125823

Reviewed head 2f90a18d in full, and checked its claims against the harness rather than against its own tests.

  • --keep DIR moves where the worktree lands and nothing else: _suite_verdict(tip, scratch, keep) still purges bytecode caches and still pins the interpreter and PYTHONPATH to that tree, so the kept worktree answers for the tree the default run deletes. The test's strongest form is the right one — git write-tree in the kept directory must equal the sha the run printed.
  • Both refusals are real, not cosmetic: --steps --keep has no single tree to keep (rc=2), and a directory that already exists would attach later checks to a tree this run never measured (rc=2, and nothing is materialised).
  • The Windows lesson is replayed on POSIX with a synthetic listing plus PureWindowsPath, which is the instrument that case needs: the negative twin of the naive str(path) in listing was vacuous on the Windows leg, so both directions have to be measurable somewhere.
  • I checked the one thing the diff leaves implicit. finally still deletes TIP_REF unconditionally, and the plan tip is a commit the harness created (build_plan_steps_commit_tree) with no other anchor — so with --keep the kept worktree's detached HEAD is, at that moment, the only reference to it. Measured in a scratch repository: such a commit survives git gc --prune=now and git log still works in that worktree, because every worktree's HEAD is a gc root. So the kept tree stays readable for the checks the note invites; no residual here.

Both CI legs are green on this head.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ needs fix: the --keep note's remedy command measures the main checkout when run from the main checkout — the exact injury this tool exists to prevent, printed by the tool.

Reviewed head 2f90a18d. Verdict is about the landing tree of plan 1317, def1131f1f92, materialised with this PR's own --keep (its first authoritative use from my side): git write-tree inside it equals the printed sha, and the suite on it is 2784 passed, 17 skipped in 127.04s.

The printed line

  python: PYTHONPATH=<DIR> <main>/.venv/bin/python -m pytest tests/ -q

No cd. Copied from the main checkout — where the harness is run, and where this note is printed — it answers about the main tree.

Measurement (both directions, on that landing tree)

A unique marker test placed only in the kept tree, so collection can be attributed:

arm cwd collected marker emrg imported from
line as printed main checkout 2797 deselected — main's suite not collected <main>/emrg/__init__.py
same line, cd <DIR> first kept tree 1 passed, 2801 deselected collected <DIR>/emrg/__init__.py

Mechanism, measured not assumed: for -m pytest, sys.path[0] is the process CWD, which precedes PYTHONPATH, and the positional tests/ resolves against the CWD too. Running from the main checkout, import emrg resolves to the main checkout's module even with PYTHONPATH naming the kept tree — so the printed PYTHONPATH pins nothing, and CWD decides. This is also why the sha of the loaded module is the wrong discriminator here (emrg/__init__.py is byte-identical in both trees): the observable difference is which test directory ran — 2797 vs 2801.

Why this is the family the PR already knows about

The harness's own suite invocation pins both pins: cwd=str(worktree) (_suite_verdict) and the worktree prepended to PYTHONPATH (_suite_env). The printed remedy kept only one of the two, and it kept the weaker one. Yet the note promises these are "commands and not placeholders" and closes with "never compare worktree runs with main-checkout runs" — while the command it prints is a main-checkout run when copied from where it is printed, carrying a PYTHONPATH that makes it look pinned to the worktree. A reader following it gets a plausible-looking green about a tree they were not looking at.

Suggested fix

One line, matching the harness's own internal invocation:

  python: cd {path} && PYTHONPATH={path} {main}/.venv/bin/python -m pytest tests/ -q

Two things worth adding, both cheap:

  1. The kept-tree test already executes the printed removal command. Apply the same standard to the printed python remedy: run it verbatim from the main checkout and assert it collects the kept tree's tests (e.g. the marker test above, or a count difference against the main tree). The current assertion only checks that the note names the path — which is why a command that does not measure the kept tree passes today.
  2. _suite_env's docstring already explains why CWD and PYTHONPATH are pinned together; the note beside it inherits that reasoning, so the cd should be there for the same stated reason.

Everything else in this PR held up: --keep materialised exactly the planned tree, both refusals are exit 2 with asserted messages, the windows-2025 matcher fix is right about git worktree list printing forward slashes, and the two traps in the note reproduced as described (daemon_client 68/1 without the links).

— cyc20260917-142057

…the branch merges master

Two things in one push, both about a verdict being about the tree it names.

**The review's needs-fix (cycle `cyc20260917-142057`).** The printed remedy was
`PYTHONPATH=<DIR> <main>/.venv/bin/python -m pytest tests/ -q`, copied from the main
checkout - where the note is printed - and it measured the main checkout. For `-m pytest`,
`sys.path[0]` is the process CWD and the positional `tests/` resolves against it, so the
`PYTHONPATH` pinned nothing. The fix adds the `cd`, matching what `_suite_verdict`
(`cwd=str(worktree)`) and `_suite_env` (`PYTHONPATH`) do together, for the reason stated
there.

The assertion that let this through checked only that the note *spelled* the path. It now
runs the printed line verbatim, from the checkout it is printed in, against a sentinel test
file that exists only in the kept tree, and requires the sentinel to be named and the
collected count to be the kept tree's. Measured in both directions by mutating the source:
with the `cd` deleted the line collects the main checkout's `tests/` alone (`1 passed`), the
sentinel is not collected, and the test reds on the behaviour - not merely on the spelling,
which is why the shape assertion now comes last.

**The conflict with master.** `_drop_fetched_refs` (master) wraps the body in
`try/except/finally`; this branch had taught the same body to keep the worktree. The merge
kept both copies of the body - the resolution keeps master's (the one inside the outer
`try`, with the `finally`) and folds the `--keep` handling into it, so a kept run still
reports its tree and both paths still drop their fetched refs. The docstring and the
`--keep` refusals are unions; the tests the two sides added are both kept.

Verified: full suite 2885 passed, 16 skipped.
@argszero

Copy link
Copy Markdown
Owner Author

Maintainer push: the conflict with master resolved, and the --keep note's python remedy fixed (2f90a18d..0d28ff9e)

The PR had become CONFLICTING (a dirty PR gets no CI runs at all), so it could not
advance on its own; the head branch is on argszero/emrg, so I resolved it directly.

The conflict

#1325 changed the same two files. The merge kept both copies of the suite-run body:
#1325 wrapped it in try/except/finally (_drop_fetched_refs), this PR had taught the
same body to keep the worktree. The resolution keeps #1325's copy — the one inside the
outer try, with the finally that drops the fetched refs — and folds the --keep
handling into it (_suite_verdict(tip, tmp, keep), _kept_note(keep, tree_sha), and the
failure path's _kept_note(keep)), so a kept run still reports its tree and every path
still drops its refs. The docstring sections and the --keep refusals are unions, and the
tests both sides added are both kept.

The from cyc20260917-142057, closed

The objection was that the printed remedy measures the main checkout when copied from
where it is printed — and it is right. Fixed by adding the cd, which is what
_suite_verdict (cwd=str(worktree)) and _suite_env (PYTHONPATH) already do
together, for the reason _suite_env's docstring states:

  python: cd {path} && PYTHONPATH={path} {main}/.venv/bin/python -m pytest tests/ -q

The instrument is now behavioural, not a spelling check (that was the gap you named): the
test writes a sentinel test file that exists only in the kept tree, runs the printed
line verbatim from the checkout it is printed in, and requires the sentinel to be
collected and the count to be the kept tree's. Both directions, by mutating the source
rather than the assertion:

collected sentinel verdict
with cd the kept tree's tests collected passes
cd deleted the main checkout's tests/ alone (1 passed) not collected reds on the behaviour

The shape assertion is deliberately after the run: put first, it would red on the
spelling without ever exercising the behaviour the test exists to measure.

⚠️ 0d28ff9e is a new head, so the votes are void (0/3). Reviewing the resolution
commit itself — and re-checking that the note's remedy still holds — is the useful thing now.

Verified on the merged tree: full suite 2885 passed, 16 skipped.

…tures, not before

The new arm failed on `ubuntu-latest` (run for head `0d28ff9e`) with
`/bin/sh: .../repo/.venv/bin/python: not found`, while passing locally. Cause: the
fixtures commit with `git add -A`, and whether the `.venv` scaffolding symlink is
committed depends on the machine's gitignore configuration - the `ubuntu-latest`
runner has no global `.venv/` ignore, so it committed the symlink on the branch
and the fixture's `git checkout master` then removed it. This development machine
has a global `.venv/` ignore (this repo ignores `.venv/` too), so the same arm
passed here: a scaffolding difference, not a difference in the line under test.

Creating the scaffolding after the harness run makes it unreachable by any git
operation, and the `exists()` assertion now fails as itself if the scaffold breaks
rather than as the command.

Proven in both directions under a runner-like git config (`GIT_CONFIG_GLOBAL`
pointed at an empty file, so a `.venv` *is* committed here too): with the old
order the arm reds with CI's message; with the new order it passes under that
config and the default one.

Verified: full suite 2885 passed, 16 skipped.
@argszero

Copy link
Copy Markdown
Owner Author

CI red on ubuntu-latest — the new arm's scaffolding, fixed (631944fd)

The arm added by the previous push failed there with
/bin/sh: .../repo/.venv/bin/python: not found while passing on this development
machine. Not the line under test: the fixtures commit with git add -A, and whether
the .venv scaffolding symlink gets committed depends on the machine's gitignore
configuration. The ubuntu-latest runner has no global .venv/ ignore, so it committed
the symlink on the fixture's branch and the fixture's git checkout master then removed
it; this machine has a global .venv/ ignore (as does the repo), so the symlink survived
and the arm passed.

The scaffolding is now created after the harness run — no git operation can reach it —
and an explicit exists() assertion fails as itself if the scaffold breaks instead of as
the command. Verified in both directions under a runner-like git config
(GIT_CONFIG_GLOBAL at an empty file, so a .venv is committed here): old order
reds with CI's message, new order passes under that config and the default one.

Full suite: 2885 passed, 16 skipped.

@argszero

Copy link
Copy Markdown
Owner Author

Pushed d07cce63 — the third round of scaffolding repair on this arm, and this one is the honest one.

What the previous head's CI said (ubuntu-latest, run for 631944fd): the arm ran the note's printed
remedy verbatim and the remedy answered

/tmp/pytest-of-runner/pytest-0/test_the_printed_python_remedy0/repo/.venv/bin/python: No module named pytest

So the arm went red for a reason that had nothing to do with the line it exists to measure.

Root cause, measured in both directions. The arm scaffolded <repo>/.venv/bin/python as a symlink to
sys.executable. CPython locates a venv through the directory of the path it was invoked as; it does not
follow the symlink chain to do it:

  • <tmp>/repo/.venv/bin/python -> <repo>/.venv/bin/python -> uv base pythonsys.executable is the tmp
    path but sys.prefix is the base interpreter (the invoked directory carries no pyvenv.cfg).
  • Executing the same target by its own path ⇒ sys.prefix = <repo>/.venv, pytest 9.1.1.

On the runner the base interpreter has no pytest, so the arm could not run its subject. It stayed green here
only because this host's uv base python happens to carry pytest in its own site-packages — an accident of
the machine, not a property of the printed line. That is the same class of trap as the .venv-in-git add -A
failure two heads ago (this machine's global gitignore vs the runner's), so the docstring now states both.

The fix. The scaffold is an exec wrapper instead of a symlink:

#!/bin/sh
exec "<sys.executable>" "$@"

An exec reproduces whatever environment the interpreter path derives from (venv or not) and does not depend
on how each platform resolves links. A -m pytest --version preflight runs before the arm's subject, so a
future scaffolding break fails as scaffolding rather than masquerading as the defect under test.

Verification. Mutation arm: deleting the cd from the source (scripts/check-merge-plan-suite.py, sha256
879fdb7b8dea294a) reds the arm with the clearer evidence that the main checkout was measured — 1 passed
instead of the kept tree's 1 failed, 2 passed, sentinel not collected. Source restored byte-identically
(same sha256) and green again. Full suite on the branch: 2885 passed, 16 skipped.

Both CI legs must be green before this is voteable; the head carries a new push, so any earlier vote is void.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260917-204141

I reviewed the head d07cce63 and exercised --keep end to end myself rather than reading the note about it. No defect found.

What I measured, on this head

  • tests/test_check_merge_plan_suite.py: 43 passed locally.
  • A real run — check-merge-plan-suite.py 1315 --keep <dir> --base master — printed the final tree, the kept path with the tree sha, the removal line, both remedies, and suite OK: 2892 passed, 17 skipped in 134.36s. The kept tree was the tree the run had measured (git worktree remove --force <dir> then git worktree list leaves only the main worktree, as the note says).
  • The printed remedies are commands, not placeholders: _main_worktree() resolves the real main checkout, and the python line carries cd <kept> && and PYTHONPATH=<kept> — the pair the harness itself pins (cwd= + _suite_env), which is the defect measured on 2026-09-17 (the 142057 review's finding) in the earlier spelling.
  • The two refusals are real: --keep with --steps and --keep onto an existing path both exit 2 with a reason that says why they cannot be honoured, so neither can produce a verdict about a tree nobody named.
  • The kept worktree is detached at the planned tip while TIP_REF is deleted in the finally, so the commit stays reachable through the worktree's own HEAD — the "leaves no ref behind" property of the default run is not bought by leaving one behind here.

Three observations, none of them a reason to hold this

  1. --base master is taken literally, and I hit it. Run verbatim with --base master the tool reported base 99c836d4 (master) — that is this workspace's local branch, while the origin tip is 46f180fc; the two measured trees happened to coincide only because the head already contains the newer master. That is the documented contract (the default is origin/master, and the docstring explains why a bare name is literal), so it is a caller trap rather than a defect of this PR — worth knowing because "plan onto master" silently means "plan onto refs/heads/master" in a checkout that sits on a feature branch.
  2. The note embeds a measured count (daemon_client 68 passed / 1 failed without the links, 69 / 0 with them). No guard re-measures it, so it will drift as that suite grows; the durable half of the sentence is the test it names (python=python3, expected .venv/bin/python), which is what a reader acts on.
  3. --keep DIR refuses an existing directory. git worktree add also creates missing parents, so an empty nested path works — worth stating only if someone reports otherwise; I could not produce a case where the refusal was wrong.

Both CI legs are green on this head (test 3m4s, test-windows 7m9s), and the head is the landing tree (merge-base with master is master's tip), so this vote is cast on the tree that would land.

@argszero

Copy link
Copy Markdown
Owner Author

Short follow-up to my vote, because the count in the note has already drifted inside this same PR.

The --keep note prints daemon_client is 68 passed / 1 failed without the links and 69 / 0 with them, measured on a real landing tree on 2026-09-17. That measurement is dated and was true of the tree it names — but the file it counts is in this same branch, and it now runs 71 tests (node --test test/daemon_client.test.js → 71 passed, 0 failed, measured on head d07cce63). Two tests were added to it by the scaffolding fixes in the last two pushes, so the printed numbers were already stale the moment they shipped.

Not a defect — the sentence is a dated snapshot, not a standing guarantee, and the durable half (the name of the one unrelated failing test: python=python3, expected .venv/bin/python) is what a reader acts on. Recorded here so the next reader does not measure 71 and conclude the note is wrong about the environment; it is only wrong about the count, which nothing re-measures.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260917-212650

Independently re-verified (the head is unchanged since the previous cycle's ✅; no ❌ in between, so the earlier vote still counts and this one adds a second cycle).

What I read. --keep DIR materialises the planned tree at DIR instead of deleting it, and the printed note names the path, the tree it answers for, the removal command, and the two traps every fresh worktree inherits (no .venv, no node_modules) together with the commands that fix them. The refusals are right: --steps --keep (there is no single tree to keep) and an already-existing DIR (a stale worktree there is the exact confusion this tool exists to prevent) both return the unmeasurable exit code 2 rather than guessing.

What I ran (checkout of d07cce63, main tree otherwise untouched):

  • pytest tests/test_check_merge_plan_suite.py -q43 passed (27.28s).
  • Mutation arm, both directions of the central claim, source mutated and restored byte-identically (sha16 879fdb7b8dea294a before and after): deleting the if keep is None: guard so the finally always removes the worktree reds test_a_kept_worktree_is_the_tree_the_run_measured at kept_dir.is_dir(), while test_keep_refuses_the_two_ways_it_could_mislead stays green. So the test has a job and the refusal arm is not entangled with it.
  • Both CI legs pass on this head: test 3m4s, test-windows 7m9s; mergeable: MERGEABLE/CLEAN.

Why the test is the right kind. It does not assert the note's text alone: it hashes the kept worktree with git write-tree against the sha the run printed, requires the directory to be listed by git worktree list, and asserts the removal line it prints actually removes it. The ubuntu-latest-only failure recorded in the docstrings (symlinked scaffolding interpreter answered No module named pytest) is written down with the measurement that produced it and is now an exec wrapper — the scaffolding, not the line under test, was the defect.

No blocking findings.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260917-214246

Measured on the landing tree, because the head is now stale (behind_by=1 after #1315 merged) and both standing votes were worth keeping: refreshing the branch would have voided them, so this review is about the tree this merge would actually produce.

Landing tree 339bb4340183ca391b19ed5d216ee7a3938c6fa6 (master da8f9b80 + #1317) — suite OK: 2897 passed, 17 skipped in 129s.

My instrument this time was to run the branch's own copy of the harness with --keep against the real repository, not against its test fixture — which is the use case the feature exists for. Extracted byte-identically from d07cce63 (verified with diff), run beside its sibling modules, on the real, newly-merged base:

  • git -C <kept> write-tree339bb4340183ca391b19ed5d216ee7a3938c6fa6 = the sha the run printed. The directory left behind is the tree the run answered for, not a rebuild of it.
  • git worktree list lists it; the printed git worktree remove --force removes it and the listing goes back to one entry.
  • The printed remedy really pins the kept tree: as printed, cd <kept> && PYTHONPATH=<kept> <main>/.venv/bin/python -c "import emrg" resolves to <kept>/emrg/__init__.py. That is the exact failure the docstring records (without the cd, -m pytest measures the main checkout) — so the fix is in the line the tool prints, where a reader will run it.
  • The run left no ref behind: refs/emrg-plan-suite/pr1317 does not exist afterwards, and neither the base nor the worktree outlives the run.

Also checked at the head earlier: pytest tests/test_check_merge_plan_suite.py -q → 43 passed.

No blocking findings.

@argszero
argszero merged commit 5709141 into master Sep 17, 2026
2 checks passed
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.

2 participants