filbert: row 90 round 1 review, approve 28021, probes and session
This commit is contained in:
@@ -0,0 +1 @@
|
||||
28021
|
||||
@@ -0,0 +1,137 @@
|
||||
[
|
||||
{
|
||||
"suite": "tasks",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 79",
|
||||
"\u2139 pass 79",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "bus",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 111",
|
||||
"\u2139 pass 111",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "harness",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 66",
|
||||
"\u2139 pass 66",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "webui",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 86",
|
||||
"\u2139 pass 86",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "cli",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 115",
|
||||
"\u2139 pass 115",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "business",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 60",
|
||||
"\u2139 pass 60",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "seat",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 27",
|
||||
"\u2139 pass 27",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "control-board",
|
||||
"rc": 0,
|
||||
"stats": [
|
||||
"\u2139 tests 124",
|
||||
"\u2139 pass 124",
|
||||
"\u2139 fail 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-auth",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"selftest: 15 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-conductor",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"selftest: 17 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-config",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"selftest: 24 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-discord",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"discord suite: 66 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-extension-package",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"extension package selftest: 18 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-foundation",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"selftest: 44 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-queue",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"queue suite: 27 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-release",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"selftest: 4 passed, 0 failed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"suite": "test-task",
|
||||
"rc": 0,
|
||||
"last": [
|
||||
"selftest: 26 passed, 0 failed"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
import os, subprocess, pathlib, datetime, json
|
||||
root=pathlib.Path.home()/"filbert-scratch/r90-review/wt"
|
||||
out=root.parent/"gate"
|
||||
out.mkdir(exist_ok=True)
|
||||
env=dict(os.environ, TMPDIR=str(pathlib.Path.home()/"filbert-scratch/tmp"), DOCKER_HOST="unix:///nonexistent.sock")
|
||||
rows=[]
|
||||
for package in ["tasks","bus","harness","webui","cli","business","seat","control-board"]:
|
||||
cwd=root/"packages"/package
|
||||
files=["tests/"] if package in ["seat","webui"] else [str(x.relative_to(cwd)) for x in sorted((cwd/"tests").glob("*.test.mjs"))]
|
||||
with (out/("node-"+package+".log")).open("w") as f:
|
||||
r=subprocess.run(["node","--test",*files],cwd=cwd,env=env,stdout=f,stderr=subprocess.STDOUT)
|
||||
log=(out/("node-"+package+".log")).read_text()
|
||||
stats=[s for s in log.splitlines() if s.startswith(("# tests ","# pass ","# fail ","ℹ tests ","ℹ pass ","ℹ fail "))]
|
||||
row={"suite":package,"rc":r.returncode,"stats":stats}; rows.append(row);print(json.dumps(row),flush=True)
|
||||
for script in sorted((root/"scripts").glob("test-*.sh")):
|
||||
with (out/(script.stem+".log")).open("w") as f:
|
||||
r=subprocess.run(["bash",str(script)],cwd=root,env=env,stdout=f,stderr=subprocess.STDOUT)
|
||||
log=(out/(script.stem+".log")).read_text()
|
||||
row={"suite":script.stem,"rc":r.returncode,"last":log.splitlines()[-1:]};rows.append(row);print(json.dumps(row),flush=True)
|
||||
(out/"summary.json").write_text(json.dumps(rows,indent=2)+"\n")
|
||||
raise SystemExit(any(x["rc"] for x in rows))
|
||||
@@ -0,0 +1,39 @@
|
||||
[
|
||||
{
|
||||
"name": "own keys replaced by inherited keys",
|
||||
"suite_rc": 0,
|
||||
"result": "survived",
|
||||
"independent_probe_rc": 1
|
||||
},
|
||||
{
|
||||
"name": "most approved ids omitted",
|
||||
"suite_rc": 0,
|
||||
"result": "survived",
|
||||
"independent_probe_rc": 1
|
||||
},
|
||||
{
|
||||
"name": "load unchecked",
|
||||
"suite_rc": 1,
|
||||
"result": "killed"
|
||||
},
|
||||
{
|
||||
"name": "unknown requirement accepted",
|
||||
"suite_rc": 1,
|
||||
"result": "killed"
|
||||
},
|
||||
{
|
||||
"name": "read permits a nonholder",
|
||||
"suite_rc": 1,
|
||||
"result": "killed"
|
||||
},
|
||||
{
|
||||
"name": "tool points at tasks",
|
||||
"suite_rc": 1,
|
||||
"result": "killed"
|
||||
},
|
||||
{
|
||||
"name": "human header drops request",
|
||||
"suite_rc": 1,
|
||||
"result": "killed"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
import os, subprocess, signal, pathlib, json
|
||||
root=pathlib.Path.home()/'filbert-scratch/r90-review/wt'
|
||||
out=root.parent/'mutants';out.mkdir(exist_ok=True)
|
||||
env=dict(os.environ,TMPDIR=str(pathlib.Path.home()/'filbert-scratch/tmp'),DOCKER_HOST='unix:///nonexistent.sock')
|
||||
R='packages/tasks/src/requirements.mjs';V='packages/tasks/src/verbs.mjs';B='packages/bus/src/broker.mjs';T='packages/harness/src/tools.mjs';RU='packages/harness/src/runner.mjs'
|
||||
req=['node','--test','packages/tasks/tests/requirements.test.mjs']
|
||||
verb=['node','--test','packages/tasks/tests/verbs.test.mjs']
|
||||
bus=['node','--test','packages/bus/tests/requirements.test.mjs']
|
||||
tools=['node','--test','packages/harness/tests/tools.test.mjs']
|
||||
turn=['node','--test','--test-name-pattern=turnRequest','packages/harness/tests/runner.test.mjs']
|
||||
M=[
|
||||
('own keys replaced by inherited keys',R,'Object.hasOwn(x, k)','(k in x)',req),
|
||||
('most approved ids omitted',V,'loadRequirements().requirements.map((r) => r.id)',"loadRequirements().requirements.filter((r,i,a)=>i===0 || i===a.length-1 || r.id==='REQ-TASK-1').map((r) => r.id)",verb),
|
||||
('load unchecked',R,'return freeze(checkRequirements(list));','return freeze(list);',req),
|
||||
('unknown requirement accepted',V," if (!requirements.has(plan.requirement)) fail('unknown-requirement');",'',verb),
|
||||
('read permits a nonholder',B,' keys(a, []);\n this.#agent(s);\n return this.#requirements;',' keys(a, []);\n return this.#requirements;',bus),
|
||||
('tool points at tasks',T,'add("list_requirements", "requirements",','add("list_requirements", "tasks",',tools),
|
||||
('human header drops request',RU,' if (m.request) head.push(`request ${m.request}`);','',turn),
|
||||
]
|
||||
rows=[]
|
||||
def run(cmd,log):
|
||||
with log.open('w') as f:
|
||||
p=subprocess.Popen(cmd,cwd=root,env=env,stdout=f,stderr=subprocess.STDOUT,start_new_session=True)
|
||||
try:p.wait(timeout=45)
|
||||
except subprocess.TimeoutExpired:
|
||||
os.killpg(p.pid,signal.SIGKILL);p.wait();return 'timeout'
|
||||
return p.returncode
|
||||
for i,(name,path,old,new,cmd) in enumerate(M,1):
|
||||
p=root/path;src=p.read_text();assert src.count(old)==1,(name,src.count(old))
|
||||
try:
|
||||
p.write_text(src.replace(old,new));rc=run(cmd,out/f'{i}-suite.log')
|
||||
row={'name':name,'suite_rc':rc,'result':'survived' if rc==0 else 'killed' if rc!='timeout' else 'timeout'}
|
||||
if rc==0:
|
||||
row['independent_probe_rc']=run(['node','--test',str(root.parent/'probes.test.mjs')],out/f'{i}-probes.log')
|
||||
rows.append(row);print(json.dumps(row),flush=True)
|
||||
finally:p.write_text(src)
|
||||
(out/'summary.json').write_text(json.dumps(rows,indent=2)+'\n')
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ every approved requirement creates, preserving its id (479.13005ms)
|
||||
✔ the received human request is visible in the runner header and creates a task (72.189594ms)
|
||||
✔ inherited top keys refuse (0.63594ms)
|
||||
✔ inherited entry keys refuse (0.2886ms)
|
||||
✔ null prototypes are accepted when all required keys are own (0.267382ms)
|
||||
✔ carriage return is accepted in a title (documented minor boundary) (0.209085ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 641.891471
|
||||
@@ -0,0 +1,39 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { resolve } from 'node:path';
|
||||
const root=process.env.MOSAIC_REVIEW_ROOT ?? new URL('./wt/',import.meta.url).pathname;
|
||||
const moduleAt=path=>import(pathToFileURL(resolve(root,path)));
|
||||
const { world }=await moduleAt('packages/tasks/tests/world.mjs');
|
||||
const { loadRequirements, checkRequirements, RequirementsError }=await moduleAt('packages/tasks/src/requirements.mjs');
|
||||
const { turnRequest }=await moduleAt('packages/harness/src/runner.mjs');
|
||||
const raw=()=>structuredClone(loadRequirements());
|
||||
test('every approved requirement creates, preserving its id', async t=>{
|
||||
const w=await world(t); await w.adapter.start('demo'); const pm=w.agent('pm');
|
||||
const {requirements}=loadRequirements();
|
||||
for(const {id} of requirements) await w.call(pm,'task.create',{title:id,request:w.instruction(),requirement:id});
|
||||
assert.deepEqual(w.events('task.created').map(e=>e.body.requirement),requirements.map(r=>r.id));
|
||||
});
|
||||
test('the received human request is visible in the runner header and creates a task',async t=>{
|
||||
const w=await world(t); await w.adapter.start('demo'); const pm=w.agent('pm');
|
||||
w.broker.request(w.human,{verb:'message.send',args:{to:'pm',body:'do this'}});
|
||||
const [message]=w.broker.request(pm,{verb:'message.receive'});
|
||||
const header=turnRequest(message); assert.ok(header.includes(`request ${message.request}`));
|
||||
const request=header.match(/, request ([^:]+):\n/)[1]; assert.equal(request,message.request);
|
||||
await w.call(pm,'task.create',{title:'header request',request,requirement:'REQ-TASK-1'});
|
||||
});
|
||||
test('inherited top keys refuse',()=>{
|
||||
const l=raw(); const inherited=Object.create({prd:l.prd}); inherited.version=l.version; inherited.requirements=l.requirements;
|
||||
assert.throws(()=>checkRequirements(inherited), e=>e instanceof RequirementsError && e.message==='list: missing prd');
|
||||
});
|
||||
test('inherited entry keys refuse',()=>{
|
||||
const l=raw(); const r=l.requirements[0]; l.requirements[0]=Object.assign(Object.create({id:r.id}),{title:r.title});
|
||||
assert.throws(()=>checkRequirements(l),e=>e instanceof RequirementsError && e.message==='requirements[0]: missing id');
|
||||
});
|
||||
test('null prototypes are accepted when all required keys are own',()=>{
|
||||
const l=Object.assign(Object.create(null),raw()); l.requirements=l.requirements.map(r=>Object.assign(Object.create(null),r));
|
||||
assert.equal(checkRequirements(l),l);
|
||||
});
|
||||
test('carriage return is accepted in a title (documented minor boundary)',()=>{
|
||||
const l=raw(); l.requirements[0].title='one\rtwo'; assert.equal(checkRequirements(l),l);
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
# Row 90 round 1 independent review
|
||||
|
||||
Candidate and verdict are in verdict.md. Gate and mutation results are in gate-summary.json and mutant-summary.json; the restored-candidate probe output is probes.log.
|
||||
|
||||
Reconstruction used ~/filbert-scratch/r90-review/wt at detached 23338c7b, git apply --index on Dewey's build.patch, and a node_modules symlink to the canonical checkout. The manifest digest is 26d1fbdf23c2ae70fd9317fe6484e7bdf4339f45b59463e66123c100dbf1ac7d. Full suite and mutant logs remain under ~/filbert-scratch/r90-review/.
|
||||
|
||||
Reproduce the independent probes against a reconstructed candidate:
|
||||
|
||||
```sh
|
||||
MOSAIC_REVIEW_ROOT="$HOME/filbert-scratch/r90-review/wt" TMPDIR="$HOME/filbert-scratch/tmp" DOCKER_HOST=unix:///nonexistent.sock node --test agents/filbert/work/queue-90/r1/probes.test.mjs
|
||||
```
|
||||
|
||||
The carriage-return probe deliberately asserts the observed acceptance, documenting the minor schema boundary rather than pretending rejection passes. gate.py and mutants.py record the actual local run procedure and use the same scratch paths. Run mutants only after the other seats' scratch runs clear. Each mutant has its own process group; timeout kills that group, and the original source is restored in finally.
|
||||
|
||||
Scope: independent review only. No candidate edits, push, landing, Console restart or bus restart. Darkwing and Dewey received scratch-clear messages after the gate and mutants. No process had a cwd under this review's scratch directory at cleanup check.
|
||||
|
||||
Queue commit correction: the first attempt verified rev 826 but refused publication because Researcher committed 85aa676f during the guard run. No commit was published by that attempt. Retried the same review revision on the new HEAD; no verdict repost.
|
||||
@@ -0,0 +1,19 @@
|
||||
Approve row 90 (#1584), round 1, candidate manifest `26d1fbdf23c2ae70fd9317fe6484e7bdf4339f45b59463e66123c100dbf1ac7d`.
|
||||
|
||||
I reconstructed the candidate on detached base `23338c7b` with `git apply --index build.patch`. All 20 manifest paths match before and after my probes and mutants. No commit from that base to the current refactor HEAD touches those paths. I reviewed the diff against the approved brief and PRD, including Sage's approved runner.mjs exception and the correction to row 89's byte-count comment.
|
||||
|
||||
The 24 ids and titles match the approved PRD's requirements. The schema checks and deep freeze, startup loads, unknown-requirement refusal, PM tool gating, request header, non-blocking Inbox paths, and human stop guidance satisfy the brief. My additional probes create a task for each of the 24 ids, pass a received human request through the real turn header into task.create, reject inherited required keys at both schema levels, and accept own keys on null-prototype objects.
|
||||
|
||||
My fresh sequential gate passed: tasks 79, bus 111, harness 66, webui 86, cli 115, business 60, seat 27, control-board 124, each with zero failures. All nine scripts/test-*.sh returned 0: auth 15, conductor 17, config 24, discord 66, extension-package 18, foundation 44, queue 27, release 4, task 26. DOCKER_HOST was unix:///nonexistent.sock throughout, so release's Docker state-machine cases and task's Docker cases were skipped. This differs from Dewey's 14 release checks because their release run allowed Docker. No live Console or bus operation was performed.
|
||||
|
||||
Seven independent focused mutants: five killed by the candidate's tests; two survived those tests and were killed by my added probes. No timeout. The restored candidate passes all six added probes and matches the manifest again.
|
||||
|
||||
Non-blocking follow-ups, no round 2 requested:
|
||||
|
||||
1. requirements.test.mjs lacks inherited-key cases. Replacing Object.hasOwn with in survives it. Add top-level and entry-level inherited-key refusals. Current code correctly refuses both.
|
||||
2. verbs.test.mjs checks only the first and last approved ids. An allowlist containing just those plus REQ-TASK-1 survives. Loop through all 24 ids. Current code accepts all 24, verified independently.
|
||||
3. A title containing carriage return passes checkRequirements even though the schema says one line. Reject carriage return as well as newline and add that boundary case. The committed titles contain neither, and this affects reviewed file validation, not task authority.
|
||||
|
||||
Evidence and reproducers: agents/filbert/work/queue-90/r1/. Sage's landing gate and Mos's pre-landing notice still apply; live at the next bus restart. Nothing pushed.
|
||||
|
||||
Filbert, Codex thread 50342f6a-fff7-437a-aa75-679554289732.
|
||||
@@ -805,3 +805,4 @@ are never rewritten or removed; corrections are new entries.
|
||||
2026-10-12T22:43:32Z | darkwing | row 63 round 2 (#1556) | in review, request 28005, revs 809-811 (77f6cc58); packet 557b28fb rebased onto cca5f23e after row 89 touched tools.mjs and tools.test.mjs, candidate 2a22fd3f; four child-path tests, mutants 25/25 killed, gate 15/15 green
|
||||
2026-10-12T22:48:48Z | dewey | row 90 (#1584) round 1 build | packet 950e8403, manifest 26d1fbdf, base 23338c7b; gate all green, 44 mutants killed after one test fix; review request c28009 and queue request c28013; revs 819-820 in 829c00fb; runner.mjs outside the list per Sage
|
||||
2026-10-12T22:51:54Z | sage | row 86 (#1580) landing | landed ad0bdc20 after gate rerun of all ten spikes, manifest rc=0 in-dir (N6), S9 OOMKilled report missed once then 3/3 clean, daemon back to baseline; rev 821 (15ed3513), #1580 closed 28014; S9 flag follow-up to Researcher
|
||||
2026-10-12T22:56:44Z | filbert | row 90 (#1584) round 1 review on 26d1fbdf, base 23338c7b | approve comment 28021, rev 826 committed e6948d92; 8 node suites and 9 shell suites rc=0 with Docker disabled (release 4, task 26, Docker cases skipped); 6 probes pass; 7 mutants, 5 killed by candidate tests and 2 by extra probes; three non-blocking follow-ups; rebase round follows row 63 landing per decision 125; no push
|
||||
|
||||
Reference in New Issue
Block a user