Console shows the reply to a web send: bus `replies` read (human and
reader, message-not-found on unknown ids, oldest first, cap 50, writes
nothing), /api/bus/replies, the Sent receipt's reply list, talk's timeout
names only mosaic talk. Base ff11aa4b, 12 paths, manifest 12/12 on a fresh
worktree. Gate green 18:29-18:35Z; 17/17 mutants killed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
39 lines
3.7 KiB
Python
39 lines
3.7 KiB
Python
# Row 81 mutants: each swaps one exact string in the candidate copy, runs the named tests,
|
|
# restores the file, and reports killed (tests fail) or SURVIVED.
|
|
import subprocess, sys, os
|
|
M = os.path.expanduser('~/dewey-scratch/r81/mut')
|
|
env = dict(os.environ, TMPDIR=os.path.expanduser('~/dewey-scratch/tmp'))
|
|
B, W, C = 'packages/bus/tests/replies.test.mjs', 'packages/webui/tests/bus.test.mjs', 'packages/cli/tests/verbs.test.mjs'
|
|
SB = 'packages/webui/tests/send-browser.test.mjs'
|
|
muts = [
|
|
('broker: no human-required', 'packages/bus/src/broker.mjs', " case 'replies': {\n if (!s.human && !s.reader) fail('human-required');\n", " case 'replies': {\n", [B]),
|
|
('broker: no message-not-found', 'packages/bus/src/broker.mjs', " fail('message-not-found');\n return this.#store.all(\n `SELECT * FROM messages WHERE business=? AND in_reply_to=?", " (void 0);\n return this.#store.all(\n `SELECT * FROM messages WHERE business=? AND in_reply_to=?", [B]),
|
|
('broker: newest first', 'packages/bus/src/broker.mjs', 'in_reply_to=? ORDER BY seq LIMIT', 'in_reply_to=? ORDER BY seq DESC LIMIT', [B]),
|
|
('broker: cap 51', 'packages/bus/src/broker.mjs', 'LIMIT ${REPLIES}`', 'LIMIT ${REPLIES + 1}`', [B]),
|
|
('broker: reader not allowed', 'packages/bus/src/broker.mjs', "'credentials', 'replies'", "'credentials'", [B]),
|
|
('broker: no strict keys', 'packages/bus/src/broker.mjs', " keys(a, ['id'], ['id']);\n identifier(a.id);\n if (!this.#store.get('SELECT id FROM messages", " if (!this.#store.get('SELECT id FROM messages", [B]),
|
|
('views: subject arg', 'packages/bus/src/views.mjs', "client.call('replies', { id })", "client.call('replies', { subject: id })", [B, W]),
|
|
('serve: no id check', 'packages/webui/src/serve.mjs', " if (!subjectOk(arg)) return json(res, 400, { error: 'invalid-request', message: 'id must be a message id' });\n", "", [W]),
|
|
('serve: replies not a verb', 'packages/webui/src/serve.mjs', ", 'replies'", "", [W]),
|
|
('page: query as subject', 'packages/webui/src/public/bus.js', "verb === 'replies' ? 'id' : 'subject'", "'subject'", [SB]),
|
|
('page: no replies read', 'packages/webui/src/public/bus.js', "try { rows = await get('replies', r.id); } catch {}", "rows = [];", [SB]),
|
|
('page: no reset on send', 'packages/webui/src/public/bus.js', "receipt = { kind: 'sent', to, id: body.id, at: body.at }; replies = [];", "receipt = { kind: 'sent', to, id: body.id, at: body.at };", [SB]),
|
|
('page: no stale guard', 'packages/webui/src/public/bus.js', 'if (receipt === r) replies', 'if (true) replies', [SB]),
|
|
('page: cap note off by one', 'packages/webui/src/public/bus.js', 'replies.length >= REPLIES ?', 'replies.length > REPLIES ?', [SB]),
|
|
('page: body unescaped', 'packages/webui/src/public/bus.js', '<p class="s1-q">${txt(m.body)}</p>', '<p class="s1-q">${m.body}</p>', [SB]),
|
|
('page: failure shown as none', 'packages/webui/src/public/bus.js', "if (receipt === r) replies = Array.isArray(rows) ? rows : null;", "if (receipt === r) replies = Array.isArray(rows) ? rows : [];", [SB]),
|
|
('cli: old message', 'packages/cli/src/cli.mjs', 'and the next mosaic talk shows it`', 'and the next mosaic talk or mosaic inbox shows it`', [C]),
|
|
]
|
|
only = sys.argv[1:]
|
|
for name, f, old, new, tests 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))
|
|
try:
|
|
r = subprocess.run(['node', '--test', *tests], cwd=M, env=env, capture_output=True, text=True, timeout=600)
|
|
finally:
|
|
open(p, 'w').write(src)
|
|
print(('killed ' if r.returncode else 'SURVIVED') + f' {name}', flush=True)
|