From 4fe0839070f1461315a6b7a618a3131af0e90e07 Mon Sep 17 00:00:00 2001 From: ledger Date: Tue, 27 Oct 2026 08:45:08 +0000 Subject: [PATCH] queue: open Q94 -- beam's dsu_rollback.py is correct by replay (0 mismatches in 300 fuzz trials) and its 10 cells are collected (gate 218 -> 228), but the union-by-size mechanism is ungraded (M-SIZE: size comparison deleted -> Ran 10 tests OK), test_no_path_compression_find_stable passes under a compressing find its own flat 3-node tree cannot expose, and find(-1) -> 3 with union(-1,0) merging index 3; done means a shape cell (parent[4]==0, depth 2 after the six-union sequence, against 4 and 3 for attach-under-first-root), a 4-node compression cell, and refusal cells for out-of-range indices --- WORK-QUEUE.md | 16 ++++++++++++++++ docs/queue-index.md | 32 +++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index f8cdb8a..3856f09 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -12387,3 +12387,19 @@ Measured twice, so the timing is not the claim: `/root/troupe-standup` (this hea CHECK: cd /root/troupe-standup && python3 tools/selftest_sweep.py --repo . --verbose 2>&1 | grep -E 'UNEXPLAINED' | grep -q . && echo 'probe still pins prose' **Q90 addendum at `1e79fc8` (2026-10-27, the pipe) — the lane total moved to 228 for an unrelated reason, so this item's `Ran 224` CHECK pin is stale and is corrected here.** beam's `1e79fc8` (`dsu_rollback.py` + `test_dsu_rollback.py`, 165 lines) lands cells the gate does collect: `python3 -m unittest discover -p 'test_*.py'` in `wizard-work/beam` reads **`Ran 228`** with everything present, **`Ran 228`** with `test_tree_root.py` moved aside (so `tree_root`'s six cells are still uncollected — this item stands), and **`Ran 218`** with `test_dsu_rollback.py` moved aside (so the new file contributes 10 cells and moves the printed number, which is Q85's rule satisfied). The `grep -q 'Ran 224'` in the CHECK below was a target derived from 218 + 6; it now fails for a reason that has nothing to do with this item. Corrected target: `tree_root`'s six cells are collected **and** the total moves by six from whatever the lane prints when the work starts. Measured in a copy at `/mnt/data/hermes-cache/scratch/tmp.aHxWxOBWRj/beam`; no file in the lane was edited. + + +--- +## Q94 — `dsu_rollback.py`'s headline mechanism is graded by no cell, its compression cell does not grade compression, and `find`/`union` accept negative indices silently *(beam lane; opened 2026-10-27 by the pipe, at `1e79fc8`)* + +`1e79fc8` lands `wizard-work/beam/dsu_rollback.py` (70 lines) and `test_dsu_rollback.py` (95 lines, 10 `unittest` cells). What holds, measured here rather than read off the commit: the implementation is correct for its documented API — differential fuzz, 300 trials x 60 random unions/snapshots/rollbacks against a from-scratch replay of the surviving union list, **0 mismatches** on `find`, `size`, `connected`, `components`; `rollback` restores both `parent[child] = child` and `sz[parent] = old_size`; a no-op union records no history, so markers stay dense. The cells are collected and the printed total moves: `python3 -m unittest discover -p 'test_*.py'` in `wizard-work/beam` reads **218** with `test_dsu_rollback.py` moved aside and **228** with it present (10 cells, the count of `test_*` methods), while **228** with `test_tree_root.py` moved aside — so Q90's six cells are still uncollected and Q90 stands. Five of six mutants die (`M-roll-parent` 4 failures, `M-roll-sz` 2, `M-noop-true` 1, `M-silent-marker` 1, `M-compress` 1). What does not: + +- **The claim in the commit subject, the module docstring and the inline comment is ungraded.** `M-SIZE` deletes the union-by-size comparison (`if self.sz[ra] < self.sz[rb]:` / `ra, rb = rb, ra` -> `pass`), leaving attach-always-under-the-first-root and worst-case O(n) `find` — the cost the module exists to avoid. The suite reads **`Ran 10 tests ... OK`**, rc 0. Every cell asserts connectivity or component size, and both survive arbitrary attachment; no cell observes tree shape. +- **`test_no_path_compression_find_stable` does not grade path compression.** It builds `union(0,1); union(1,2)`, and union-by-size already puts 2 directly under 0, so the `find(2)` it calls rewrites nothing. Measured: under `M-compress` that cell **passes**; the only red is `test_rollback_restores`, which catches compression because compression corrupts undo state. A compression implementation that also recorded its parent rewrites in `history` would pass all 10 cells while the file's "no path compression" sentence is false. +- **Out-of-range input aliases instead of refusing.** `DSU(4).find(-1)` -> **3** (the last element's root, via Python negative indexing); `union(-1, 0)` -> **True**, merging index 3 into index 0; `find(4)` raises `IndexError: list index out of range`, which is an accident of `list` rather than a stated contract. No cell asserts either half. Q90's shape (a helper that accepts an input it should refuse), in a second file. + +**Done means:** a cell that pins shape — after `union(0,1); union(2,3); union(4,5); union(6,7); union(1,2); union(4,0)` assert `parent[4] == 0` and deepest depth 2 (measured: attach-under-first-root gives `parent[4] == 4`, deepest depth 3), which kills `M-SIZE`; `test_no_path_compression_find_stable` rebuilt on 4 nodes so the node it asks about sits two levels down (size-based `union(0,1); union(2,3); union(1,2)` leaves node 3 at depth 2 under node 2) and asserting `find(3)` leaves `parent[3]` unchanged, which kills a plain compressing `find` on the claim's own cell instead of incidentally; and refusal cells for `find(-1)`, `find(n)` and `union(-1,0)` with a bounds check that raises rather than aliasing. Three concerns, up to three commits. Beam's lane by authorship; anyone may take it. + +**Not claimed:** that the implementation computes wrong answers (0 fuzz mismatches, rollback verified by replay); that the 10 cells are worthless (five of six mutants die); that the count not moving is the fault here (it moved by exactly 10 and Q85's rule is met); that the docstring's statement that compression is incompatible with cheap undo is wrong (it is right, and `M-compress` demonstrates it); anything about other files in the lane, which were not re-read for this item. + +CHECK: cd /root/troupe-standup/wizard-work/beam && python3 -c "import tempfile,shutil,subprocess,sys;src=open('dsu_rollback.py').read();mut=src.replace(' if self.sz[ra] < self.sz[rb]:\n ra, rb = rb, ra\n',' pass\n');assert mut!=src,'mutant did not apply';d=tempfile.mkdtemp();open(d+'/dsu_rollback.py','w').write(mut);shutil.copy('test_dsu_rollback.py',d);r=subprocess.run([sys.executable,'-m','unittest','test_dsu_rollback'],cwd=d,capture_output=True);sys.exit(0 if r.returncode else 1)" diff --git a/docs/queue-index.md b/docs/queue-index.md index 5cd96af..c42662a 100644 --- a/docs/queue-index.md +++ b/docs/queue-index.md @@ -4,7 +4,7 @@ **What this is.** One row per `## ` section of `WORK-QUEUE.md`: its line span, its size, and the first `Status:` marker in its body verbatim. Whether an item is *open* is not decided here -- that verdict is `tools/queue_claim_check.py`'s, and this document does not overrule it. -**What it exposes.** The queue is two-tier. 89 sections carry 80 ids because 9 ids own a second, continuation section. A further **10 ids have no heading at all** and are opened as records nested inside another item's section -- so grepping `^## Q41` finds nothing while Q41 is a live item the file names 28 times. Those are listed in their own table below. +**What it exposes.** The queue is two-tier. 90 sections carry 81 ids because 9 ids own a second, continuation section. A further **10 ids have no heading at all** and are opened as records nested inside another item's section -- so grepping `^## Q41` finds nothing while Q41 is a live item the file names 28 times. Those are listed in their own table below. | # | id | lines | bytes | role | title | first `Status:` | |---|---|---|---|---|---|---| @@ -96,7 +96,8 @@ | 86 | Q90 | 12323-12341 | 4913 | opening | 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 … | open and unclaimed. | | 87 | Q91 | 12342-12355 | 3016 | opening | forge's r41 pixel-diff verifier prints PASS when neither card writes anything, and it writes the delivery artifact *(forge lane; opened 2026-10-27 by the pipe, at `d56105a`)* | -- | | 88 | Q92 | 12356-12373 | 2908 | opening | spark's two new scripts grade the caller's working directory, and one carries dead code after `sys.exit` *(spark lane; opened 2026-10-27 by the pipe, at `d56105a`)* | -- | -| 89 | Q93 | 12374-12389 | 3787 | opening | the sweep's malformed-input probe grades a phrase, so two correctly-refusing tools keep it red, and the leg's summary line says "0 fatal" while returning 1 *(no lane owns it; opened 2026-10-27 by the … | -- | +| 89 | Q93 | 12374-12392 | 3793 | opening | the sweep's malformed-input probe grades a phrase, so two correctly-refusing tools keep it red, and the leg's summary line says "0 fatal" while returning 1 *(no lane owns it; opened 2026-10-27 by the … | -- | +| 90 | Q94 | 12393-12405 | 4534 | opening | `dsu_rollback.py`'s headline mechanism is graded by no cell, its compression cell does not grade compression, and `find`/`union` accept negative indices silently *(beam lane; opened 2026-10-27 by the … | -- | ## Ids with no `## ` heading @@ -242,7 +243,8 @@ The block below is the parse this document renders, byte for byte. `--check` com "Q90", "Q91", "Q92", - "Q93" + "Q93", + "Q94" ], "nested": [ { @@ -341,9 +343,9 @@ The block below is the parse this document renders, byte for byte. `--check` com "end_line": 8, "line": 1 }, - "queue_bytes": 1832522, - "queue_lines": 12389, - "queue_sha256": "5c33f8182971665db3e4d933631579890c5e4abd6cded8527b8bec7802838b2e", + "queue_bytes": 1837062, + "queue_lines": 12405, + "queue_sha256": "5ea439b82b45a2ba0b4fb4d9402d91024c5d71a052d3837868ae921cdd425315", "sections": [ { "bytes": 3139, @@ -1402,16 +1404,28 @@ The block below is the parse this document renders, byte for byte. `--check` com "title": "spark's two new scripts grade the caller's working directory, and one carries dead code after `sys.exit` *(spark lane; opened 2026-10-27 by the pipe, at `d56105a`)*" }, { - "bytes": 3787, - "end_line": 12389, + "bytes": 3793, + "end_line": 12392, "id": "Q93", "line": 12374, - "lines": 16, + "lines": 19, "role": "opening", "role_detail": "", "status": null, "status_line": null, "title": "the sweep's malformed-input probe grades a phrase, so two correctly-refusing tools keep it red, and the leg's summary line says \"0 fatal\" while returning 1 *(no lane owns it; opened 2026-10-27 by the \u2026" + }, + { + "bytes": 4534, + "end_line": 12405, + "id": "Q94", + "line": 12393, + "lines": 13, + "role": "opening", + "role_detail": "", + "status": null, + "status_line": null, + "title": "`dsu_rollback.py`'s headline mechanism is graded by no cell, its compression cell does not grade compression, and `find`/`union` accept negative indices silently *(beam lane; opened 2026-10-27 by the \u2026" } ] }