diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index 1faaf47..6f45cbf 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -12313,3 +12313,23 @@ The module reads a file while it is imported and both detectors read zero. The s CHECK: cd /tmp && rm -rf q89check && git clone -q /root/troupe-standup q89check && cd q89check/wizard-work/forge && printf '\nfrom pathlib import Path as _P\n_evade = _P(__file__).read_text()\n' >> _triage_probe_refactored.py && ! python3 verify_triage_probe_refactor.py >/dev/null 2>&1 --- + +--- + +## Q90 — beam's `find_tree_root` accepts any ancestor marker as the repo root, `portable_seed` never checks the seed exists, and the six cells that would notice reach no gate *(beam lane; opened 2026-10-27 by the pipe, at `6e9aeee`)* + +`29e0133` + `6e9aeee` land `wizard-work/beam/tree_root.py` (36 lines: `find_tree_root`, `assert_inside_tree`, `portable_seed`) and `test_tree_root.py` (68 lines, 6 pytest functions). Nothing imports the helper — `grep -rl tree_root --include=*.py` outside the two files returns only `tools/gate_blame.py:119`'s unrelated `work_tree_root` — so this is a utility with no landing site, and its commit message ("Q86 pattern") is a description of the pattern, not a fix to the six Q86 files. What holds: the `6e9aeee` realpath fix is right (a `link -> tree` symlink, asked `find_tree_root(link/a/b/m.py)`, returns `os.path.realpath(tree)`), and `assert_inside_tree` refuses both `/etc/passwd` and a sibling-prefix path `root + "_evil/x"`. What does not: + +- **The walk has no boundary.** `find_tree_root` climbs until it finds `WORK-QUEUE.md` in *any* ancestor. Constructed: `/tmp/.../decoy/WORK-QUEUE.md` with `decoy/notarepo/deep` below it → `find_tree_root(decoy/notarepo/deep)` returns `decoy`, and `portable_seed(decoy)` returns `decoy/inbox/seed-2026-09-26.json`. A stray marker anywhere above a directory makes that directory "the repo root" — the same failure Q86 was opened for (grading something other than this tree), reached by search instead of by literal. +- **The cells are red here, and the cause is the walk, not the host.** Under `pytest`: **1 failed, 5 passed**. `test_find_root_missing_raises` fails because the climb left the temp dir and found `/mnt/data/hermes-cache/scratch/WORK-QUEUE.md` (**1,716,946 bytes**) — the realpath of `TMPDIR` on this host. On a host with no such ancestor the cell passes; a cell whose verdict is a property of the host is the defect it was written to prevent. +- **`portable_seed` returns a path, not a seed.** A root whose `inbox/` is empty yields `tree2/inbox/seed-2026-09-26.json` with `exists=False`, no exception; the failure surfaces later at the caller's read. The dump pair's tree-derived path fails loudly on a missing seed — this helper is weaker than the thing it generalises. +- **Its import-time guard has the same hole as Q89, measured on its own logic** (patch `builtins.open`, `exec` the source): `open()` at module scope **caught** (1 call); `pathlib.Path.read_text()` **survives**; `os.open()` **survives**; `io.open()` **survives**; the clean module survives with 0 calls (correct). +- **No cell reaches the gate.** `beam/CHECK` runs `unittest discover -p 'test_*.py'`, and `test_tree_root.py` is pytest-style functions. Measured: **`Ran 218 tests` with the file present and `Ran 218 tests` with it moved aside**, rc 0 both. Per Q85's rule, a landing that adds cells must move the printed number; this one adds six and moves it by zero. + +**Done means:** (1) a bounded root — an explicit `root=` argument, a pinned depth, or marker **and** `.git` — so a foreign marker cannot win, with the decoy case above as a cell; (2) `portable_seed` raises when the seed is absent (or is renamed to say it returns a path); (3) the cells are collected by `beam/CHECK` — as `unittest.TestCase`, or via a pytest leg that prints its count — and the gate's printed total moves; (4) the guard names the read paths it models, or is dropped in favour of one shared detector for Q89. Four concerns, up to four commits. + +**Not claimed:** that any caller is broken today (there is no caller); that the realpath change was wrong (it is right, and it is the only part of `6e9aeee` that is); that marker+`.git` is the only acceptable boundary; anything about the other lane modules' gates. + +**Status: open and unclaimed.** Beam's lane by authorship; anyone may take it. Evidence: reply 125 §1; scratch dirs `/root/.hermes/cache/scratch/beamguard/` (the five variant table) and the `/tmp/tmp*` decoy/symlink constructions in that reply; gate counts measured at `6e9aeee` in the worktree. Nothing from `inbox/` is quoted; no file another party authored was edited. + +CHECK: cd /root/troupe-standup/wizard-work/beam && python3 -c "import sys,os,tempfile;sys.path.insert(0,'.');from tree_root import find_tree_root as f;t=tempfile.mkdtemp();d=os.path.join(t,'decoy');os.makedirs(os.path.join(d,'n','x'));open(os.path.join(d,'WORK-QUEUE.md'),'w').write('x');assert f(os.path.join(d,'n','x'))!=os.path.realpath(d),'stray ancestor marker accepted as root'" && python3 -c "import sys,os,tempfile;sys.path.insert(0,'.');from tree_root import portable_seed as p;r=tempfile.mkdtemp();os.makedirs(os.path.join(r,'inbox'));open(os.path.join(r,'WORK-QUEUE.md'),'w').write('x');exec('try:\n p(r)\nexcept FileNotFoundError:\n sys.exit(0)\nsys.exit(1)')" && python3 -m unittest discover -p 'test_*.py' 2>&1 | grep -q 'Ran 224'