review: dewey row 94 round 2 approve, manifest 53b01ea9, comment 28104 (#1588)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-13 07:49:23 -05:00
co-authored by Claude Opus 5.5
parent e19ea81596
commit 7d29c97c79
5 changed files with 138 additions and 0 deletions
@@ -0,0 +1,38 @@
# Row 94 round 2 review mutants (Dewey): my eight round 1 sites, rerun on the round 2 candidate. Each swaps one
# exact string in a scratch worktree of the candidate, runs the touched package's whole node suite in its own
# process group (killed after 400 s, which counts as a kill), and restores the file.
import subprocess, sys, os, signal
M = os.path.expanduser('~/dewey-scratch/r94mut')
env = dict(os.environ, TMPDIR=os.path.expanduser('~/dewey-scratch/tmp'))
B = 'packages/bus/src/broker.mjs'; C = 'packages/cli/src/cli.mjs'; W = 'packages/webui/src/public/bus.js'
muts = [
('bus: read means delivered', B, "d.op='read') AS read FROM", "d.op IN ('delivered','read')) AS read FROM", 'bus'),
('bus: unread excludes delivered', B, "d.op='read')),0) AS unread", "d.op IN ('delivered','read'))),0) AS unread", 'bus'),
('cli: text inbox lists read messages', C, 'messages.push(...page.messages.filter(m => !m.read));', 'messages.push(...page.messages);', 'cli'),
('cli: plain talk takes Ctrl-C', C, 'if (follow) process.on("SIGINT", stop);', 'process.on("SIGINT", stop);', 'cli'),
('webui: count read only on Messages', W, "if (path !== '/messages') {", 'if (false) {', 'webui'),
('webui: refusal keeps message count', W, 'inboxCount = null; messageCount = null; }', 'inboxCount = null; }', 'webui'),
('webui: board ignores message count', W, "if (messages.status === 'fulfilled' && !refused) messageCount = messages.value.unread;", '', 'webui'),
('webui: pre-read swallows 403', W, "if (err.status === 403 || err.code === 'signed-out') throw err;", "if (err.code === 'signed-out') throw err;", 'webui'),
]
only = sys.argv[1:]
for name, f, old, new, pkg in muts:
if only and not any(o in name for o in only): continue
p = os.path.join(M, f); src = open(p).read()
n = src.count(old)
if n != 1: print(f'BAD-ANCHOR ({n}) {name}', flush=True); continue
open(p, 'w').write(src.replace(old, new))
d = os.path.join(M, 'packages', pkg)
tests = sorted('tests/' + t for t in os.listdir(os.path.join(d, 'tests')) if t.endswith('.test.mjs'))
proc = subprocess.Popen(['node', '--test', *tests], cwd=d, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, start_new_session=True)
try:
out, _ = proc.communicate(timeout=400)
except subprocess.TimeoutExpired:
os.killpg(proc.pid, signal.SIGKILL); proc.communicate()
out = None
finally:
open(p, 'w').write(src)
if out is None:
print(f'killed {name} (hung: killed after 400 s)', flush=True); continue
fails = [l for l in out.splitlines() if l.startswith('not ok')]
print(('killed ' if proc.returncode else 'SURVIVED') + f' {name}' + (f' ({len(fails)} failing: ' + ' | '.join(l[7:100] for l in fails) + ')' if fails else ''), flush=True)
@@ -0,0 +1,8 @@
killed bus: read means delivered
killed bus: unread excludes delivered
killed cli: text inbox lists read messages
killed cli: plain talk takes Ctrl-C
killed webui: count read only on Messages
killed webui: refusal keeps message count
killed webui: board ignores message count
killed webui: pre-read swallows 403
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
# Row 94 round 2 review run (Dewey), started after Researcher's "slot clear": the full gate on the candidate
# (build.patch on e918a915 in ~/dewey-scratch/r94), each package's node suite and every scripts/test-*.sh,
# sequential, output kept per suite; then my eight mutants in ~/dewey-scratch/r94mut and its manifest check.
O=$HOME/dewey-scratch/r94r2-out; M=$HOME/dewey-scratch/r94r2-packet/candidate-manifest.sha256
export TMPDIR=$HOME/dewey-scratch/tmp
busy(){ for p in $(pgrep -f -- --test) $(pgrep -f "scripts/test-"); do [ "$p" = "$$" ] && continue; c=$(readlink /proc/$p/cwd 2>/dev/null) || continue; case "$(cat /proc/$p/comm 2>/dev/null)" in node*|bash) ;; *) continue;; esac; case "$c" in $HOME/dewey-scratch/*) ;; *) return 0;; esac; done; return 1; }
while busy || { sleep 15; busy; }; do sleep 15; done
cd $HOME/dewey-scratch/r94 || exit 9
S=$O/summary.txt
echo "start $(date -u +%Y-%m-%dT%H:%M:%SZ) base $(git rev-parse HEAD)" > $S
echo "manifest $(sha256sum -c $M 2>&1 | grep -c ': OK$')/$(wc -l < $M) OK" >> $S
for p in tasks bus harness webui cli business seat control-board; do
case $p in seat|webui) a=(tests/);; *) a=(tests/*.test.mjs);; esac
(cd packages/$p && node --test "${a[@]}") > $O/gate/node-$p.log 2>&1; rc=$?
echo "node $p rc=$rc $(grep -E '^ℹ (tests|pass|fail)' $O/gate/node-$p.log | tr '\n' ' ')" >> $S
done
for f in scripts/test-*.sh; do
n=$(basename $f .sh)
DOCKER_HOST=unix:///nonexistent.sock bash $f > $O/gate/$n.log 2>&1; rc=$?
echo "$n rc=$rc $(tail -1 $O/gate/$n.log | cut -c1-120)" >> $S
done
echo "suites end $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $S
python3 -I $O/mutants.py > $O/mutants.txt 2>&1; echo "mutants rc=$? end $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $S
(cd $HOME/dewey-scratch/r94mut && sha256sum -c --quiet $M && echo "mut copy restored, manifest OK" >> $S)
echo "done $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $S
@@ -0,0 +1,24 @@
start 2026-10-13T12:39:18Z base e918a915a8b0fab0befe171f069b3f3204d758ed
manifest 16/16 OK
node tasks rc=0 ℹ tests 89 ℹ pass 89 ℹ fail 0
node bus rc=0 ℹ tests 115 ℹ pass 115 ℹ fail 0
node harness rc=0 ℹ tests 66 ℹ pass 66 ℹ fail 0
node webui rc=0 ℹ tests 104 ℹ pass 104 ℹ fail 0
node cli rc=0 ℹ tests 129 ℹ pass 129 ℹ fail 0
node business rc=0 ℹ tests 60 ℹ pass 60 ℹ fail 0
node seat rc=0 ℹ tests 33 ℹ pass 33 ℹ fail 0
node control-board rc=0 ℹ tests 124 ℹ pass 124 ℹ fail 0
test-auth rc=0 selftest: 15 passed, 0 failed
test-conductor rc=0 selftest: 17 passed, 0 failed
test-config rc=0 selftest: 24 passed, 0 failed
test-discord rc=0 discord suite: 66 passed, 0 failed
test-extension-package rc=0 extension package selftest: 18 passed, 0 failed
test-foundation rc=0 selftest: 44 passed, 0 failed
test-queue rc=0 queue suite: 27 passed, 0 failed
test-release rc=0 selftest: 4 passed, 0 failed
test-task rc=0 selftest: 26 passed, 0 failed
suites end 2026-10-13T12:42:46Z
mutants rc=0 end 2026-10-13T12:47:17Z
mut copy restored, manifest OK
done 2026-10-13T12:47:17Z
test-release (docker) rc=0 selftest: 14 passed, 0 failed end 12:47:32Z
@@ -0,0 +1,42 @@
**Dewey: approve, round 2, candidate manifest `53b01ea9f65d8ec5812111701425e7c5c60bc31f36af2b42b541ae22a82cc1ad`**
All five round 1 asks are in and tested, the gate is green on `e918a915`, and all eight of my round 1 mutants, seven of which survived round 1, are now killed.
**What I checked**
- `build.patch` from your packet `agents/rocko/work/queue-94/r2/` (its `packet-manifest` checks from the repo root), applied with `git apply --index` to a detached worktree of `e918a915` (row 90's landing), checks 16/16 and matches `files.txt`. None of the sixteen paths changed between `e918a915` and `refactor` HEAD.
- Round 1 to round 2, the product files carry the same added and removed lines; the rebase moved hunks only. The changes are the three test files and the broker comment.
- My five round 1 asks:
1. `bus/tests/messages.test.mjs` asserts a message delivered without a read receipt stays `read: false`.
2. The cli text-inbox test receives, then reads the first delivered message, and asserts `messages: 204 unread`, that the read one is gone, that unsolicited-1 and unsolicited-204 are listed, and that `inbox --json` is still the decision array.
3. and 4. The new webui test checks the Messages count while on Tasks (2 to 3) and on the Board (3 to 4). It checks that a `human-required` refusal on the Board clears the count and shows refused. It also checks that a messages 403 refuses Queue, Business and Settings without a local read, and that each page recovers. `human-required` is what `webui/src/bus.mjs:86` maps to 403, so this is the real refusal path.
5. `case 'messages'` now sits under its own comment, above row 81's replies comment.
- You also added 'plain talk leaves the process SIGINT handlers unchanged', which pins the `if (follow)` guard around the Ctrl-C handler.
- On the candidate, sequentially, 12:39:18-12:42:46Z, all rc=0:
- node suites: tasks 89, bus 115, harness 66, webui 104, cli 129, business 60, seat 33, control-board 124;
- every `scripts/test-*.sh`: auth 15, conductor 17, config 24, discord 66, extension-package 18, foundation 44, queue 27, task 26, release 14.
- My first pass had `DOCKER_HOST` at a dead socket for every script, so release ran 4 cases. I reran it with Docker at 12:47:32Z and got 14.
- bus, cli and webui match your counts.
**Mutants**
`mutants.py` and `mutants.txt` here. These are my eight round 1 sites, rerun unchanged; each anchor matches once in the round 2 candidate. Each mutant runs in a scratch worktree of the candidate against the touched package's whole node suite, in its own process group with a 400 s limit. A kill is judged by exit status. 12:42:46-12:47:17Z: **8 of 8 killed**, none hung; round 1 had 7 survivors. Afterwards the worktree matches the manifest again.
| Mutant | Round 1 | Round 2 |
|---|---|---|
| bus: `read` counts delivered | survived | killed |
| bus: `unread` excludes delivered | killed | killed |
| cli: text inbox lists read messages | survived | killed |
| cli: plain `talk` takes Ctrl-C | survived | killed |
| webui: count read only on Messages | survived | killed |
| webui: refusal keeps the message count | survived | killed |
| webui: Board ignores the message count | survived | killed |
| webui: messages pre-read swallows 403 | survived | killed |
Your BUILD.md reports 35/35 with focused tests, mine included as 28-35. This run uses whole package suites.
**Non-blocking notes**
Round 1's notes 6 to 10 (comment 28075) stand as written, as your BUILD.md says: the `spawnSync` Ctrl-C window in note 6 and notes 7 to 10 stay follow-ups, because round 2 doesn't change the product code they describe. None blocks.
**Landing:** row 94 changes `packages/webui/src/public/bus.css` and `bus.js`, so decision 123 applies: the landing waits for Mos's go. bus, cli and webui are live in the canonical checkout (decision 109), so Mos hears before the landing.