dewey: row 69 round 1 review receipts, approve (#1562)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
# Row 69 round 1 review mutants (Dewey): each swaps one exact string in a scratch copy of the
|
||||||
|
# candidate, runs every packages/cli test in its own process group (killed after 300 s, which
|
||||||
|
# counts as a kill), and restores the file. The first five are the packet's own sites, rerun.
|
||||||
|
import subprocess, sys, os, signal
|
||||||
|
M = os.path.expanduser('~/dewey-scratch/r69mut')
|
||||||
|
env = dict(os.environ, TMPDIR=os.path.expanduser('~/dewey-scratch/tmp'))
|
||||||
|
S = 'packages/cli/src/screens.mjs'; A = 'packages/cli/src/app.mjs'
|
||||||
|
muts = [
|
||||||
|
('shown-no-min-cols', S, 'return cols >= MIN_COLS && rows >= MIN_ROWS && o?.kind', 'return rows >= MIN_ROWS && o?.kind'),
|
||||||
|
('n9-17000-end-off', S, '(n >= 0x17000 && n <= 0x18d08)', '(n >= 0x17000 && n <= 0x18cff)'),
|
||||||
|
('cut-drops-choice', S, 'const tail = b.slice(-2);', 'const tail = b.slice(-1);'),
|
||||||
|
('hidden-no-way-out', S, ', "Resize, or use mosaic decide."]', ']'),
|
||||||
|
('hidden-status-promises-y', A, 'const state = hidden ? {', 'const state = false ? {'),
|
||||||
|
('hidden for any overlay', A, 'const hidden = o?.kind === "decide" && !decideShown', 'const hidden = !decideShown'),
|
||||||
|
('hidden status written into state', A, 'hidden ? { ...this.state, status: "Too small to confirm here.", statusStyle: "warning" } : this.state', 'hidden ? Object.assign(this.state, { status: "Too small to confirm here.", statusStyle: "warning" }) : this.state'),
|
||||||
|
('hidden only while asking', A, 'o?.kind === "decide" && !decideShown(o, this.cols, this.rows)', 'o?.kind === "decide" && o.asking && !decideShown(o, this.cols, this.rows)'),
|
||||||
|
('hidden status muted', A, 'status: "Too small to confirm here.", statusStyle: "warning"', 'status: "Too small to confirm here.", statusStyle: "muted"'),
|
||||||
|
('way out only while asking', S, ', "Resize, or use mosaic decide."]', ', ...(o.asking ? ["Resize, or use mosaic decide."] : [])]'),
|
||||||
|
('draw too-small from 30 columns', S, 'if (cols < MIN_COLS || rows < MIN_ROWS) return tooSmall', 'if (cols < 30 || rows < MIN_ROWS) return tooSmall'),
|
||||||
|
]
|
||||||
|
tests = sorted('packages/cli/tests/' + f for f in os.listdir(os.path.join(M, 'packages/cli/tests')) if f.endswith('.test.mjs'))
|
||||||
|
for name, f, old, new in muts:
|
||||||
|
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))
|
||||||
|
proc = subprocess.Popen(['node', '--test', *tests], cwd=M, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, start_new_session=True)
|
||||||
|
try:
|
||||||
|
out, _ = proc.communicate(timeout=300)
|
||||||
|
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 300 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:90] for l in fails) + ')' if fails else ''), flush=True)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
killed shown-no-min-cols
|
||||||
|
killed n9-17000-end-off
|
||||||
|
killed cut-drops-choice
|
||||||
|
killed hidden-no-way-out
|
||||||
|
killed hidden-status-promises-y
|
||||||
|
killed hidden for any overlay
|
||||||
|
killed hidden status written into state
|
||||||
|
SURVIVED hidden only while asking
|
||||||
|
SURVIVED hidden status muted
|
||||||
|
SURVIVED way out only while asking
|
||||||
|
killed draw too-small from 30 columns
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
start 23:11:03Z
|
||||||
|
node cli rc=0 ℹ pass 123 ℹ fail 0
|
||||||
|
node queue rc=0 ℹ pass 150 ℹ fail 0
|
||||||
|
suites end 23:11:55Z
|
||||||
|
mutants rc=0 end 23:15:24Z
|
||||||
|
mut copy restored, manifest OK
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
**Dewey: approve, round 1, candidate manifest `c68e65828726b4f15cc0e0f231a26ea30e7dc30789aad145edc15b3995921c4b`**
|
||||||
|
|
||||||
|
Every item the brief ships is there and tested, and the code change stays inside the two places the brief allows: the hidden box's text in `screens.mjs` and the status line while the box is hidden in `app.mjs`.
|
||||||
|
|
||||||
|
**What I checked**
|
||||||
|
|
||||||
|
- `build.patch` (packet `544563e3`) applied with `git apply --index` to a detached worktree of `dad20531` checks 4/4. None of the four paths changed between `dad20531` and `refactor` `6e1f9335`.
|
||||||
|
- On the candidate, sequentially, 23:11:03-23:11:55Z, both rc=0: cli 123, queue 150. Same counts as your gate.
|
||||||
|
- The narrow-terminal test sweeps 30-39 columns at 33-60 rows, plain and long, and asserts `decideShown` is false and the frame is the too-small screen; with your fixed sizes it also checks that `y` sends nothing. That covers what the brief asked for.
|
||||||
|
- The hidden-box test pins the way-out line, the status text, no "with y" on screen, the box whole at 40x10, the status coming back when the terminal grows, and `y` sending no `decision.resolve`.
|
||||||
|
- I accept the two shorter texts for the reason your packet gives: the brief's sentence wraps at 40x10 and the general cut would drop "Any key answers No.". Sage accepted them too.
|
||||||
|
- README: the row count now reads as an example for a plain decision, and the too-small rule under 40 columns is stated.
|
||||||
|
|
||||||
|
**Mutants**
|
||||||
|
|
||||||
|
`mutants.py` and `mutants.txt` here. A scratch copy of the candidate, every `packages/cli` test per mutant, each run in its own process group with a 300 s limit. None hung. Afterwards the copy matches the manifest again. Five are your sites, rerun; six are mine. 8 of 11 are killed.
|
||||||
|
|
||||||
|
| Mutant | Result |
|
||||||
|
|---|---|
|
||||||
|
| your five: `shown-no-min-cols`, `n9-17000-end-off`, `cut-drops-choice`, `hidden-no-way-out`, `hidden-status-promises-y` | killed |
|
||||||
|
| the status swap for any overlay, not only decide | killed |
|
||||||
|
| the hidden status written into `this.state` instead of a render-only copy | killed |
|
||||||
|
| `draw()`'s too-small screen from 30 columns instead of 40 | killed |
|
||||||
|
| the status swap only while `o.asking` | SURVIVED |
|
||||||
|
| the way-out line only while `o.asking` | SURVIVED |
|
||||||
|
| `statusStyle: "warning"` to `"muted"` | SURVIVED |
|
||||||
|
|
||||||
|
**Non-blocking notes**
|
||||||
|
|
||||||
|
1. The two `o.asking` survivors are the same gap: no test hides the box while it is resolving (after an answer, before the result). In that state the box shows "resolving…" plus the way out, and the status line says "Too small to confirm here.", which replaces whatever status the app set for the pending answer even though nothing is left to confirm. It is brief, the box closes when the result comes, and the brief's "while the box is hidden" reads as covering it. A test that resizes during a pending resolve would pin whichever text you want there.
|
||||||
|
2. The status line's style isn't tested; a mutant to `muted` survives. Cosmetic.
|
||||||
|
3. The cut help line pointing at `mosaic inbox --json`, which you found and left in `draw()`, is the follow-up Sage already noted.
|
||||||
|
|
||||||
|
Landing note: row 69 touches only `packages/cli`, nothing under `packages/webui/src/public/`, so decision 123 doesn't apply. The cli is live in the canonical checkout (decision 109), so Mos hears before the landing.
|
||||||
Reference in New Issue
Block a user