Compare commits

...
Author SHA1 Message Date
jason.woltje aca16404cf queue: revs 3195-3216. Rows 278, 281 and 264a reviews, notes and done moves (sage, gizmoduck, megavolt, gander, webby, dewey, duckworth); row 264 round 1 request posted as jarvis (sage-2693, #1769) 2026-10-22 09:25:48 -05:00
jason.woltje f7e4ec3df5 row 264a (#1769): BUILD.md records the r13 gate on 2cc34aef8 (phases 1-3 green, M2 thrown at the trigger) and the r13p4 rerun at 84f53540d (M1-M4 killed on assertions, M2's four edits and kill rule), and the limits row gets the measured probe time; doc only (mos-1280 item 1, sage-2701) 2026-10-22 09:23:39 -05:00
jason.woltje b789188504 docs: row 264a landing sweep. BUILD-LOG gets Rocko's V502 rerun line and Sage's V502, rows 278/281 and row 264a landing lines; SESSIONS gets Dewey's, Rocko's and Sage's lines; DEFERRED moves the fire-keeps-grants gap to Done (row 281) and opens row 281 N1/N2 and row 264a N1 (actor_run, binds row 269) and N2 (esbuild skip) (sage-2695, #1769) 2026-10-22 09:22:05 -05:00
jason.woltje 84f53540dd row 264a r13 (#1769): BUILD.md writes M2's four edits before phase 4 reruns: the receive filter, delivery_same_session dropped from 3k-3l.sql and schema.sql, and store.mjs's SCHEMA_SHA256 set to the mutated schema; a kill counts only as a receive-test assertion; doc only (mos-1279, sage-2688, sage-2690, duckworth-0143, duckworth-0144) 2026-10-22 09:08:25 -05:00
jason.woltje 2cc34aef87 row 264a r13 (#1769): threads.test :341 takes the 3l trigger's text, 'only to its session's holder' (delivery_same_session, 3k-3l.sql:153); BUILD.md raises the stack-release limit to 1800 s from the survey's 575 s and records the r10 and r11 reds and the r12 survey with M1 in Runs; test only (mos-1278, sage-2682) 2026-10-22 08:36:56 -05:00
jason.woltje 93f4af12bc row 264a r12 (#1769): sessions.test T2's refused() keeps every table but events equal and pins one action.refused {code: not-holder} event per refused call in call order; the old every-table check could never pass since request()'s catch (broker.mjs:4242) writes the refusal through #refused; BUILD.md records Mos's reading of sage-2257; test only (mos-1277, sage-2676) 2026-10-22 08:21:41 -05:00
jason.woltje 75f049ed23 row 264a r11 (#1769): later3l in account-, gitea- and grant-migration names threads_id_not_session, the 3l trigger on threads (3k-3l.sql:104) the sqlite_master compares missed; test only (mos-1276 option A, sage-2672) 2026-10-22 08:14:15 -05:00
jason.woltje 54f65f9abd row 264a r10 (#1769): rebase on landed 281 (e479521d3), all 16 =; broker.mjs overlap read; cli limit 1800 s from 281's 591 s run (sage-2665, sage-2668, sage-2647) 2026-10-22 08:08:28 -05:00
jason.woltje 7451878b66 row 264a r9 (#1769): rebase on landed 278 (385a7194c), all 15 =; webui read check; run limits at 3x the longest recorded run (sage-2647, mos-1275) 2026-10-22 08:07:43 -05:00
jason.woltje 16889a46be row 264a r8 (#1769): build notes correction for the r7 red (account-migration, sqlite_sequence rows from the 3k-3l inserts), the whole-snapshot audit of every migrating test, the r7 run in Runs (sage-2621, duckworth-0129) 2026-10-22 08:07:43 -05:00
jason.woltje c3f43960eb row 264a r8 (#1769): the six migration tests that compare a whole store with sqlite_sequence after the 3k-3l step leave out the sessions and session_defaults sequence rows and assert them exactly, so any other new row still fails; usage-migration reads sqlite_sequence by name (sage-2621, duckworth-0129); unrun 2026-10-22 08:07:43 -05:00
jason.woltje 0431778465 row 264a r7 (#1769): build notes for the rebase onto landed 277 (980cec88c, sage-2608) and the per-session thread.claims; DEFERRED entry binds row 272 to make 274's user reply check session-scoped (sage-2591) 2026-10-22 08:07:43 -05:00
jason.woltje f3e9b6512c row 264a r7 (#1769): thread.claims reads each session's latest claim, so a thread with two held sessions lists both (sage-2591, duckworth-0124 C4); thread-claims.test threads get their default session and its T5 message names it (C5), T6 two held sessions; unrun 2026-10-22 08:07:43 -05:00
jason.woltje b7a05482bb row 264a r6 (#1769): build notes for the rebase onto landed 274 (0165be266, sage-2588): the four user-principal conflicts, users stay at the ruled seven verbs, and why 274's thread-scoped reply check needs no session clause yet 2026-10-22 08:07:43 -05:00
jason.woltje 4beb6433a4 row 264a r5 (#1769): build notes correction, rounds 1-4 never parsed three test files and no run claimed them; the round 5 gate runs every touched suite (sage-2581) 2026-10-22 08:07:43 -05:00
jason.woltje fbfaab3655 row 264a r5 (#1769): build notes for the rebase onto landed 236 (47a35bf43, sage-2579): the 194 conflicts, message-filter.test as the 19th test file, and the escaped quotes in three DEFAULT_SESSION blocks 2026-10-22 08:07:43 -05:00
jason.woltje 9ff668550f row 264a r5 (#1769): build notes name the op rename to legacy-3l and migration-3l by the step's target version (sage-2415) 2026-10-22 08:07:43 -05:00
jason.woltje 5baaaa447b row 264a r5 (#1769): build notes for the 3k-3l step on row 236 (8f51900b5, sage-2412): the renames, the merged pins and lists, gitea-migration reading both steps, and the in-memory dry run on 236's schema; README op value legacy-3l 2026-10-22 08:07:43 -05:00
jason.woltje c4a12de3d8 row 264a r3 (#1769): build notes say the generation fence is equivalent to the holder_run check it replaced, and M1 shows the refusal is tested (duckworth-0108, sage-2270) 2026-10-22 08:07:43 -05:00
jason.woltje 72fc5a330b row 264a r2 (#1769): generation fence for thread runs, a retired generation's approval, delivery and read refuse and write nothing (sage-2257); #route refuses an unknown session, README default-op note, Row 155 comment reworded, mutants M1-M3 in the build notes (duckworth-0107) 2026-10-22 08:07:43 -05:00
jason.woltje d6301dffce row 264a (#1769, T1 item 7): bus schema 3k to 3l, sessions below a thread
sessions and session_defaults are new and append-only. thread_claims, message_threads and
thread_opens are rebuilt in place with a session column, and thread_claims gains a generation
counted from claim rows. Each existing thread gets a default session with the thread's id; new
threads get a random one. Holder, per-run, release and delivery triggers key on the session,
and two id triggers keep session and thread ids apart (Duckworth checks 1-7, duckworth-0106).

The broker binds a thread run to a session (the default when the record names none), and
thread.open, thread.send and thread.messages take an optional session. New verbs session.list
and session.create (idempotent on op). Tests: sessions.test.mjs for T1 bus half, T2 and T7 with
a pinned 3k fixture; count, version and verb pins; hand-made test threads write the legacy
default session.

Built on row 236 (8f51900b5), which takes 3j-3k, so this step is 3k-3l by landing order
(row264 Q2, sage-2412). The op values are legacy-3l and migration-3l. gitea-migration.test reads
its store after both steps. Not run yet: every run waits for Sage's CLEAR.
2026-10-22 08:07:43 -05:00
jason.woltje ae525c4095 gizmoduck: row 264a bus design in the build notes: sessions and session_defaults, thread_claims, message_threads and thread_opens rebuilt with a session (legacy default id = thread id), generation, broker lookups by session, verbs, tests and pinned lists 2026-10-22 08:07:43 -05:00
jason.woltje b5630ca198 gizmoduck: row 264 build notes record Sage's Q1-Q7 rulings (sage-2235, 5f5b51dd6) 2026-10-22 08:07:43 -05:00
jason.woltje 26380e3f0b gizmoduck: row 264 phase A build notes, code at da9555ca2, consumer audit first pass, five proposed slices and Q1-Q7 to Sage (sage-2233, #1769, Vikunja 463) 2026-10-22 08:07:43 -05:00
jason.woltje e479521d3a row 281 build notes: the manifest-round slot on 7979fb41e is green; Runs has the base, anchors, M1 exit check, dewey-0840 files, bus/business/cli whole and the shells with their limits and named skips; Mutants has M1-M22, 22 killed, M22 fails only T14 (sage-2661, dewey-0845, #1786) 2026-10-22 08:00:45 -05:00
jason.woltje 7979fb41eb row 281 build notes: the gate plan for row281-e, with each scripts/test-*.sh under a limit of at least 3x its longest recorded run (sage-2649, dewey-0840, mos-1275, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 54ebc5d71c row 281 b5: T14 pins that the human's no takes a declined host decision out of the set, after hosts.remove left it with no host (N1); M22 drops the closed check and T14 kills it; test only, not yet run (sage-2653, dewey-0844, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 5e05e21794 row 281 build notes: the mutant table names section 9's killing test and each mutant's failing tests from its log; every mutant fails its named test (dewey-0841, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 6b6eb533e8 row 281 b4: T6b pins step 0's four Gitea reads in order and says 'before any Gitea write'; M1-M21 all killed on b4a 3f29375a8 with the M1 exit check, table in the build notes (dewey-0839, sage-2627, sage-2643, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje f9fcf5d7b3 row 281 b4a: the M1 hang was T6c's held web1:add loop, which only the fire's abort ends; setup's t.after clears held and failing, and T6c and T10 release their Gitea gate; test only, no code change (mos-1273, sage-2636, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje c055dddf44 row 281 b3: the first base run's five red tests were test faults, no code change; T4b reads the manual's revoke id from its event, T5b expects gitea-left:<id>,tokens (N10), T6b allows step 0's GET checks, gitea T8 leaves the call log out, cli T10 makes the 0700 store root; rebase onto 980cec88c noted (sage-2605, sage-2615, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 6d62ef04e0 row 281 build notes: rebase onto 46dedf925 after row 256, range-diff all =, 256's actor threading doesn't change what a delete calls (sage-2597, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 4982fa0adf row 281 b2: T1-T13 tests (fire-revokes-grants, lifecycle-revoke T1, T8 tester refusals, cli T10 pass) and the test choices in the build notes (#1786) 2026-10-22 07:42:10 -05:00
jason.woltje 7c2c876319 row 281 b1: step G in the broker (fire and delete jobs, the grant set, the lock, boot's interrupted check) and build notes (#1786) 2026-10-22 07:42:10 -05:00
jason.woltje 7d5f16ef95 row 281 build notes: Dewey's d6 approval with N7 (T12's step B cause survives step G) and N8 (no decision-consumed for a within-role fire) (dewey-0829, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje a7b4f6785c row 281 design d6: the job's step C without the chief's claim, fire.failed for a step B or C failure, boot closes interrupted jobs, Q1 lines in the set (dewey-0825, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 938378455d row 281 design d5: two requests per granted delete with its five conditions, a job id on every answer, event and message (sage-2575, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 5f4cd2faa6 row 281 design d4: step G detached from the verbs, open decisions and a fired-agent raise check, one step G per agent (dewey-0823, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 6faa0f1479 row 281 design d3: a grant decision approved before a fire and executed after it, tests T6/T6b/T6c (sage-2574, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 9867a6f322 row 281 design d2: Q1/Q2 rulings (sage-2573), the finding in the Why, T3b/T4b and M8/M9 (#1786) 2026-10-22 07:42:10 -05:00
jason.woltje 15ab01c0c3 row 281 design d1: a fire or a delete revokes the instance's host and Gitea grants (sage-2568, #1786) 2026-10-22 07:42:10 -05:00
jason.woltje 385a7194c7 docs(row278): record green third gate and final review evidence 2026-10-22 07:32:56 -05:00
jason.woltje 3e4c77ac60 docs(row278): pin Mos-approved fixture and per-script timeout receipts 2026-10-22 07:21:05 -05:00
jason.woltje 9696d1fcb7 test(webui): supply empty thread claims in shell bus fixture 2026-10-22 07:17:46 -05:00
jason.woltje f99c39a3f0 docs(row278): void run2 and record legacy fixture stop 2026-10-22 07:17:12 -05:00
jason.woltje 42abda031f docs(row278): void run1 and pin approved fixture repair 2026-10-22 07:09:57 -05:00
jason.woltje 964b6b1848 test(webui): export bus error in thread claims loader fake 2026-10-22 07:08:42 -05:00
jason.woltje 0011fe357e docs(row278): pin committed source and accepted gate rules 2026-10-22 06:40:47 -05:00
jason.woltje e7d21b91b8 feat(webui): show thread claims separately in Agents 2026-10-22 06:40:05 -05:00
jason.woltje 2c350a4669 docs(row278): freeze thread claims candidate for the gate 2026-10-22 06:39:00 -05:00
rocko 6af85df4be docs: record V502 rerun on 980cec88c 2026-10-22 06:28:40 -05:00
rocko 04a86cf338 docs: record Vikunja 502 focused verification and rebase evidence 2026-10-22 06:24:27 -05:00
rocko 407c8d7be2 test: harden processing failure diagnostics and cleanup 2026-10-22 06:24:27 -05:00
jason.woltje 980cec88c2 queue: revs 3188-3194, row 277 in-review (Morgana 3188, request failed 3189, no token), review request 3190/3191 (Sage, c30538), Duckworth approve 3192 (c30539, posted by Sage as jarvis), landing note and done 3193/3194 (Sage) 2026-10-22 06:23:06 -05:00
jason.woltje c33cba810c docs: row 277 landing log line, Sage's session line, and the M8 resolve-pin DEFERRED entry (Duckworth N1, binds the next tester.test.mjs row) 2026-10-22 06:21:43 -05:00
jason.woltje 01ea1fb11b row 236 build notes: the runs and mutants from the 10-22 slot (2c, the whole gate at bd5f11ded, 40/40 killed), doc-only (#1742) 2026-10-22 06:21:17 -05:00
jason.woltje b831733053 honker: row 256 (#1761) BUILD.md gate results, doc-only after landing f12441d4f: full gate green on 0165be266 (31/0 touched, M1-M4b killed, 18 packages 3757/0, 10 scripts rc=0, 4 skips none touched), Webby approve c30519 2026-10-22 06:21:17 -05:00
jason.woltje 62f53b1e07 morgana: row 277 (#1782) r4: a thread.claims error with no bus code still throws and prints nothing (duckworth-0123 N1, M9); BUILD.md records the rebase onto 0165be266 and N2/N3 2026-10-22 06:01:09 -05:00
jason.woltje bda4ee6138 morgana: row 277 (#1782) r3: a refused thread.claims prints the role lines and the refusal code (N1), cli README agents usage (N2), per sage-2505 2026-10-22 06:01:09 -05:00
jason.woltje 3a5275a9ad morgana: row 277 (#1782) build r2: thread-claims test helper passes a run's capability through, T1 copies store rows before the strict compare (early look sage-2504) 2026-10-22 06:01:09 -05:00
jason.woltje eccd6e276e morgana: row 277 (#1782) build: thread.claims bus verb for human and reader sessions (D1), mosaic agents adds thread lines without --tester or --json (C1/C2), message-filter pin moves to thread.claims (C3), tests T1-T8 2026-10-22 06:01:08 -05:00
jason.woltje 571ca3d912 morgana: row 277 (#1782): design folder moves to queue-277 (sage-2486) 2026-10-22 06:01:08 -05:00
jason.woltje 2f7fc6832f morgana: #1782 design r2 (duckworth-0118): C1 tester path makes one call, C2 --json keeps the agents array, C3 pin moves to thread.claims; N1-N4 taken, M7 added 2026-10-22 06:01:08 -05:00
jason.woltje 1d5d00939a morgana: #1782 design r1 (sage-2481): owner thread claims as a human/reader verb thread.claims, agents unchanged; Console and TUI read c.role, so the briefed mixed list would need them too (Q1, Q2 to Duckworth) 2026-10-22 06:01:08 -05:00
jason.woltje 46dedf9259 queue: revs 3181-3187, row 256 in-review (Honker 3181/3182, request failed, no token), review request 3183/3184 (Sage, c30518), Webby approve 3185 (c30519, posted by Sage as jarvis), landing note and done 3186/3187 (Sage) 2026-10-22 06:00:35 -05:00
jason.woltje cac129e23a docs: row 256 landing log line and Sage's session line (f12441d4f, #1761 closed c30520) 2026-10-22 05:59:17 -05:00
jason.woltje f12441d4fa honker: row 256 (#1761) b2: Webby's N1 (webby-0124): instance-settings.mjs:30 and agents.js:46 comments name the assistant, not the chief of staff; BUILD.md note; comment-only, unrun 2026-10-22 05:33:13 -05:00
jason.woltje e617543b8d honker: row 256 (#1761) b1: the human deletes a creative instance and any other actor is refused organization-creative-human-only; protectedRefusal is the delete check and the listing's per-reader endProtected; actor threaded through planDelete/checkDelete/instances.check; fire unchanged; DEFERRED entry closed for delete; tests T1-T8, unrun 2026-10-22 05:33:13 -05:00
jason.woltje d4dfc79b18 honker: row 256 design draft 2 (webby-0122): T4 uses the last-listed refusal (R1), endProtected keeps its name with comments rewritten (Q1), bus test in creative.test.mjs (Q2), M1 killed by T2 only and the chief's human-required pinned (N1), M4 for the actor threading (N2) 2026-10-22 05:33:13 -05:00
jason.woltje b5f1e09d6c honker: row 256 (#1761) design draft 1: one protectedRefusal predicate for delete and the listing's per-viewer endProtected, actor threaded through planDelete/checkDelete/instances.check, fire unchanged, persona file left in place 2026-10-22 05:33:13 -05:00
jason.woltje 0165be2661 queue: revs 3173-3180, row 281 claim (Megavolt 3173), row 274 in-review (Morgana 3174/3175, request failed, no token), review request 3176/3177 (Sage, c30488), Dewey approve 3178, landing note and done 3179/3180 (Sage) 2026-10-22 05:32:22 -05:00
jason.woltje 6d6cc0f608 docs: row 274 landing log lines, Dewey's 274 and 281 session lines, and the N7 DEFERRED entry (runs suite gates mosaic-task.mjs) 2026-10-22 05:31:01 -05:00
jason.woltje 4c485c63b9 morgana: FED R3 r6 (sage-2576): the collaborator-list test pins USER_VERBS as the ruled seven so M3x and M6x fail it, and its off-list set adds the grants, lifecycle, web and host verb lists; test only, unrun 2026-10-22 05:06:52 -05:00
jason.woltje f58cfc3617 morgana: FED R3 r5 (sage-2566): covers, LEVELS and the all marker move into the business vocabulary so the broker keeps its sandbox import closure; access.mjs re-exports them, the pin test lists covers on the vocabulary line, RUNNER_FILES unchanged, M16 on the pin, the closure walk and the confined load; unrun 2026-10-22 04:48:41 -05:00
jason.woltje cee3f25a37 morgana: FED R3 r4 (sage-2486, sage-2557): halt refuses a granted user's thread.send while thread.messages answers (test), row 194's hire refuses an instance named user at the broker and the writer (S1, one test each), the access argument check moves before the store read (S2, test), M12-M15; unrun 2026-10-22 04:48:22 -05:00
jason.woltje 1313bfb718 morgana: FED R3 r2 packet (sage-2299): rulings 1-5 recorded, brief's 193b1a mutant line void, manifest widens to instance-settings and its test; doc only, unrun 2026-10-22 04:48:22 -05:00
jason.woltje 618fe0f0b3 morgana: FED R3 r2 (dewey-0777): role key user refused at the broker load check and by the instance writer (N1, one test each), #threadFor user clause listed as an equivalent mutant, 193b1a filter mutant not applicable, M10/M11 and the M3x two-walls run in the kit; unrun 2026-10-22 04:48:22 -05:00
jason.woltje d20c92bf65 morgana: FED R3 build (#414, sage-2292): user principal on the bus, bindUser with a per-request grant read, the collaborator verb list and its filters, user threads and the B6 reply path, runner user header; unrun 2026-10-22 04:48:22 -05:00
jason.woltje 47a35bf436 queue: revs 3163-3172, row 256 claim (Honker 3163), row 236 in-review (Megavolt 3164/3165), review request 3166/3167, Dewey approve 3168, landing note and done 3169/3170, row 281 add and briefed 3171/3172 (Sage) 2026-10-22 04:47:17 -05:00
jason.woltje 6b32424adb docs: row 236 landing log lines, and row 281 (#1786): a fire or a delete revokes the instance's grants (mos-1271)
Brief docs/plans/2026-10-22_fire-revokes-grants.md, owner Megavolt, reviewer Dewey, gate owner Sage. DEFERRED entry points at row 281. BUILD-LOG and SESSIONS carry Honker's row 194 lines, Dewey's two row 236 lines and Sage's row 236 landing lines.
2026-10-22 04:43:49 -05:00
jason.woltje bd5f11dedd bus: row 236, a gitea grant raise on a broker with no Gitea path refuses gitea-not-configured (sage-2559, #1742) 2026-10-22 03:59:40 -05:00
jason.woltje e40b74bebc bus: row 236, two out-of-manifest pins: gitea is a known grant method, and the broker imports giteaName and parseGiteaUrl (gate run sage-2554, #1742) 2026-10-22 03:57:48 -05:00
jason.woltje ce74477e14 bus: row 236, grants.status is a read under the kill switch, as hosts.status is (sage-2453, #1742)
Row 191's #processingGate refuses agent verbs off its read list while
processing is halted. grants.status joins hosts.status on that list, per
the kill-switch plan (2026-10-20_kill-switch.md:16): reads still work.
An agent's grants.revoke stays refused while halted, as hosts.revoke is.
2026-10-22 03:42:05 -05:00
jason.woltje 4d9d62ae89 bus: row 236 r3, one N5 test per settle branch; README notes for a left admin token and a running executor (sage-2388, #1742) 2026-10-22 03:42:05 -05:00
jason.woltje 5e5ba94b19 bus: row 236 r3, a revoke during a settle whoami ends revoked in the 401 and token-unknown branches (Dewey N5, #1742) 2026-10-22 03:42:05 -05:00
jason.woltje 97bbe7fd30 bus: row 236 r2, a revoke during step 7 or a settle ends revoked; sweep fire retry checks the user id (Dewey B1, B2, #1742) 2026-10-22 03:42:05 -05:00
jason.woltje 91f7029923 bus: row 236 gap test takes any HTTP status in a grant.result (debug run 2, #1742) 2026-10-22 03:42:05 -05:00
jason.woltje be11a1f7e6 bus: row 236 tests for the static mutant gaps M8, M9, M16, M28, M29, M37 (#1742) 2026-10-22 03:42:05 -05:00
jason.woltje d87483d683 bus, cli: #436b Gitea grant path, schema 3j-3k (row 236, #1742)
Gitea grant executor (steps 0-8, settle, restart, revoke and fire, sweep,
status), the grants.* verbs and mosaic grants, the 3j-3k migration with
gitea_users and gitea_grants, and the section 9 tests with a fake Gitea and
a scratch gitea/gitea:1.27.1 X-G3 test. Build notes in
agents/megavolt/work/queue-236/BUILD.md.
2026-10-22 03:42:05 -05:00
jason.woltje be2b008cc0 queue: revs 3156-3162: row 194 Honker in-review and failed request (3156/3157), Sage review request (3158/3159), Webby verdict (3160), Sage landing note and done (3161/3162) 2026-10-22 03:39:38 -05:00
jason.woltje ab7377bcf1 docs: row 194 landing BUILD-LOG and SESSIONS lines (Sage) 2026-10-22 03:38:16 -05:00
jason.woltje fd6dd327c3 honker: row 194 b15 (b') (sage-2507): T15 drops the exited reviewer stand-in's registry entry by hand, the N6 convention, so the post-resume coder launch isn't refused on an entry with no provider/model; BUILD.md notes for (a) and (b') 2026-10-22 03:06:41 -05:00
jason.woltje 5fd178e44d honker: row 194 b15 (a) (sage-2501): the Broker constructor's harnessOn, testerOn and roleFile type checks move ahead of the store reads, so a null store gets the argument error first (chief-of-staff T8b); 191's lines unchanged 2026-10-22 03:06:41 -05:00
jason.woltje 345f3ace67 honker: row 194 b8 r3 docs: correct N4, only session.ended clears the alive flag today 2026-10-22 03:06:41 -05:00
jason.woltje 54ec93d06f honker: row 194 b8 r3 docs (webby-0100, sage-2290): N1 corrects the N6 clock caveat (the bus clock runs ahead, so the error is over-signal); N2 DEFERRED the 64-stop done cap; N3 and N4 follow-ups; no product change 2026-10-22 03:06:41 -05:00
jason.woltje 4f68485272 honker: row 194 b8 r2 (sage-2289): a fire stop stopRun can't confirm (unknown) reads as lifecycle.end.alive with reason unknown, never killed, and the Console flags it; cli T9a no-runtime-record test, bus T9a reason checks, M56; notes 2026-10-22 03:06:41 -05:00
jason.woltje c48239ec3d honker: row 194 b8 notes: base eb3abba12 (row 191), the commit 1, b4 and b6 conflict resolutions file by file, S6 design notes, the unknown-outcome question, mutants and run list 2026-10-22 03:06:41 -05:00
jason.woltje 5d2c274420 honker: row 194 b8 S6 (sage-2241, sage-2246, sage-2261): fire's kill end goes through row 191's stopRun with the fire's request as owner, killed and alive come back as lifecycle.end.killed and lifecycle.end.alive and the Console flags a run still alive; terminate stays SIGTERM-only (V3); halted, the pass closes launches and regenerates processing-halted and a halt joins a fire's stop; terminate's pass narrows to runs spawned by the end's time (N6); T9a, T9b, T15, N6 2026-10-22 03:06:41 -05:00
jason.woltje 9e5ad7c599 honker: row 194 b7 notes: rebase onto dcd8d4dda (row 254), channel-proof pin, N3 as a behaviour change, routes.set keep and M-next, mutant (a) kill file corrected, N6 ruling for S6 2026-10-22 03:06:41 -05:00
jason.woltje 939356a1c2 honker: row 194 b7 (webby-0095 N1, sage-2248): routes.set refuses a kept instance's route to anyone but the human, as the limits writer does 2026-10-22 03:06:41 -05:00
jason.woltje 3521c23c3e honker: row 194 b6 (webby-0094, sage-2241, sage-2245): every instance-writer verb answers restart (B1) and the CLI and Console show it for veto; fire runs the writer's checks against the file before step A, so an unloaded keep can't strand an instance firing; a fire of a delisted name revokes (N1); a host service makes no token reference (N2); only the human re-points a kept instance's model (N3); DEFERRED a human escape for a stuck fire (N4); S6 waits on row 191's stopRun contract 2026-10-22 03:06:41 -05:00
jason.woltje 2311a50e1c honker: row 194 b4 (sage-2164, sage-2166, sage-2217): a hire and the role's hireable list refuse a creative definition; a library mapping change isn't reloaded (T14); the listing's endProtected hides a Delete the server refuses; DEFERRED creative delete; C1 testerNoSignIn closed; row 213's writer-restart pin follows D3 and T16 uses row 196's tester socket 2026-10-22 03:06:41 -05:00
jason.woltje 29daebf548 honker: row 194 b3 sage-1634: commit() checks the revision before the revoke, so a stale delete or fire refuses revision-conflict with nothing revoked (N1); bus T21; option 2 a follow-up 2026-10-22 03:06:41 -05:00
jason.woltje 2f08fd8f23 honker: row 194 b3 sage-1630: BUILD.md follow-up N1, a revoke that succeeds before a refused write (a stale-revision delete does it every time) 2026-10-22 03:06:41 -05:00
jason.woltje b8c3d00362 honker: row 194 b3 sage-1620: credential-revoke-failed says the business file is unchanged and a retry is safe (CLI and Console), W2 checks the log per case 2026-10-22 03:06:41 -05:00
jason.woltje 14124d96d4 honker: row 194 b3 (sage-1605, sage-1610): fire and delete revoke before the write (T20), a human add takes a tracker bot, a store-only delete names the bot; the tester keeps the credential refusal (row 175 W2); channel-proof and project-runtime pins 2026-10-22 03:06:41 -05:00
jason.woltje e7fb59f225 honker: row 194 on row 199's landing cb5fdb064 (sage-1601): honker/row194-b2 85edab7c7 squashed, five conflicts kept both sides (broker imports, constructor, dispatch, the credential and lifecycle verbs; runtime imports; organization write takes detail and context; cli credentials and veto dispatch; vocabulary comment as row 199 wrote it) 2026-10-22 03:06:41 -05:00
jason.woltje e122aad8e2 queue: revs 3148-3155: row 280 Rocko start, in-review and failed review request (3148-3150), Sage review request (3151/3152), Duckworth verdict (3153), Sage landing note and done (3154/3155) 2026-10-22 03:03:05 -05:00
jason.woltje 4c4b8559cf docs: row 280 landing BUILD-LOG and SESSIONS lines (Sage); Rocko's row 280 BUILD-LOG and SESSIONS lines 2026-10-22 03:00:14 -05:00
rocko b0fd28b6f3 docs: keep a slim row 280 packet with full evidence reference 2026-10-22 02:56:40 -05:00
rocko b765f5cb81 test(bus): prove scratch sshd listener ownership before use 2026-10-22 02:28:09 -05:00
jason.woltje da5d3651d7 queue: revs 3138-3147: row 279 Rocko start and in-review (3138-3140), Sage review request (3141/3142), Dewey verdict (3143), Sage landing note and done (3144/3145); row 280 #1785 bus sshd port race added and briefed (Sage 3146/3147, mos-1270) 2026-10-22 02:14:46 -05:00
jason.woltje 82c8281166 sage: brief for the bus sshd port race row (mos-1270, #1785); 279 landing and 194 b16 third-red BUILD-LOG lines; SESSIONS lines (Sage, Rocko 279, Dewey 279 r1 and carry) 2026-10-22 02:12:09 -05:00
rockoandjason.woltje ceadad993c docs: record row 279 regression and mutant evidence 2026-10-22 01:03:26 -05:00
rockoandjason.woltje f5611c937e fix(processing): observe run status after stop deadline overshoot 2026-10-22 01:03:26 -05:00
jason.woltje 343b6dd766 queue: revs 3134-3137: row 277 brief re-pin (Sage 3134), Morgana 277 claim (3135); row 279 #1784 stopRun deadline added and briefed (Sage 3136/3137, mos-1269) 2026-10-22 00:54:47 -05:00
jason.woltje f40f2e770e sage: brief for the stopRun deadline row (mos-1269), the 191 follow-up row 194 b15's gate found 2026-10-22 00:51:17 -05:00
jason.woltje 23c3d62183 queue: revs 3130-3133 (Sage): row 277 #1782 owner thread claims added and briefed; row 278 #1783 Console thread claims added and briefed 2026-10-22 00:17:54 -05:00
jason.woltje 70e289ba73 sage: #1782 design D1 ruling (sage-2487) and the Console thread-claims follow-up brief 2026-10-22 00:14:35 -05:00
jason.woltje ab50de9fe3 queue: revs 3114-3129: rows 191, 205, 268 landed and done (Sage 3116/3117, 3119/3120, 3123/3124, 3126-3129); Rocko 191 in-review 3114/3115; Dewey 191 verdict 3118; Morgana 205 in-review 3121/3122; Duckworth 205 verdict 3125 2026-10-22 00:12:00 -05:00
jason.woltje b3665f5ab1 sage: docs for landings 191, 205, 268; #1782 owner thread-claims brief (mos-1262); re-pin 86f95bb27 plan; phase 2 window draft 3; seat SESSIONS and BUILD-LOG lines 2026-10-22 00:10:08 -05:00
jason.woltje c27207f6e6 row 268 (C2-01c, #1773, Vikunja 464): playgrounds at three levels; classify checks prefixes first
checkMapping takes kind absent, hybrid or draft. A draft has a name and one
or more prefixes and no books, and comes back with books []. A prefix inside
or holding another entry's book refuses library-playground-other-universe,
which replaces library-playground-outside-book. A prefix equal to a book or
holding its own refuses library-mapping-invalid, as does a draft source.
classify returns a playground file's entry and the book holding its prefix,
or null at universe level and in a draft.
2026-10-22 00:04:42 -05:00
jason.woltje ce6a96ad61 morgana: row 205 r2 (sage-2430): put() events carry their decision so the decision trail reaches them; pin checks the thread claim via threadsState, owner read is a follow-up row 2026-10-21 23:49:34 -05:00
jason.woltje 59f708ca21 morgana: row 205a build (sage-2288): trail and replies hide other users' thread messages from owner, reader and tester; hidden answers as unknown; #readable owner-only; design d2 rulings 2026-10-21 23:49:34 -05:00
jason.woltje f751505ada morgana: row 205 design d1 (sage-2280): FED R3 unfiled, so split 205a message filter now and 205b viewer verbs after R3; mutant 3 to 193b2; hidden trail subject returns [] 2026-10-21 23:49:34 -05:00
rocko 0fa7bf421f fix: place processing controls within the Console navigation box 2026-10-21 22:42:13 -05:00
rocko 93d211c295 fix: allocate Console viewport space to processing controls 2026-10-21 22:42:13 -05:00
rocko 08c896e3c5 docs: record processing gate failures and timer fixture correction 2026-10-21 22:42:12 -05:00
rocko 03ed2bccce test: attribute processing timer to its owning script 2026-10-21 22:42:12 -05:00
rocko ad6020754d fix: stop processing controls on Console sign-out and preserve layout 2026-10-21 22:42:12 -05:00
rocko 5c8f983dde test: initialize processing control in Discord CLI fixtures 2026-10-21 22:42:12 -05:00
rocko f1267e49af fix: account for processing controls in image inputs and launch fixtures 2026-10-21 22:42:12 -05:00
rocko d2be97c5fc test: use private tester socket for processing controls 2026-10-21 22:42:12 -05:00
rocko c13c68c813 test: strengthen processing cancellation and refusal guards
Bound the halt-abort expectation, check Discord refusal before malformed journal reads, and isolate HTTP origin and valid oversized-body guards. These test changes are committed for the row 191 gate; execution awaits the coordinated slot.
2026-10-21 22:42:12 -05:00
rocko 4bdc7e0e86 processing: inspectable per-run stop seam for lifecycle fire
Unify halt and fire cancellation by verified run identity with durable first-owner receipts and shared deadlines. Integrate the instance control with the current host, library and tester-socket paths. Focused nine-file evidence is 62 passing tests; broad suites, mutants and review remain pending.
2026-10-21 22:42:12 -05:00
jason.woltje 86f95bb27f queue: revs 3109-3113 (darkwing: row 273 in-review round 1 and review request; filbert: row 273 APPROVE recorded (c30308); sage: row 273 landing note and done after 0bbf0f6d1 (#1778)) 2026-10-21 22:41:05 -05:00
jason.woltje 5365adaef6 docs: row 273 TOOLS.md activate usage and F39 rules (Filbert N1), BUILD-LOG for rows 202 and 273
TOOLS.md: activate takes --no-sso and --send; three lines state the F39 rules.
BUILD-LOG: the row 202 landing line held since 02:01Z and the row 273 landing line.
2026-10-21 22:37:16 -05:00
jason.woltje 0bbf0f6d18 row 273: T53 test 6 pins the usage line with --no-sso
The usage line gained --no-sso in the proof and sso bracket. T53 test 6
still matched the old bracket and failed the whole run on 978143bf4.
2026-10-21 22:15:36 -05:00
jason.woltje 95f4bd8fdc row 273 notes: name the changed T57 item 3 assertion for review (sage-2321) 2026-10-21 22:15:36 -05:00
jason.woltje d8034c51bc stack-release: a rollback that drops --sso drops --send; the --no-sso walk refuses an ok line with no activation (row 273, sage-2315)
B1: row 200's rollback to a Console without --sso kept the pointer's --send,
which F39 b forbids once --send can sit beside --sso. send_for_target drops it
whenever the run drops the pointer's --sso, and the plan and steps say so.
N1: an ok line with no activation refuses sso-off-flags instead of being
skipped.
2026-10-21 22:15:36 -05:00
jason.woltje b28baf7ee8 stack-release tests: T58 adds sage-2305 cases a and b (row 273)
(a) --sso on, then two re-pins that carry it, then --no-sso gives back the
arrival's ExecStart byte for byte. (b) every set in the log holds --sso, so
--no-sso refuses sso-off-flags before any unit stops.
2026-10-21 22:15:36 -05:00
jason.woltje 3673463182 stack-release: --no-sso drops --send in one place, send_for_target (row 273) 2026-10-21 22:15:36 -05:00
jason.woltje 7991662dc0 stack-release: activate --send and --no-sso (row 273, #1778)
activate --send turns send on only when the run's Console flags hold
--sso, given or carried (F39 b), and puts it after --sso and before the
tester flags. activate --no-sso turns --sso off with the Console flags
from the set of the activation that turned it on, drops --send (F39 a)
and keeps the pointer's tester. Both are usage errors under --units
external. T58 covers the brief's T1-T4; the external test covers T5.
Design and the set-walk choice: agents/darkwing/work/queue-273/BUILD.md.
2026-10-21 22:15:36 -05:00
jason.woltje 378a76b854 queue: revs 3103-3108 (morgana: rows 205 and 274 claims; darkwing: row 273 claim; sage: row 276 F5 follow-up added and briefed (#1781, duckworth-0111 C4), row 202 done after ddfb29af7 (#1700 closed)) 2026-10-21 21:17:02 -05:00
jason.woltje ddfb29af7c row 202: FED R5, mosaic access list, grant and revoke (#1700)
Candidate quackerjack/fed-r5-r5 a74cd9f87 on c3d88840c, manifest of 6
paths (CANDIDATE.sha256). Duckworth APPROVE round 5, rev 3026 (#1700
c30184). C1 gate on Sage's slot by Quackerjack on the merge of a74cd9f87
onto a849d89b7 (3b86180b9), finished 01:56:24Z: cli suite 771/771, skip 0
(run 2; run 1 red on a too-long gate TMPDIR, harness only), every
scripts/test-*.sh rc 0 with Docker up, mutants M1-M13 killed by their
named tests. Landed onto 9c9732983 with the candidate's blobs and modes
for the 6 paths; c3d88840c..9c9732983 touches none of them.
2026-10-21 21:00:28 -05:00
jason.woltje 9c97329833 docs: brief for the row 253 F5 follow-up, supervised legacy AS_USER calls (duckworth-0111 C4) 2026-10-21 20:58:00 -05:00
jason.woltje a849d89b73 docs: phase 2 plan, row 273 cases go in stack-release.test.mjs (mos-1247; test-release.sh never calls stack-release.sh) 2026-10-21 20:23:38 -05:00
jason.woltje 0042f713dc queue: revs 3092-3102 (megavolt: row 236 claim; sage: row 273 activate --send/--no-sso added and briefed (#1778, mos-1246), row 274 FED R3 added and briefed (#1779), row 275 193b1b added and briefed (#1780), row 205 re-pinned to 193b1a with its piece, row 206 re-pinned and after 275) 2026-10-21 20:06:55 -05:00
jason.woltje f0d0b31e9b docs: briefs for the activate --send/--no-sso row, FED R3 and the 193b1 split; phase 2 plan F39 fixes
- docs/plans/2026-10-22_activate-send-nosso.md: the row Mos approved in mos-1246. Darkwing builds,
  Filbert reviews. --no-sso drops --send, --send refuses without --sso (F39), test-release.sh cases.
- docs/plans/2026-10-22_federation-r3.md: FED R3, the broker user principal, on 193b1a's candidate.
  Owner Morgana, reviewer Dewey. Its parents R1 and row 196 have landed, and the filing was owed.
- human-users-build.md: 193b1 split into 193b1a (message filter, chained on 196) and 193b1b (viewer
  verbs and board refusals, after FED R3 and R4). Mutant 3 moves to 193b2 (sage-2288, morgana-0063).
- sso-phase2-window.md draft 2: the tool gap paragraph names the approved row, and rollback step 1
  drops "--send follows the pointer", since --no-sso drops --send (mos-1246 items 2 and 3).
2026-10-21 19:42:01 -05:00
jason.woltje 92be0db025 docs: Q175 phase 2 window plan, draft 2 after mos-1245 (#385, Vikunja 412)
R1 same-copy rollback, 7247d80c7 named, placeholder stop, step 10 aimed at a
tester-owned thread, agent config writes. Names the tool gap: activate has no
--send and no --no-sso, and --expect-from is external-units only.
2026-10-21 19:33:57 -05:00
jason.woltje 02da6a2ae4 queue: revs 3088-3091 (sage: rows 205 and 236 brief re-pins to HEAD and briefed) 2026-10-21 19:30:48 -05:00
jason.woltje 2dd9c80c1c docs: Q175 phase 2 window plan, draft 1 for Mos (#385, Vikunja 412) 2026-10-21 19:21:29 -05:00
jason.woltje 137ddd0079 docs: BUILD-LOG entry for the row 254 landing and a Sage SESSIONS line (#1759) 2026-10-21 19:18:12 -05:00
jason.woltje e3c0446f55 queue: revs 3073-3087 (gizmoduck: row 264 claim, row 268 r2 back to in-progress and in-review on ecd9b35eb, request refused without a token; sage: 268 r2 review request as jarvis, rows 269-272 for 264b-264e added and briefed with issues #1774-#1777; webby: row 268 r2 APPROVE carried on ecd9b35eb) 2026-10-21 19:17:00 -05:00
jason.woltje dcd8d4ddaa queue: revs 3071-3072 (sage: row 254 landing note and done after 331597709 and eb9672c91, #1759 closed) 2026-10-21 18:58:46 -05:00
jason.woltje eb9672c910 row 254: README request-timeout sentence and a DEFERRED entry after the landing (#1759)
Doc-only commit after the row 254 landing. The library README now says
that a sync outlasting the server's 120-second hold gets request-timeout
and still finishes (Dewey N1, #1759 comment 30173; server.mjs sets the
120 s socket timeout and the broker promise runs on). DEFERRED records
Dewey N2: library-mapping-invalid, library-remote-invalid,
library-state-invalid and library-git still map to 502 until the Console
library routes row decides them. No test reads either file's content.
2026-10-21 18:55:26 -05:00
jason.woltje 3315977095 row 254: library.sync 130 s human client timeout, six library-* STATUS entries, channel-proof re-pin, README (#1759)
Candidate megavolt/row254 b31300d79 on c3d88840c, manifest be63cfbe
(7 paths). Dewey APPROVE r1, rev 3006 (#1759 c30173). Gate on Sage's
slot by Megavolt, 23:37:27-23:40:52Z on b31300d79: library 77/77, bus
628/628, webui 305 pass with 1 skip (editor rebuild needs esbuild
0.28.2), every scripts/test-*.sh rc 0; the human-cli timeout and
library-fetch-failed STATUS mutants killed by their behaviour tests.
Landed onto 41b0cf755 with the candidate's blobs and modes for the 7
paths; c3d88840c..41b0cf755 touches none of them. Merged-tree rerun of
library, bus, webui and cli on Sage's slot before the push.
2026-10-21 18:44:22 -05:00
jason.woltje 41b0cf7551 queue: revs 3060-3070 (gizmoduck: row 268 claim and in-review, review request refused without a token; sage: 268 review request as jarvis, notes on 216 and 220 pointing at RULINGS.md da9555ca2, row 264 to gizmoduck with reviewer duckworth and briefed; webby: row 268 r1 APPROVE on 9d9ee12c3) 2026-10-21 18:35:57 -05:00
jason.woltje 5f5b51dd65 sage: rulings for row 264 (T1 item 7 sessions) on Gizmoduck's phase A questions Q1-Q7
Five slices 264a-264e, all MVP; schema label by landing order across rows 236, 264a and 206; PRD 1.13
already landed; row 194 is the stop owner for 264d; one admission hook for row 191; Pi count exact with
Claude unknown until Vikunja 466; legacy single human until row 193 (gizmoduck-0154, #1769, Vikunja 463).
2026-10-21 18:34:12 -05:00
jason.woltje da9555ca2f sage: rulings for rows 216 (C2-05a) and 220 (C2-10a) on the phase A build notes
Row 216: paging approved, get takes universe, links page instead of refusing, manuscript without a
chapter returns the first chapter, long search lines return excerpt null, exclude stays path-prefix
until C2-15, and four codes approved with query-chapter-required dropped. The next round rebases on
row 268's landing and adds the PRD 1.14 playground-level tests.

Row 220: one business helper gives library and creative seat sets from the business files, so the
Discord binding schema doesn't change. M7 is wired in the control board, M8 in discord check and run.
Both fail closed on an unreadable business file. The scope grows by the helper, its test and the board's
serve.mjs. Questions 2 to 4 are answered as proposed.
2026-10-21 18:12:46 -05:00
jason.woltje 0dbb242905 sessions: Ludwig PRD 1.11-1.14 drafts handed to Sage (ludwig-0032), Sage PRD 1.13/1.14 landing (db1e7732a) and rows 264-268 2026-10-21 18:04:09 -05:00
jason.woltje ea6989d4ed queue: revs 3038-3059 (sage: rows 264-268 added for T1 item 7 sessions, C2-09b, C2-10c, C2-15 and C2-01c with #1769-#1773; Case 2 re-pin of 214, 216, 217, 219, 220, 223-227, 229 and 265-267 to rows blob a6ac627c8; 216 and 217 after 268; 268 briefed for Gizmoduck) 2026-10-21 18:03:56 -05:00
jason.woltje db1e7732aa PRD 1.14: playground levels in REQ-LIB-2 (book, universe, draft) and the draft universe in REQ-LIB-3, from Gosalyn's approved ruling 51fdfb7e2 (webby-0089, mos-1233, mos-1241, Vikunja 464) 2026-10-21 17:45:38 -05:00
jason.woltje 5d2437f899 docs: Case 2 design (Gosalyn) as of the playground ruling round d2 at 51fdfb7e2, approved by Webby in 7c00c8345 (webby-0089, mos-1233), landed before PRD 1.14 cites it (ludwig-0031, ludwig-0032, Vikunja 464). The design's history stays on origin/gosalyn/case2-design. 2026-10-21 17:45:38 -05:00
jason.woltje 28e3d82265 gosalyn: Case 2 C2-01c brief round d2 for Webby d1: gate grep scoped to packages and docs/case2 with the six owned hits named, draft frozen with books [], hybrids may have universe-level prefixes, tests for a prefix equal to a book and for prefixes-first order (webby-0090 B1 N1 N2, mos-1240) 2026-10-21 17:45:38 -05:00
jason.woltje 524e169b8c gosalyn: Case 2 C2-01c brief, playground levels: kind values and draft entries, other-universe refusal replacing outside-book, classify checks prefixes first with book null, the readers and every file that pins the old code; C2-05a brief gains one line for the null book and drafts, C2-06 needs none (mos-1240, sage-2218, ruling 51fdfb7e2, Vikunja 464) 2026-10-21 17:45:38 -05:00
jason.woltje 5f73b388c4 PRD 1.13 r2: della-0011 F1 (owner on its own thread and a granted collaborator create or clear a session) and N1 (REQ-SESS-1 title) (Vikunja 463) 2026-10-21 17:38:03 -05:00
jason.woltje 52f36e921e PRD 1.13: session ids from the approved T1 item 7 design (REQ-SESS-1 to 3) and the REQ-ROLE-2 and REQ-THREAD-2 replacements (mos-1231, mos-1235, Vikunja 463) 2026-10-21 17:38:03 -05:00
jason.woltje 6ba8a582e8 plans: row 226 (C2-13b) brief follows design D8: the install makes the stack copy and runs no release package or activate, and the precheck's --library-status reads the bus's recorded sync state after design 10 step 4a (624212842, webby-0085 B1, sage-2189, sage-2195) 2026-10-21 17:36:25 -05:00
jason.woltje aa772d731d plans: Case 2 v1 briefs for C2-09b rooms, C2-10c Console room view and C2-15 hybrid universes, Webby-approved round d2 (Gosalyn 72ceda935 and 99b1e0859 on gosalyn/case2-v1-briefs, webby-0089, mos-1233, Q211, Vikunja 464); codes room-not-open, addressee-ambiguous and R8 accepted by Sage (sage-2218) 2026-10-21 17:36:25 -05:00
jason.woltje 3dcd3651ed docs: T1 item 7 sessions design, approved r3 (Huey; Scrooge scrooge-0008; mos-1232, mos-1235, mos-1236, mos-1237; Vikunja 463)
Lands docs/plans/2026-10-21_t1-sessions.md as of 2c843d190 on origin/huey/t1-sessions-design (347278044, e19e30df2, 2c843d190 on cca206cdc) with its three BUILD-LOG and three SESSIONS append lines, onto the current refactor tip. The design blob is unchanged. Build dependency N2 (Claude completed-compaction format and the managed dataRoot reader) is Vikunja 466.
2026-10-21 17:35:03 -05:00
jason.woltje eb017d77f1 sessions: Dewey 251 r2 and 254 r1, Darkwing re-pin prep, Filbert 257 r2, Sage W9b-W12 and PRD 1.11/1.12 landings 2026-10-21 17:34:17 -05:00
jason.woltje f842462bdd queue: revs 2995-3037 (sage window and review requests; gander 253 start; dewey 251 r2 and 254 r1 records; megavolt 254 start and in-review; gosalyn 226 claim; webby 244 verdict; quackerjack 202 r5; duckworth 0104 record; morgana 257 r1 and r2; filbert 257 r1 and r2 records) 2026-10-21 17:34:02 -05:00
jason.woltje ad9cefcf2d sage: re-pin window 4429a104f to 7247d80c7 record (rows 196, 222, 215, 250, 243, 66): STATE.md, transcript, scripts, S1/S2, matrices, P3 transcripts; W0-W12 passed, pm read open (mos-1226, mos-1228, mos-1230, mos-1234); Vikunja post scripts and records 2026-10-21 17:32:32 -05:00
jason.woltje 5c91c96df5 sessions: Filbert row 257 r1 static review, APPROVE c30188 (rev 3031) 2026-10-21 17:31:06 -05:00
jason.woltje 1509c7cc57 PRD 1.12 r3: mos-1231 rulings (T1.7 is v1 under 463, design 9.2 is an estimate, LIB-6 residual 465, KILL-1 vs Q198 protected mode) and della-0009 owner-thread share condition (Vikunja 462) 2026-10-21 17:19:27 -05:00
jason.woltje 74dea06d92 PRD 1.12 r2: della-0008 F1-F4 (viewer reads, share needs the thread user's grant, Risks line names the sandbox, LIB-6 fixed notices) and the LIB-3 pin wording (Vikunja 462) 2026-10-21 17:17:54 -05:00
jason.woltje 3576afffb3 PRD 1.12: ids for the Q176 items from the approved designs (REQ-USER-3, REQ-USER-4, REQ-LIFE-1, REQ-KILL-1, REQ-LIB-1 to 7), the Risks line and the REQ-DEC-3 title (mos-1229, Vikunja 462) 2026-10-21 17:14:24 -05:00
jason.woltje 73222011f2 PRD 1.11: the review path is Mos's reading of Q211, and the v1 VMs' OIDC provider is open (vikunja:19/461) (mos-1229) 2026-10-21 17:03:11 -05:00
jason.woltje ea0b2a16d6 PRD 1.11: v1 is the 10-27 goal (Q211, mos-1227, Vikunja 459)
Follows Jason's Q211 ruling and Mos's reading. Adds to v1 and removes nothing.
- Status and a Version 1.11 source bullet quoting Q211.
- Users: two v1 users on their own instances (Q176). Where it runs: two PVE VMs, dragon-lin dev only (Q180, Q181).
- Out of scope: minting credentials (Q188, Q190), SSO (Q175) and access beyond localhost (Q176, Q179, Q180) move into v1. The bundled Pocket ID stays out (REQ-INST-2, Q203). Codex and SetSpark stay out. Case 2's own organization is v1.
- REQ-CRED-1: Gitea per seat through a grant (Q190).
- REQ-FED-1: person-to-person v1, agent-to-agent post-v1 (Q179, Q180).
- New REQ-INST-3: one-command install and upgrade, Console unit enabled in both v1 profiles (Q187, Q189).
- Acceptance: the 10-27 goal (Q176). The 1.10 note at :1217 now points to Q211. A Version 1.11 technical note keeps the old list text.
requirements.json goes to 1.11 with 71 ids. Both requirements tests are updated to match.
2026-10-21 17:01:08 -05:00
jason.woltje cca206cdce docs: briefs for Q198 S1 and email rows E01, E03-E07 (post-v1; mos-1222, mos-1223)
E12 and E14 wait to be queued until their WAIT-row and S5 prerequisites exist.
2026-10-21 16:54:13 -05:00
jason.woltje f437973d79 docs: post-v1 email plan (Della, Ludwig approved ludwig-0005; Vikunja 460, mos-1223)
Lands docs/plans/2026-10-21_email-plan.md (merged plan, 399 lines) with
Della's independent plan and her review of Ludwig's plan, from
origin/della/email-plan b0844a5ce on c3d88840c. Della's 10 BUILD-LOG and
4 SESSIONS lines are carried as appended. All rows are post-v1; no live
mailbox, credential, DNS, spend, external mail or re-pin is authorized.
2026-10-21 16:52:52 -05:00
jason.woltje 33029f3a8a deferred: the host pi auth file entry (059577886) moves to Done with row 244 (e69260a3c); real-model suite cases run outside the gate is open (Webby N2 on row 244 r1, #1757) 2026-10-21 16:44:55 -05:00
jason.woltje e69260a3ce row 244: gate runs mount a 0600 fixture pi auth file, test-release activates on the mock adapter, and real-model test-task cases sit behind MOSAIC_LIVE_PROVIDER=1 (#1757)
Candidate morgana/row244 94ab4c2fe on a36523713, manifest 6e7e3e3c (8 paths).
Webby APPROVE r1, rev 3008 (webby-0084, REVIEW-r1.md at webby/reviews
ebb3d83bf; request #1757 c30154). Gate on Sage's slot at 81e037d20
(sage-2147): the five gate-lane files whole 51/0, test-task.sh 91/0,
test-release.sh 14/0, mutants M-G, M-L, M-A, M-T and M-F killed.
94ab4c2fe adds only BUILD.md results. Webby's drift check: a36523713..d37210288
changes none of the 8 paths and no path either suite reads; merge-tree clean.
Rulings A and C (sage-1914, sage-2061). The dropped real-model coverage goes
to DEFERRED in the follow-up doc commit.
2026-10-21 16:44:37 -05:00
jason.woltje 3a853f35dc docs: Q198 system-manager design r6.1 (Huey, Scrooge approved r6 and r6.1, mos-1222)
Integrates origin/huey/system-manager-design 1715efb78 (base 6c75887b0) as one
doc-only commit: docs/plans/2026-10-21_q198-system-manager.md (blob 4fbebd3e,
pinned code evidence base 6c75887b0) plus Huey's 14 BUILD-LOG lines and 7
SESSIONS lines, appended unchanged. Scrooge approved r6 (scrooge-0004) and
confirmed r6.1 N1-N3 closed (scrooge-0005). No package, script, runtime or
queue change. Slices S1-S6 go to the queue under Vikunja 452.
2026-10-21 16:43:25 -05:00
jason.woltje 111ec559c8 brief template: seats hand off directly to the next seat and Sage over T3 (Q210, mos-1221) 2026-10-21 16:36:53 -05:00
jason.woltje 25ffaae832 deferred: T27 sweep test leaves two sleep 60 children; the fix is a process-group kill in both t.after hooks (row 251 landing d37210288, darkwing-0117, Dewey c30168) 2026-10-21 16:36:29 -05:00
jason.woltje d372102882 row 251: T27 adds its key with -t 2 and sleeps 3.5 s, because ssh-agent counts lifetimes in whole seconds (#1756)
Candidate darkwing/row251 27f01ef63 on 3b0aef995, manifest f2bdd684
(BUILD.md and packages/bus/tests/host-run.test.mjs). Dewey APPROVE r2,
rev 2996 (#1756 c30168). Gate on Sage's slot: bus suite whole in a clean
worktree on f7a77721a plus the two manifest paths (b79ad5f2c adds docs only),
627/627 at 21:30:33Z.
Darkwing's slot runs (darkwing-0114) are on the old base and are not the
gate.
2026-10-21 16:30:50 -05:00
jason.woltje b79ad5f2cb brief: the human deletes a creative instance, chained after row 194 (REQ-COS-3, mos-1215); window plan W11 posts on 435 2026-10-21 16:20:12 -05:00
jason.woltje 3fb00018e0 window plan: draft 1 correction, 7333 acceptance was Mos's (mos-1015), Q1/Q3/Q4 answered (mos-1214) 2026-10-21 16:18:35 -05:00
jason.woltje f7a77721a9 window plan: 10-24 re-pin draft 1, NEW 7247d80c7 with --tester-socket (mos-1145, mos-1211) 2026-10-21 16:15:48 -05:00
jason.woltje 829e5f8340 sessions: Sage row 196 landing, rows 253 and 254 launched, 194 b4 ruling, queue revs to 2994, window draft 1 2026-10-21 16:14:06 -05:00
jason.woltje abb352d27e queue: revs 2977-2993; Morgana 244 start, in-review and outcome (2977-2979), Gander 196 r6 manifest (2980/2981), Sage 244 and 196 jarvis review requests, Duckworth 196 m2 approve record (2986), Sage 196 landing note and done, row 254 issue #1759, Darkwing 251 r2 in-progress and in-review (2990/2991), rows 253 and 254 briefed 2026-10-21 16:13:56 -05:00
jason.woltje c3d88840c5 row 196: BUILD-LOG lines and two DEFERRED entries after the landing (#1694)
Doc-only append after 7247d80c7. BUILD-LOG takes Gander's ten row 196 lines from 527b9a1e6 unchanged. DEFERRED records Duckworth's C1 (round 1 N2, the dead testerNoSignIn, binding the next serve.mjs row) and round 2 N5 (the Console library routes row decides on library.sync for the tester listener). No test reads either file's content.
2026-10-21 15:59:48 -05:00
jason.woltje 7247d80c7a row 196: human boundary on peer credentials, interpreter receipt and the Console tester socket (#1694)
Candidate 527b9a1e6 (gander/row196-r6-prd19, base f48725cfc), the 39 manifest paths of CANDIDATE.sha256 537d30aef70b6cd1 at ec1e7fad8. Duckworth approved round 1 outside B1/B2 (rev 2973, comment 30145) and round 2 merge-scoped (rev 2986, comment 30156). Gate gander-0066 on grant sage-2145: 2334 pass, 0 fail, 1 skip; mutants 38/38 killed. BUILD-LOG lines and Duckworth's C1 DEFERRED entry follow as a doc-only append.
2026-10-21 15:55:39 -05:00
jason.woltje 6661732925 sessions: Sage row 222 landing, PRD 1.9 and 1.10, Pocket ID row 255, 196 r6 grants, overlap class rule (mos-1204) 2026-10-21 15:46:03 -05:00
jason.woltje 21def28502 queue: revs 2968-2976; Gander 196 r5 manifest and r6 changes move, Sage 222 review request and done, Duckworth 196 m1 changes record, rows 254 and 255 added 2026-10-21 15:45:45 -05:00
jason.woltje add0f1aae5 PRD 1.10: REQ-INST-2, a bundled Pocket ID for users with no OIDC provider, post-v1 (Q203, mos-1204)
Adds REQ-INST-2 after REQ-INST-1 as drafted in sage-2144 and ruled in mos-1204: Jason's Q203 sentence verbatim, marked post-v1 the way REQ-FED-1 is, with Mos's reading (mos-1202) labelled as his. A Version 1.10 technical note records, as fact, that REQ-WEB-2 uses the Console's own OIDC sign-in while the out-of-scope list still names 'Pocket ID and SSO', which Jason hasn't ruled on (vikunja:19/459). The list and the Pocket ID technical note are unchanged. requirements.json goes to 1.10 with 70 ids, and both requirements tests are updated to match. Design row 255 (#1760, Vikunja 458).
2026-10-21 15:26:45 -05:00
jason.woltje 7d08237e17 brief: bundled Pocket ID for users with no OIDC provider, design (Q203, Vikunja #458, mos-1202) 2026-10-21 15:21:38 -05:00
jason.woltje f48725cfc1 PRD 1.9: REQ-WEB-2, Console decide buttons for a human the Console signed in, and the REQ-DEC-3 amendment (mos-1202)
Jason approved the buttons in decision 00ed58e2 (vikunja:19/266) and chose
O6 in Q203 (OIDC-only), relayed by Mos in mos-1202 with "Land PRD 1.9 with
REQ-WEB-2 as written". The wording is sage-2067's draft. requirements.json
goes to 1.9 with 69 ids; tasks suite 97/0 and bus requirements.test.mjs 3/0
on Sage's slot.
2026-10-21 15:19:43 -05:00
jason.woltje 0de97f429d brief: library sync follow-up, client timeout, STATUS codes and README (row 222 deferrals, #1723) 2026-10-21 15:16:54 -05:00
jason.woltje 0b33f5e9db row 222: C2-03a fetch-only library sync, askpass helper, bus verb and timer (#1723)
Candidate c9aa9c2ee (megavolt, manifest c2121b55, 15 paths), approved by
Dewey (rev 2966, comment 30138). Gate on Sage's slot by Megavolt,
20:08:37Z to 20:11:33Z: library 77/77, bus 609/609, webui library-cli 1/1
and pinned-copy 10/10, cli stack-copy 17/17, every scripts/test-*.sh rc=0,
fixture tokens 0 hits; mutant kills carried from 4a0e0ab3a with equal blobs.
2026-10-21 15:13:31 -05:00
jason.woltje 3586955286 sessions: Sage row 250 landing, 196 r5 run 4 and resume, F27 row 253; Dewey 66 r4, 251 r1 and 222 r1 lines; Darkwing 251 line 2026-10-21 15:04:41 -05:00
jason.woltje a54a17f3d8 queue: revs 2905-2967 (rows 66, 215, 243, 250 landings; 196, 222, 244, 250, 251 rounds; row 253 added)
Includes other seats' revs: dewey 2905 2966; filbert 2906 2924 2950 2957; herb 2917-2919; morgana 2928 2933 2934; gizmoduck 2935 2945 2946 2951-2953; darkwing 2938 2944 2947; webby 2939; megavolt 2960 2961.
2026-10-21 15:04:30 -05:00
jason.woltje 0cdead66cd brief: F27, case2-unit.sh and case1-accept.sh move to --tester-socket, chained after row 196 (#1758)
Mos ruling mos-1198 item 4. Owner Gander, reviewer Duckworth, gate owner Sage.
2026-10-21 14:47:32 -05:00
jason.woltje 1b6158ce26 row 250: K12 holds the stop's release while it reads the shim, the release answers the events read's reason, and R13 closes its controller (#1755)
Candidate gizmoduck/row250-r2 c1a858975 on 3b0aef995, manifest eca0b8e2.
Filbert APPROVE rev 2957 (#1755 c30130). Gate on Sage's slot (grant sage-2109,
gizmoduck-0150): P1/P2/M1 probes as predicted, conversation whole 3x 183/183
and a concurrent pair 183/183 each, control-board whole 124/124.
2026-10-21 14:42:48 -05:00
jason.woltje 081ff6b128 sessions: Sage row 215 landing, 196 r4 grant after the base change, slot order for 250, 222, 244 and 251; Herb row 215 line 2026-10-21 14:35:05 -05:00
jason.woltje be86adbff2 sessions: Filbert row 250 round 2 static review, approve 2026-10-21 14:35:05 -05:00
jason.woltje d163afc47f sessions: Filbert row 250 round 1 static review, changes 2026-10-21 14:35:04 -05:00
jason.woltje e54e054632 row 215: C2-04 the library entry in the business file, consumer skips, M9 organization-projects-protected, the bare mirror, library.file and library.status (#1716)
The business file accepts a kind "library" project entry, and each consumer
that assumed a project root skips it. An organization write whose projects
differ from the file's is refused (M9). The bare mirror is created at the
projectRepo path with no remote. library.file and library.status are human
only and refuse an agent session with human-required.
Candidate herb/row215-on197 dde3445ab on a36523713, Filbert APPROVE rev 2924.
2026-10-21 14:24:37 -05:00
jason.woltje 6096b051b1 row 243: tests that depend on the gate umask set their file modes; stack-instances bootstraps under an explicit umask with a 077 subtest (#1754)
process.test, proof-cli.test and sso.test set the too-open mode with chmod
instead of taking it from the umask. stack-instances.test bootstraps under an
explicit umask and asserts the 0700 config dir under umask 077.
Candidate morgana/row243 6581f750e (code 137bda3af), Webby APPROVE rev 2939.
2026-10-21 14:12:03 -05:00
jason.woltje 9a8c8860d3 sessions: Sage row 66 landing, J2 brief and REQ-WEB-2 wording, gate coordination for 196 r2, 215, 243, 250, 251 2026-10-21 14:06:16 -05:00
jason.woltje 6195a00f8d sessions: Filbert row 215 round 2 merge-scoped review, approve 2026-10-21 13:55:22 -05:00
jason.woltje 3b0aef9952 deferred: row 66 live checks, Claude Code at the first re-pin with row 66 and pi after #383, Vikunja #454 (mos-1186) 2026-10-21 13:55:07 -05:00
jason.woltje 2c38325eca row 66: managed sessions run the unslop check on both harnesses, the operator note on the RESULT, a correction notice on the next turn, and unslop.jsonl counts (#1559)
Lands Sage's sage/row66-r5 at 7ffb640ac, round 4 (r4d 82c830779) rebased onto a36523713 after row 197,
approved by Dewey (comment 30085) and Filbert (30086) on manifest 6cfd812da4ca (23 paths, rev 2905). The
rebase had no conflict. The range-diff is = except one pi-session.test.mjs hunk header. Patch-id without
agents/ is d67275ac4251 on 7b9737953, a36523713 and this commit's parent. Gate (mos-1186): unslop,
harness, cli and every scripts/test-*.sh green on r4d, harness 149/0 again on r5. Landing sessions on a
scratch root from the candidate tree: Claude Code r4ab24630d323 showed the note, the injected notice and
counts checked 2, flagged 1, notices 1. Pi r1dd94171bede is launch only until #383 (Vikunja #454).
2026-10-21 13:51:28 -05:00
jason.woltje 640aa03f27 brief: Console inbox Approve and Deny for grant requests, Vikunja #435 (mos-1193) 2026-10-21 13:44:03 -05:00
Herbandjason.woltje a365237133 test: resolve the real Docker binary inside lane fixtures
(cherry picked from commit c45ddeb6bd)
2026-10-21 13:28:40 -05:00
jason.woltje 5afff54908 brief: T27 row 251 records the monotonic-boundary check, 8 of 80 adds lost the key (mos-1185 item 2) 2026-10-21 12:20:21 -05:00
jason.woltje f33932921c brief: T27 lists no identities right after ssh-add -t 1, Vikunja #453 (mos-1185 item 2); row 197 lane-b observation (item 3) 2026-10-21 12:12:46 -05:00
jason.woltje 1be656ac97 brief: K12 reads cgroup.events after cgroup.kill under load, Vikunja #450 (mos-1182 item 3) 2026-10-21 11:09:37 -05:00
jason.woltje 19d3d5f026 sessions: Filbert row 66 round 4 review, approve 2026-10-21 10:21:00 -05:00
jason.woltje 6c75887b0c sessions: Sage 10-21 afternoon (rows 249, 197, 222, 66, queue revs 2642-2904), with pending Dewey and Researcher lines 2026-10-21 10:19:14 -05:00
jason.woltje 0636721e60 queue: revs 2642-2904 (rows 234, 235, 249 landed; 212, 213, 218, 221, 231, 247 landed; 228, 233, 238, 240, 195, 245, 248 landed; 197 r8 approve, 215 r1 approve, 66 round 4; Case 2 and installer row notes)
Sweeps other seats' revs: Gizmoduck (234, 235, 249), Duckworth (234, 235, 195, 245, 249 verdicts),
Darkwing (233, 240, 195, 245), Filbert (233, 240, 215 verdicts), Gosalyn (212, 221, 231, 247),
Morgana (213), Researcher (228), Launchpad (238), Herb (197, 215), Webby (197, 212, 213, 218, 221,
228, 231, 238, 247, 248 verdicts). The rest are Sage's notes, landings, moves and review requests.
2026-10-21 10:18:29 -05:00
jason.woltje 7b9737953a deferred: row 248 Webby N1, the grant executor test sleep 30 can outlive its test; Duckworth deferred it in the row 249 review (#1751 c30070) 2026-10-21 09:55:13 -05:00
jason.woltje 9de5a57abd row 249: row 235 follow-up, a grant whose install never returned records hostLineLeft, since the remote add can outlive an abort or a timeout (#1751)
An abort or a timeout kills only the local ssh. A non-pty sshd command gets no SIGHUP, so the remote
add can still write its line after the undo's remove. The broker now marks install done only after
`await install(...)` returns. When it never returned, the undo records hostLineLeft with the tag, so
grant.failed and status name the line, hosts.remove refuses until `mosaic hosts sweep` clears it.
The :432 test comment now matches. Row a's enroll does no remote add, so it has no such race.

Candidate gizmoduck/row249-on-8a04 05595794b (Gizmoduck), manifest 3a969bb136bc, approved by
Duckworth in round 1 (rev 2889-2890 request c30068, verdict c30070). Gate on Sage's slot 14:53Z
(sage-2026): grant-executor.test.mjs whole 39/0 and bus 598/0 with no stub left, and C1, which
drops the `if (!installed)` branch, fails G8 and both G23 tests. Webby's N1 on X5 `sleep 30` is
deferred by Duckworth (DEFERRED.md).
2026-10-21 09:54:29 -05:00
jason.woltje 8ca064158a sessions: Filbert row 215 candidate review r1, approve 2026-10-21 08:43:38 -05:00
jason.woltje 8a04f4aa4a row 248: row 235 follow-up, the grant-executor hold-add and hold-remove stubs stop when their test dir is gone, so no stub outlives its test (#1750)
The row 197 r8 D5 proof stopped on a leftover hold-add stub. G23 and G13 write release, finish and
remove the test dir before the stub polls again, so the stub looped forever on sshd's side. 4 runs
of the file left 7 stubs. Both hold loops now also stop once $D is gone.

Candidate 4d99c178b, approved by Webby in round 1 (rev 2883, webby-0080). Gate on Sage's slot
13:05-13:07Z: the whole file 3 runs at 37/0 with no stub left, bus 596/0, and a mutant that drops
the hold-add check leaves 2 stubs. The late remote add the leak exposed is row 249 (#1751).
2026-10-21 08:16:49 -05:00
jason.woltje bc579f7a84 docs: host run sheet section 4, the apt-get download W: line as root is expected, and the profile's sha256 is checked again at /etc/apparmor.d (mos-1168) 2026-10-21 08:14:11 -05:00
jason.woltje 6de1ebc629 plans: row 235 follow-up brief, the grant undo records a host line it can't prove gone (mos-1166, gizmoduck-0139, duckworth-0091) 2026-10-21 08:11:21 -05:00
jason.woltje 540239b6b7 plans: row 235 follow-up brief, the held grant-executor stubs stop when their test dir is gone 2026-10-21 08:03:55 -05:00
jason.woltje 6d5545d442 row 245: row 195 follow-up, F9 runs node as root only at the pinned root-only path, the header and TOOLS.md list what root runs, F6 refuses .. after claude-<pin>/ (Duckworth N1-N3, #1693)
Darkwing's ef8b4439e (darkwing/row245), Duckworth round 1 APPROVE (rev 2849, comment 30043),
manifest 69bc05f4f706, 5 paths. Slot run sage-1961 (darkwing-0107): singles 23/0, mutants 16/16
killed, N1 and N3 among them. DESIGN.md:336-338 stays unedited, superseded by gosalyn-0087.
Sage gate on 856c1826b plus these 5 paths (12:24-12:35Z): case1-accept.test.mjs alone 23/0,
cli 681/0, every scripts/test-*.sh 429/0.
2026-10-21 07:35:39 -05:00
jason.woltje 856c1826bc row 247: C2-20b persona import follow-up, keys from config.yaml print as JSON strings, the dry run applies C2-08's fence and refuses, privateDir refuses an EEXIST race by name (#1749)
Gosalyn's 6d43618a3 (gosalyn/c2-20b), Webby round 1 APPROVE webby-0076 (rev 2852), manifest 6d3f279f692b,
4 paths. Webby's row 221 notes N1, N2 and N4. Slot runs sage-1969 (red base, the builder's comma
regression) and sage-1971 (14/0, M1-M4 killed). M1/M2 sit at :248 in this commit, not :237 as
BUILD.md says (gosalyn-0111). JSON.stringify leaves DEL, C1, U+2028/9 and bidi raw, a known limit
by sage-1964.
Sage gate on 5c6f73ed7 plus these 4 paths (12:10-12:21Z): the test file alone 14/0, cli 680/0,
every scripts/test-*.sh 429/0. f8276c5eb adds only docs/SESSIONS and docs/case2 sheets no test reads.
2026-10-21 07:22:07 -05:00
jason.woltje f8276c5eb3 row 218: C2-12 setup sheet for Melanie and the library survey run sheet (#1719)
Doc only, Sage's sage/row218 89ba79d94 (three commits squashed). Webby APPROVE round 1 (webby-0075,
rev 2848), round 2 (webby-0077, rev 2856) and round 3 (webby-0078, rev 2860). docs/case2/SETUP-SHEET.md
tells Melanie what the agents read, the playground, link and property forms, and what changes for
Bean and Chet, with M5's 1,200 character reply total (mos-1165). It goes to her only after C2-06
lands and on Jason's go (#419). docs/case2/SURVEY-RUN.md is design 10 step 7's run sheet: the
bare mirror as the source, a node check, output lines and refusals from survey.mjs. Claim sources
and rulings are in agents/sage/work/queue-218/BUILD.md. No test reads either doc path.
2026-10-21 07:05:39 -05:00
jason.woltje b65f3a0e84 sessions: Darkwing row 245 slot green, round 1 in review 2026-10-21 06:50:41 -05:00
jason.woltje 5c6f73ed75 plans: C2-03a brief, the mirror HEAD is a symbolic ref to refs/heads/served so the C2-12 survey reads the served commit
The survey reads HEAD and has no ref flag, and design 10 step 7 surveys the bus mirror. Row 222 is not
built yet, so this adds one requirement and one test to its brief before the build starts.
2026-10-21 06:39:33 -05:00
jason.woltje 947101d8a3 sessions: Sage 235, 221 and C2-20b landings, 197 r7 request and proof prep 2026-10-21 06:28:49 -05:00
jason.woltje 335bb3e30f plans: C2-20b brief (row 221 follow-up, Webby N1, N2 and N4) and DEFERRED for N3, Morgana's 213 B3 anchor
Webby approved row 221 round 1 (webby-0073) with four notes that don't block. N1, N2 and N4 are in
scripts/case2-persona-import.mjs and go in before Jason's one import run (sage-1941), as row C2-20b,
owned by Gosalyn and reviewed by Webby. N3 is tooling outside the product and waits in DEFERRED.
2026-10-21 06:23:41 -05:00
jason.woltje 3007664504 row 221: C2-20 Bean and Chet persona import, stage and install script with a count-only dry run, personaTextFault exported from bundle.mjs, yaml 2.9.0 exact, fixture Hermes home and read trace (#1722)
Lands Gosalyn's round 1 candidate, 8f403d0d4 on gosalyn/c2-20-r2 (48f044ccc plus its BUILD.md, on
62ddc96cc), approved by Webby (webby-0073, REVIEW-r1 a0a00630e, rev 2808). 22 paths, manifest
20f05e3a6ad5. No 221 path changed between 62ddc96cc and this commit's parent. Patch-id dfbb754c6fb4, the
same as 62ddc96cc..8f403d0d4. The two state.db fixtures and auth.json are short text stand-ins.

Webby's N1, N2 and N4 go to the C2-20b follow-up row before Jason's import run. N3 (mutants.py:48
anchor) is in DEFERRED.md. The script itself runs only under Jason's go (design 10 step 6, 9.1).

Evidence: Gosalyn's singles on my slot, 419/0 on 48f044ccc (gosalyn-0104).
Gate on my slot, 11:07:50-11:19Z on b1fece6f0 plus the 22 paths: case2-persona-import.test.mjs alone
11/0, harness 140/0 (bundle.mjs changed), cli 677/0, and every scripts/test-*.sh green (auth 15,
conductor 17, config 31, discord 78, extension-package 18, foundation 44, land-work 86, queue 156 and 28,
release 14, task 98, all 0 failed). Lands before row 197 r7: no shared paths, and r7's proof candidates
both carry it (sage-1954).
2026-10-21 06:19:41 -05:00
jason.woltje b1fece6f0a row 235: machine grant row b, raise binding, executor, reconcile, revoke and sweep, creative roles refused at raise, recheck and host.run, N10 (#1741)
Lands Gizmoduck's round 1 candidate, ed4193316 on gizmoduck/row235-e (one commit on 62ddc96cc), approved
by Duckworth (duckworth-0089, REVIEW-r1 d9ecec514 on duckworth/reviews, #1741 comment 30022). 13 paths,
manifest dad377ca8fe4. No 235 path changed between 62ddc96cc and this commit's parent. Patch-id
c355d2fc457d, the same as 62ddc96cc..ed4193316. broker.mjs keeps row 213's import and decision.raise
creative refusal as landed.

Creative roles (mos-1163, mos-1164, sage-1908): #hostDefinition refuses host-creative-role at the raise
and at the step 1 recheck, and #hostAccess refuses it at host.run before reading the grant record, which
stays for hosts.revoke. Duckworth checked from the code that a creative role can't raise, approve or
spend a host grant, and ruled the upsert mutant equivalent.

Evidence: Gizmoduck's runs on my slot. B1-B37 on 5df4b52c5, and run 2 on 534f2254a (10:12:52-10:14:51Z):
grant-host 9/9, grant-executor 37/37 and grant-enroll 24/24, each run whole, with B16, B23, B27, B38 and
B39 killed. B1-B39: 38 killed, and B17 is equivalent (sage-1904).
Gate on my slot, 10:30:55-10:42:43Z on 29ce1e360 plus the 13 paths: bus 596/0 (its first whole run on
this head, duckworth-0089 N1), business 200/0, cli 666/0, and every scripts/test-*.sh green (auth 15,
conductor 17, config 31, discord 78, extension-package 18, foundation 44, land-work 86, queue 156 and 28,
release 14, task 98, all 0 failed).
2026-10-21 05:42:52 -05:00
jason.woltje aa19a2464e sessions: Darkwing row 245 built, slot asked 2026-10-21 05:12:45 -05:00
jason.woltje 29ce1e3602 row 231: C2-01b library reader and survey fixes: control and bidi escapes, front matter list links, an unresolved body embed to a non-.md target is an attachment (#1733)
Lands Gosalyn's round 2 candidate, f37a65857 on gosalyn/c2-01b-r2 (base fefd54e13; commits 3647a5a93,
88daaac50, f37a65857), approved by Webby at merge scope (webby-0072, REVIEW-r2 efd6c1f02 on webby/reviews,
#1733 comment 30005, rev 2787). Nine paths, manifest 312c16fc4f65. No 231 path changed between fefd54e13
and this commit's parent. Patch-id 59b98b1b3e00, the same as fefd54e13..f37a65857.

Evidence: Gosalyn's singles on my slot, 61/0 on r2 (gosalyn-0099; run 1 60/1 was a test order defect).
Gate on my slot, 10:05:31-10:07:52Z on 62ddc96cc plus the nine paths: library 45/0, and every scripts/test-*.sh
green (auth 15, conductor 17, config 31, discord 78, extension-package 18, foundation 44, land-work 86,
queue 156 and 28, release 14, task 98, all 0 failed).
Webby's N4 (README:88 "A link to ... an attachment is R4" next to the embed paragraph) is doc-only and
stays as restored (sage-1917).
2026-10-21 05:09:23 -05:00
jason.woltje 62ddc96cc7 plans: row 195 follow-up (Duckworth N1-N3) and the .53 window row, which carries 195's done condition after its early done move 2026-10-21 05:03:21 -05:00
jason.woltje d6cff0cdd8 deferred: Duckworth's N1-N3 on row 195, the Case 1 acceptance script's root parse order, header and prefix match 2026-10-21 05:01:46 -05:00
jason.woltje 361ba2387f row 213: Case 2 C2-08 creative roles, persona file and block, M1, M2, M6, M10, prompt passed by file (#1714)
Lands Morgana's round 4 candidate, 2b3e67e36 (base c771a36f4, branch morgana/row213-r4), approved by Webby
(webby-0071, REVIEW-r4 02bb0afb3, rev 2775). Manifest digest 26d4d0ecff56, 35 paths, plus Morgana's
four packet files under agents/morgana/work/queue-213/ (base.txt, BUILD.md, candidate-manifest.sha256,
mutants.py): 39 paths, blobs and modes from the candidate. No 213 path changed between c771a36f4 and
this commit's parent. Patch-id f313e69b6f7e, the same as c771a36f4..2b3e67e36.

Evidence: Morgana's slot run on 2b3e67e36 (sage-1844): singles 191/0 and 31/31 mutants killed.
Gate on my slot (sage-r195land, base 38b83ea5c plus 195's 5 and 213's 39 paths, 09:45:52-09:57:52Z): business 200/0, bus 542/0, harness 140/0, cli 663/0; scripts auth 15/0, conductor 17/0, config 31/0, discord 78/0, extension-package 18/0, foundation 44/0, land-work 86/0, queue 156/0 plus 28/0, release 14/0, task 98/0; the models mutant L1 killed (launch-settings 15/1), restore matched.
Between the gate base 38b83ea5c and 4364dddb0 only docs/plans/2026-10-20_host-credentials.md changed (01e1fe512, 4364dddb0), which no test reads. Row 195 landed as this commit's parent; it shares no path with 213.
Webby's N2 (a host grant for a creative role) is a row 235 acceptance item (mos-1163), not a deferral.
2026-10-21 04:58:30 -05:00
jason.woltje b650146479 row 195: scripts/case1-accept.sh, root's Case 1 acceptance (F1-F11, P1-P11), its test, TOOLS.md entry (#1693)
Lands Darkwing's manifest round 1 candidate, 37171f65b (base 4ced5e63d), approved by Duckworth
(duckworth-0088, REVIEW-m1 6afcee2a5, #1693 comment 29988, rev 2758). Five paths:
scripts/case1-accept.sh (100755), packages/cli/tests/case1-accept.test.mjs, docs/TOOLS.md,
agents/darkwing/work/queue-195/DESIGN.md (r7, approved duckworth-0087) and BUILD.md. No 195 path changed
between 4ced5e63d and this commit's parent. Patch-id 656e43ff25de, the same as 4ced5e63d..37171f65b.

Evidence: Darkwing's slot runs: single 22/22 (sage-1829), 12/12 mutants killed and gate cli 662/0 plus
selftests 429/0 on ddf7dce6c (sage-1865, sage-1870).
Gate on my slot (sage-r195land, base 38b83ea5c plus 195's 5 and 213's 39 paths, 09:45:52-09:57:52Z): business 200/0, bus 542/0, harness 140/0, cli 663/0; scripts auth 15/0, conductor 17/0, config 31/0, discord 78/0, extension-package 18/0, foundation 44/0, land-work 86/0, queue 156/0 plus 28/0, release 14/0, task 98/0; the models mutant L1 killed (launch-settings 15/1), restore matched.
Between the gate base 38b83ea5c and 4364dddb0 only docs/plans/2026-10-20_host-credentials.md changed (01e1fe512, 4364dddb0), which no test reads.
Duckworth's notes N1-N3 go to docs/plans/DEFERRED.md in the next commit.
2026-10-21 04:58:17 -05:00
jason.woltje 4364dddb0d plans: row b (235) host.run also refuses a creative agent at spend time, grant record kept for revoke (mos-1164, sage-1908) 2026-10-21 04:49:11 -05:00
jason.woltje 01e1fe5128 plans: row b (235) refuses a host grant to a creative role, after row 213 lands (mos-1163, Webby N2 on 213 r4) 2026-10-21 04:40:22 -05:00
jason.woltje 38b83ea5c6 sessions: Sage, 212 landing, 197 proof stop and r6, rows 243/244, row 66 r4b 2026-10-21 04:20:46 -05:00
907 changed files with 114949 additions and 1318 deletions
+134
View File
@@ -5177,3 +5177,137 @@ Before: managed project/thread verbs had no Console conversation area. After: fi
2026-10-21T01:28:05Z | Darkwing | row 232 #1734 installer I1 build, round 1 in review | Before: stack-release.sh managed only user units (systemctl --user), and stack-copy.sh had no bundle copy. After: --units external (adopt, activate, rollback --to, status, confirm, revert, gate --since, AWAITING-UNITS, stale-start, external-pm, --plan --expect-from) and stack-copy check --units external, copy --bundle FILE SHA, wrapper ID --create; user mode byte-identical to the base by test. First build 0af0c73c6 on 00d4cc1f6; rebased onto row 200 (cb5fdb064) as a0ffabc3f on darkwing/row232-r1; --sso refused under external (D9), row 200 config_checks run under external (D10). Gate on Sage's slot (sage-1618): cli 561/0, every scripts/test-*.sh green; 17/17 mutants killed. Results commit 84f1a91e6 (pushed, seat branch only). Manifest 7a3b4ea1 (9 paths), queue revs 2595-2596, request comment 29825, reviewer Filbert. Packet agents/darkwing/work/queue-232/BUILD.md.
2026-10-21T04:50:44Z | Darkwing | row 233 #1735 installer I3 build, round 1 in review | Before: root had no upgrade driver for root-owned units and no host run sheet; stack-release.sh had no rehearse --backup last and no external plan refusals. After: scripts/stack-upgrade.sh upgrade and rollback (r6 A1-A5, A2f, R1-R4) with 20 tests, docs/guides/host-run-sheet.md, TOOLS.md lines, and on Sage's rulings stack-release.sh --backup last, BACKUP_STORE and the --plan refusals open-activation and migrate-required (3 tests). Base e65a3ab4d (row 232's landing). Gate on Sage's slot (sage-1704) on d99166ade: cli 616/0, every scripts/test-*.sh green, 1201/0 summed by awk; m1-m8 8/8 killed. Correction: the process sweep after the gate found an orphaned sleep 60 from the lock test's flock holder (N1); 08db6ac3f fixes it test only, Sage ruled the gate stands (sage-1707), rerun c0 20/0 and m1 killed with 0 left (sage-1708). Tip 1a1dc80ca (pushed, seat branch only). Manifest 464ce9eb (7 paths), queue revs 2644 and 2647, request comment 29901, reviewer Filbert. Packet agents/darkwing/work/queue-233/BUILD.md.
2026-10-21T06:37:41Z | Darkwing | row 240 #1746 installer I4 build, round 1 in review | Before: root had no host check for the bwrap AppArmor profile, its pins or a boot unit, and stack-upgrade.sh exited 1 args-failed when the args move after A5 failed, while exit 1 means the old copy runs. After: scripts/case1-hostcheck.sh (seven items, --check, --enforce, --upstream), scripts/case1-pins.sh, mosaic-hostcheck.service and 16 tests; the args move failure exits 5 args-failed, documented in TOOLS.md and run sheet section 6 and tested; run sheet section 3 puts the pinned npm on PATH and names the bin/claude.exe --claude path; sections 8 and 10 have precheck lines. Verification: slot run r1 on 47ec9fe2f failed at the singles (the new N1 test's after hook threw ENOENT after the fixture cleanup removed the root); b45852daa drops the hook; r2 on b45852daa green: singles 16/0 and 21/0, c0 plus M1-M8 8/8 killed, cli 639/0, scripts 585/0. Candidate darkwing/row240-r3 ad1b23ab2 on c771a36f4, manifest 573ece95 (9 paths), revs 2694 and 2695, comment 29943.
2026-10-21T09:00Z | Herb | row 215 C2-04 implementation started | Before: business files reject library entries and root consumers assume code projects; the organization writer can change all project mappings. Plan: approved manifest 2522025af on C2-01 a2c72ac95, Filbert reply to herb-0056, scope sage-1848/1852/1860. Focused slot sage-1869 observed expected red mapping and M9 cases, then 14/0 green for new T1/T2 cases, no skips; clear herb-0062 with empty test/fixture process scan. After that clear, T3/T4 tests and host-only mirror/bus implementation continue under sage-1874, unrun while Sage holds the slot. Full singles, suites and implementation review remain pending. No source commit, push or live change.
2026-10-21T13:29Z | Herb | row 215 C2-04 source verified for candidate review | Before: business code assumed every project had a root and organization writes could replace project mappings. After: library mappings load without agent checkouts or publish grants, project mappings are protected before and after serialization, host-only bare mirrors share a bounded publication lock with sync, and library.file/library.status are human-only async bus reads. Base f8276c5eb preserves all nine landed overlaps. Granted sage-2008 whole singles: 16 files, 451/0, no skips or cancellations, ended 13:27:27.279728Z; all source hashes unchanged, process scan empty, no own-path drift through 8a04f4aa4. Full landing gate and implementation review remain pending; no HTTP, sync writer or live change.
2026-10-20 19:09:44 UTC | Gander row 196 #1694 design phase | Before: tester TCP reaches every local uid and human proofs do not bind the socket peer. After: design draft at agents/gander/work/queue-196/DESIGN.md inventories listeners, proposes private tester HTTP and SO_PEERCRED binding, aligns the per-request principal contract with Morgana and Gizmoduck, and lists migration, tests, mutants and same-uid limits. Python versus other credential options and Console provenance require Duckworth ruling. Documentation only. No product code, suite, live probe, secret access or deployment.
2026-10-20 19:16:20 UTC | Gander row 196 #1694 design r2 | Before: Duckworth r1 requested concurrent helper-fd evidence (B1) and selected O1 with interpreter, proof-only and image conditions. After: design adds eight concurrent genuine proof processes plus a racing copier, M20 swapped socket and post-helper socket survival, root-owned system ELF pinning and activation evidence, safe gid validation, cap traffic without helpers, and unchanged P19 R2 text. Mos accepted socket-only tester access (mos-1015 via sage-1363); any authenticated browser relay is a separate row. Documentation coverage checks passed. No product code, suites or live action.
2026-10-20 19:21:19 UTC | Gander row 196 #1694 design approval and N5 | Before: Duckworth approved r2 (duckworth-0009, cb6d840df) with a nonblocking interpreter-upgrade note. After: r3 chooses startup safety revalidation, appends actual interpreter identity to bus/peercred-starts.jsonl and retains old activation evidence. Operator re-pin uses the next reviewed copy, respecting already-active refusal. Added task-by-task PLAN.md for inline implementation and independent manifest review. Documentation checks passed. No product code, suites or live action.
2026-10-20 19:34:28 UTC | Gander row 196 build paused at design mismatch | Before: approved design promised Unix tester cleanup only for the owned inode. After: scratch test shows Node/libuv close unlinks a replacement inode before JS close handlers. Evidence agents/gander/work/queue-196/evidence/tester-cleanup-blocker.txt. Sent Sage/Duckworth gander-0016/0017, recommending explicit same-uid residual with private 0700 parent retained. Interpreter, concurrent peer, principal, human, peer-transport, transport, tester and process single files passed. Partial code uncommitted, tester transport not wired. No suites, mutant batches or live actions.
2026-10-21 18:45 UTC | Gander row 196 preservation before rebase | Sage-2051, Mos order mos-1193, explicitly authorizes commit and fast-forward push of the current build before deferred full verification. Product and evidence preserved together; prior focused checks and stopped gates are recorded in the row196 packet, with no claim of full acceptance. Next: rebase onto a36523713 on new gander/row196-r2, report range-diff/patch-id/conflicts, then await Sage's clear for M1-M29 and all requested suites. No live action, force push, branch deletion or tests during hold.
2026-10-21T16:34:44Z | Huey | Q198/Q199 system-manager design, mos-1183, Vikunja 452 | Before: pinned foundation 6c75887b0 has separate bus, development queue, run evidence, turn/cohort controls and launch/usage paths; the assignment requests a mechanical manager design. After: docs/plans/2026-10-21_q198-system-manager.md proposes admission/cooldown, priority and safe interruption, durable requests, bounded retry/DLQ/replay/rerouting, Console monitoring, optional decision adapters with USD reservations, six ordered slices and three recommended owner decisions. Verification: 26 pinned file:line references resolve, ten-line summary, manual source/contract review, git diff --check and installed queue guard pass. No builds/suites, runtime writes, credential reads, service changes or paid calls. Huey queue next refused the linked worktree, then returned nothing from canonical checkout; direct brief controls this assignment. Gitea issue and queue-row capture are handed to Sage under the no-credential-read/no-queue-write boundary.
2026-10-21T18:45:47Z | Huey | Q198 system-manager design r2, mos-1194, Vikunja 452 | Before: Scrooge requested changes on add7cb506 for decision-key worker exposure, cap scope and absent sampler ownership. After: distinct MOSAIC_DECISION_OPENROUTER_KEY with S6 sessionEnv canary requirement; exclusive per-instance key with per-key caps and provider limit on every enablement; S2 owns supervisor sampler and waits until after MVP/re-pin. Also records P1 interpretation, missing-confidence fallback and stand-in timeout selection, explains verified Noul spelling, excludes notifier/gateway retry loops with citations, and cites lifecycle revocation requirement. Verification: 30 pinned citation spans resolve, ten-line summary, manual diff/source review and whitespace/queue-guard checks. No builds, suites, live changes, credential reads or paid calls.
2026-10-21T19:56:11Z | Huey | Q198 design r3, mos-1201/1201a, Vikunja 452 | Before: Scrooge approved r2 7e785a08f with three notes. After: N1 names proposed system.health bus read verb and includes broker handler/authorization in S2 scope and review; N2 labels exclusive ownership as a setup attestation that cannot be mechanically proved and identifies provider key limit as real ceiling; N3 adds recommended Q4 for P1 narrowing and removes the Mos-flag instruction. Other design content retained. Verification: manual r2-to-r3 delta review, ten-line summary, whitespace and installed queue-guard checks. No builds, suites, live changes or paid calls.
2026-10-21T20:19:53Z | Huey | Q198 design r4, mos-1203, DECISIONS Q204, Vikunja 452 | Before: r3 a36952564 presented Q1–Q4 for owner approval. After: section 9 records Q20a–Q20c verbatim as approved; D11 labels Huey’s reading of configurable daily/monthly caps with $0.10/$1 defaults in the one instance config via reviewed schema; provider key ceiling and explicit enable/key requirements retained; Q4 pending, Jason restated 2026-10-21, P1 unchanged. Verification: quotes match DECISIONS ledger, unrelated sections and P1 equal r3, ten-line summary, whitespace and installed queue guard checked. No builds, suites, live changes or paid calls.
2026-10-21T20:48:49Z | Huey | Q198 design r5, mos-1206, DECISIONS Q205/Q206, Vikunja 452 | Before: r4 1e8bccff1 left Q4 pending and long outages could exhaust request retry budgets. After: protected mode separate from unchanged D1 human kill authority; mechanical detection, safe-point pause/proof, JEV-first endpoint-before-headless probes at 60-second increments to 600 seconds without attempt limit, upstream reset waits, shared D11 probe accounting, one test session then batches, proposed three-failed-exit escalation, frozen outage clocks/counters without DLQ, advisory online-service routing, Q4 superseded and Q22 pending. Thresholds/deadlines/batches/escalation explicitly labelled Huey readings. Acceptance proposals updated, no implementation. Verification: complete Q205/Q206 read, quotes match ledger, D1/inventory/Q1–Q3 unchanged, 30 pinned citation references resolve, 11-line summary, manual consistency/diff review, whitespace and installed queue guard checked. No builds, suites, real probes, live changes or paid calls.
2026-10-21T21:04:37Z | Huey | Q198 design r6, mos-1208/mos-1210, DECISIONS Q207, scrooge-0003, Vikunja 452 | Before: r5 fd44f7c60 gated probes on JEV and lacked request-local resume failure separation. After: parallel independent probes; central JEV/smaller-model/rules endpoint chain, per-model timeout/calibration, 4 KiB metadata limit and isolated fallback credentials; subscription quota vs metered USD accounting and separately enabled paid-probe budget (proposed $0 defaults). S-F1–S-F7: bounded outage classification, request-local D6/two-resume DLQ rule and batch definition; escalation latch with authorized revision-bound system.recovery.release separate from kill clear; cooperative F5 pause/F6 proof only; proposed configurable 24-hour cumulative pause expiry; full Q205 kill sentence with labelled protected-mode interpretation; r3–r6 history. S5/S6 acceptance proposals updated. Verification: Q205/Q207 quotes match ledger, D1/inventory/Q1–Q3 unchanged, 30 pinned references resolve, summary within 15 lines, manual consistency/delta review, whitespace and installed queue guard checked. No builds, suites, real probes, live changes, credential reads or paid calls.
2026-10-21T21:39:25Z | Huey | Q198 r6.1 touch-up, mos-1222, scrooge-0004 N1–N3, Vikunja 452 | Before: approved r6 2ee68cd69 had unprovable session-call denial wording, implicit queue/late-call behavior and a partial Q207 paragraph. After: rule/S6 tests require session decision calls/output have no routing authority; non-waiting dispatchers use internal rules immediately; timed-out JEV does not occupy fallback decision slot but retains spend reservation; full Q207 paragraph copied exactly from DECISIONS; matching Q22 reading corrected. ENV_ALLOW and all runtime code unchanged. Verification: exact full-quote equality, obsolete wording absent, D1 unchanged, summary within 15 lines, manual N1–N3 delta review, whitespace and installed queue guard checked. No builds, suites, probes, live changes or paid calls. Review/handoff via T3 as Mos authorized.
2026-10-21T21:11:44Z | Della mos-1213 / Vikunja 460 planning phase | Before: PRD 1.10 has no email feature; MP 95b0298 and EP 7a64921 are read-only prior inputs. Scope: independent post-v1 email plan on della/email-plan, no implementation/live access/MVP or queue changes. Gitea issue enrollment belongs to Mos/Sage because this seat has no API credential.
2026-10-21T21:12:18Z | Della mos-1213 / Vikunja 460 planning verification | After: docs/plans/2026-10-21_email-plan-della.md is 341 lines, with 13 post-v1 rows and six Jason questions. Verified 42 pinned citation anchors, ten requested coverage areas, identical prior src trees, append-only records, clean whitespace and repository queue guard. No configured CI pipeline or CI-queue wrapper found in the current foundation; documentation-only validation applies, no product suites or live tests run. Phase B/C and Gitea issue/queue enrollment remain with Mos/Sage. Only della/email-plan is authorized for push.
2026-10-21T21:37:07Z | Della mos-1220 / Vikunja 460 phase B cross-review | Before: independent plans Della 191dff32f and Ludwig 4a27b73ac delivered. After: docs/plans/2026-10-21_email-review-by-della.md reviews all 218 Ludwig plan lines, records ten findings, five grafts, six retained strengths, nine disagreements and eleven merged Jason questions. Ludwig review 143415779 read in full after ludwig-0002 arrived; reconciliation records new mail-access action, no agent reroute and correction of Della dataRoot credential example. Original plan unchanged. Planning only, no product/MVP/queue/live change.
2026-10-21T21:43:02Z | Della mos-1223 / Vikunja 460 phase C synthesis | Before: independent plans/reviews complete, Mos selected Della base. After: docs/plans/2026-10-21_email-plan.md merges Ludwig grafts and accepted corrections, with 16 post-v1 rows (eight READY, eight WAIT/optional), eleven deduplicated Jason questions, per-row test paths and explicit Q210 non-v1 scheduling. Original Della plan/review preserved; Ludwig originals remain on their branch. Static checks cover graft/row/question/citation anchors and original blobs. No source code, suite, mailbox, secret file, service, MVP or queue change. Candidate goes to Ludwig before Sage landing/queue handoff, copying Mos.
2026-10-21T21:45:20Z | Della mos-1223 / ludwig-0004 focused corrections | Before: b096a16cc left content-key location implicit and E05 core registration marked ready. After: merged plan 399 lines fixes external configDir secret key/lifecycle namespace outside dataRoot backup/restore, E01 schema and E03 missing/expired-key restore tests, and E05/E06 test-local registry readiness with core kinds.mjs registration gated on approved E01/Q4. Sixteen rows and eleven questions retained; originals unchanged. Focused static checks and queue guard apply, no product/live changes. Reviewer will check changed lines only.
2026-10-21T22:24:12Z | Huey | T1 item 7 sessions design r1, mos-1232, Vikunja 463 | Before: origin/refactor cca206cdc keys assistant claims/stores/messages by thread and renders Pi compaction markers; row 194 r4 excludes thread context clear. After: docs/plans/2026-10-21_t1-sessions.md proposes independent per-agent sessions within threads on Pi/Claude, scoped claims/stores/messages/workspaces, completed compaction counts, owner-write/RBAC matrix, idempotent proven-stop/fresh-successor clear, common admission/kill checks, migration and seven acceptance groups, replacement REQ-ROLE-2/REQ-THREAD-2 text and three owner questions. PRD 1.12 USER-3/4 candidate 1509c7cc5 cited separately from base. Verification: 22 pinned references resolve, eight-line summary and three exact owner quotes; manual source/consistency review, whitespace and installed queue guard checked. No code, queue/PRD edits, builds, suites, credential reads, live changes or paid calls. MVP priority ahead of Q198 S1. Review via Scrooge, then Sage/Ludwig as Mos authorized.
2026-10-21T22:28:56Z | Huey | T1 sessions design r2, scrooge-0006, mos-1235/1236, Vikunja 463 | Before: r1 347278044 lacked the exact per-session checkout/single-writer invariant and safe runner drain ordering, and admitted other role instances. After: F1 exact workspace path, fenced checkout setup, legacy shared-workspace quiescence, clear retains old dirty/untracked/unpushed checkout and creates fresh approved checkout, T2 mutant; F2 dequeue fence and generation-bound turn-boundary idle proof before runner signal, busy drain stays clearing, T4 cases; F3 THREAD_DEFINITION only per Mos scope ruling, no role eligibility change; N1 private titles/history vs owner-visible count/activity projection; N2 Claude offline adapter/managed-store-reader dependency flagged as MVP risk. Section 8 records Mos’s Q1–Q3 readings, no questions to Jason. Verification: 27 pinned references resolve, summary within 15 lines, source/delta consistency review, whitespace and installed queue guard checked. No code, queue/PRD edits, builds/suites/live changes/provider calls/credential reads.
2026-10-21T22:30:20Z | Huey | T1 sessions design r3, scrooge-0007 R1, Vikunja 463 | Before: r2 e19e30df2 nested new session checkouts under the retained legacy instance workspace, allowing project-name collision or historical parent inspection to reach live siblings. After: exact path is dataRoot/session-workspaces/business/instance/session, outside the legacy root; canonicalized ancestor/descendant overlap refuses; T2 nesting mutant covers historical mount/inspection and a legacy project named sessions. All other r2 content retained as approved, revision label updated. Verification: old nested path absent, manual R1-only delta, whitespace and installed queue guard checked; no code/builds/suites/live changes/provider calls/credential reads.
2026-10-20 18:51:10 UTC | Row 191 #1689 design phase | Before: per-business launch revoke and per-binding Discord STOP leave task containers, active sessions and background work without one switch. Proposed per-data-root durable halt with human-only resume, generation-fenced starts, bounded concurrent termination, write-once stop receipts and existing event mirror; no schema migration. DESIGN.md inventories starter/continuation paths and container control-mount restriction. Sent to Dewey with Sage copied; implementation waits independent design approval. No tests, commits or live actions.
2026-10-20 18:57:51 UTC | Row 191 design revision | Dewey r1 changes: interim Console --send absence, reserved processing events and missing-state semantics required correction. DESIGN-r2.md now names CLI interim path, unavailable UI controls, trusted initialization and fail-closed missing leaf, container delete/replace mount tests, reservations and id-bound reconciliation. Small notes addressed including diagnostic seats and aliases. Recommended smaller Docker scope to Sage; design and scope approval pending, no code or test runs.
2026-10-20T19:50:56Z | Rocko | row 191 #1689 implementation stage: from independent brakes to shared root state, generation-fenced launcher and tracked stops, Discord/task guards and control HTTP/UI. Evidence is agents/rocko/work/queue-191/logs/ and PROGRESS.md. Fixture single files only so far; heavy verification and candidate not complete. Scope additions sage-1367 (one read-only CODE file) and sage-1392 (processing-only client socket timeout); no schema, proof baseline, live file/unit, commit or push change.
2026-10-20 22:58:45 UTC | Rocko | row 191 #1689 rebase inspection candidate | Rebuilt uncommitted kill-switch tree from da230ca48 onto landed row 190 base 00d4cc1f6 under new branch rocko/row191-r2-00d4. Hand merges retained instance flags and SSO/sign-out changes; fixture tests exposed and fixed SSO signer compatibility and two unknown-runtime cleanup defects. Final touched singles 249/249 across 26 files; 15 overlapping Client reader files 102/102. Manifest a4f780c2 has 78 paths; packet 185 files verified with scan clear. Mutants and owner gate remain pending; no review-ready or activation claim, no commit/push/live action.
2026-10-21 23:39:21 UTC | Rocko | row 191 #1689 inspection snapshot | Sage-2242 authorized a local inspection commit for Honker's row 194 S6. Created d52b4db1c on new rocko/row191-inspection-20261021, parent 00d4cc1f6, preserving the reviewed-design build and candidate a4f780c2 (78 paths). Static manifest/index/source scan and diff check verified; no tests run, no push credential or push attempt. Existing single-file evidence is historical, 249/249 and overlapping Client readers 102/102; suites/mutants/gate remain pending. Current code has verified runtime signalling and instance halt, but no dedicated per-run stop API yet; Honker and Sage notified of that seam directly. Snapshot is not review-ready or approved for live use.
2026-10-22 00:04:05 UTC | Rocko | row 191 #1689 per-run stop inspection | Implemented agreed Honker-0079/0081 stopRun contract with verified per-signal identity, fixed 5s+2s, durable first-owner join and immutable result plus later-exit observations. Focused CLEAR sage-2250: final 9 files 62/62, no skipped, after correcting host guard placement and peer-discovery fixture timeout isolation; initial failures and failed teardown logs retained, only own failed group stopped. Slot returned with cwd sweep clear. Sage published f7bf7dfec; sage-2265 clean rebase creates 7aa18b0f6 on dcd8d4dda under new branch, explicit Rocko identity, all 79 manifest product blobs identical so 62/62 evidence carried. Direct S6 handoff sent to Honker and Sage. Wider suites, mutants, review and activation remain pending.
2026-10-22T00:18:12Z | Sage (Opus 5.5) | row 254 landing (#1759), library.sync human timeout | Before: the human transport gave library.sync the 5-second default, so a sync longer than that reported outcome-unknown, and six library-* codes reached the Console as 502. After: 331597709 lands Megavolt's candidate (7 paths, tree d49e4626f, manifest digest be63cfbe recomputed and matched). human-cli.mjs waits 130 s for library.sync, past the server's 120 s hold, and 5 s for other verbs. webui bus.mjs maps library-sync-busy, library-diverged and library-accept-stale to 409, library-accept-invalid to 400, and library-credential-missing and library-fetch-failed to 503. channel-proof re-pinned. Merged-tree gate on the landing commit: library 77/0, bus 628/0, webui 305/0 (1 skip), cli 749/0 (23:44:33-23:55:11Z). eb9672c91 adds the README request-timeout sentence (Dewey N1) and a DEFERRED entry for the four library codes still at 502 (Dewey N2, binds the Console library routes row). Overlap sweep before push: 268 rebased to r2 ecd9b35eb (README only, approval carried webby-0096), 194 rebased to b7. Done rev 3072, #1759 closed.
2026-10-22 00:24:34 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 full gate on c78f48946 | stopped on second integration failure per sage-2275; singles 269/269, processing-control 61/61, bus 646/646; CLI interrupted with 26 observed failures; no further edits; cwd sweep empty and slot returned to Sage.
2026-10-22 00:48:20 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 eb3abba12 full gate | stopped at Discord 190/192; 32 singles 304/304, processing-control 61/61, bus 646/646, cli 761/761; two uninitialized Discord fixtures reported to Sage; no later run; cwd sweep empty, slot clear.
2026-10-22 00:58:27 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 sage-2294 fixture fix | e6800380d on eb3abba12, two test files/four additions, assertions preserved; 338-entry static all-package sweep recorded; no tests; sent Sage for publication and Honker for dependent gate.
2026-10-22 01:30:04 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 e6800380d resume | binding15/15, recover5/5, Discord192/192; stopped WebUI314 passed/4 failed/1 esbuild skip; processing polling violates sign-out/manual redirect and bar changes layout; no fixes/retries, cwd sweep empty, slot returned.
2026-10-22 01:38:08 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 sage-2317 Console integration fix | 8e1f55c1d on e6800380d; shared sign-out/manual redirect/interval and desktop frame fixes, assertions retained, six browser cases, 73 mutant sites preflight; syntax only, no tests; sent Sage/Honker.
2026-10-22 02:06:38 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 rebase sage-2329 | eafcbd3e7 on ddfb29af7, new branch, dispatcher retains processing and access; CLI/readme auto-merges checked; 87-path fd0f2740 manifest and 73-site preflight; Sage2333 published, awaiting CLEAR; no tests.
2026-10-22 02:20:51 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 eafcbd3e7 full gate | stopped singles313/6: six new browser cases count app freshness timer as processing timer; diagnosis sent Sage, no fix/retry; no suites/shells/mutants; cwd sweep empty, slot clear.
2026-10-22 02:23:13 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 sage-2345 timer fixture | 4db8b5778 on eafcbd3e7, one line attributes timer to processing.js; all assertions retained, no product change or tests; sent Sage and Honker; awaiting publication/CLEAR.
2026-10-22 02:25:29 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 sage-2349 record commit | 0f8235277 on 4db8b5778 adds packet BUILD.md cause record; product manifest remains ffb46fbd/87 paths; no amend, product change or tests; Sage/Honker notified.
2026-10-22 02:48:36 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 0f8235277 full gate second red | singles330/330, processing61/61, bus646/646, cli783/783, discord192/192; WebUI323/1/1 host esbuild skip; shell geometry1062vs1000; stopped/no retry, no later suites/shells/mutants; cwd sweep empty, slot returned, Sage escalates Mos.
2026-10-22 02:57:36 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 #1689 mos-1248 desktop layout restart | FF 5cd32f4c1 on 0f8235277: desktop grid allocates processing bar, existing shell assertions kept, visibility/no-scroll assertions added; 74 static mutant sites; candidate 2f93ef19; sent Webby/Sage for static review; no runs, awaiting review and CLEAR.
2026-10-22 03:11:09 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 191 static nav layout, mos-1249/1250 | FF da4334806 on 5cd32f4c1; controls first in nav, non-sticky per sage-2386/webby-0108; candidate-only placement assertion changed, landed shell assertions preserved; 77 mutants statically preflighted; manifest 245dceb1; Webby/Sage handoff sent, no runs, awaiting static look/publish/debug CLEAR.
2026-10-22 03:15:11 UTC | Rocko (d99326cc) | row 191 sage-2394 debug | da4334806 shell5/5 and processing-browser9/9, awk14/0/0; geometry heights reported with read-only distinction; cwd sweep[] and slot returned; full window awaits separate CLEAR.
2026-10-22 02:01:30 UTC | Sage (Claude Opus 5.5, 1ef1e4f8) | row 202 #1700 FED R5 landing | ddfb29af7 on 9c9732983: 6 manifest paths from a74cd9f87 (digests match CANDIDATE.sha256, patch-id 9d89077b equal); Duckworth APPROVE r5 rev 3026; C1 gate by Quackerjack on merge 3b86180b9: cli 771/771 skip 0 (run 2, run 1 red on gate TMPDIR length), 10 test-*.sh rc 0, M1-M13 killed; done rev 3108; landing note refused for length before the done move, so the record is the commit body and #1700 c30265; 191 and 194 rebased onto it (one scripts/mosaic case line)
2026-10-22 03:35:55 UTC | Sage (Claude Opus 5.5, 1ef1e4f8) | row 273 #1778 activate --send/--no-sso landing | 0bbf0f6d1 landed on 378a76b85, a rebase of cac7d0f67 (0042f713d) with all 6 range-diff pairs = and equal patch-ids; 4-path manifest e1031023 unchanged; Filbert APPROVE rev 3111 (c30308) carried merge-scoped under mos-1160, carry comment c30319 names 0bbf0f6d1. Gate on 0bbf0f6d1 by Darkwing: stack-release.test.mjs 218/218 skip 0, stack-release-external.test.mjs 25/25 skip 0, test-release.sh rc 0 (selftest 14/0, no skips), T58 controls c0 11/11 pass and c1 11/11 fail, M1-M7 killed. Rerun because row 202 changed scripts/mosaic, which stack-release.test.mjs copies. Red 1 was 978143bf4 (T53 test 6 usage pin). This doc commit adds the TOOLS.md usage line and F39 rules (Filbert N1).
2026-10-22 04:02:12 UTC | Rocko (d99326cc) | row191 full window0fa7bf421 | touched35files336pass, packages2403pass/1esbuildskip, shells425selftests+156queue node pass; SR01–07killed, SR08timeout,69unrun; stopped/no retry;88blobs restored,cwd sweep[],owned network removed,slot returned Sage; await Mos ruling.
2026-10-22 04:14:56 UTC | Rocko (d99326cc) | row191 control/resume sage-2427 | control12/12;SR08separate timeoutkill;49resumed assertionkills thenKS43survived;total56assertionkills+1timeout,1survivor,19unrun;88blobs restored,cwd sweep[],slot returned,Sage/Mos informed;no retry/edit.
2026-10-22 04:21:30 UTC | Rocko (d99326cc) | row191 KS43+19 retarget run | KS43assertionkill thenKS44invalid mutation syntax;57assertionkills+1timeout,1invalid,18unrun;stopped,no edit/retry;88hashes restored,cwd sweep[],slot returned,Sage/Mos notified.
2026-10-22 04:30:06 UTC | Rocko (d99326cc) | row191 KS44+18 resume | 10assertionkills thenKS54timeout-without-control despite dependency assertion;total67assertionkills+1timeoutkill,1unqualifiedtimeout,8unrun;88hashes restored,cwd sweep[],slot returned,Sage/Mos notified,no retry/edit.
2026-10-22 04:41:46 UTC | Rocko (Codex gpt-6.1-sol,d99326cc) | row191 #1689 builder complete/in-review | published0fa7bf421,manifest0bcbf337;35singles336pass,9packages2403pass/1knownskip,10shells425selftests+156queue nodepass;75assertionkills+2controlledtimeoutkills=77;88hashrestore,cwd sweep[],slotreturned;in-review rev3114,expected no-token failure3115(exit1);Sage/Dewey handoff,no live action.
2026-10-22 05:03:18 UTC | Rocko (Codex gpt-6.1-sol,d99326cc) | Vikunja502 processing test/runner hardening | brief+isolatedrocko-v502;expected wordingred→green,Node27/27,Python4/4,5/5assertionkills(includingSR08andKS54nohang),0skips/timeouts;sweep[],candidate5hashrestored,slotreturned05:01:29Z;candidate968d6ee3,runnerc5bdc764;packetready,no commit/push/liveaction.
2026-10-22 05:07:34 UTC | Rocko (d99326cc) | Vikunja502 committed/review handoff sage-2482 | newbranchrocko/vikunja502-ce6a-20261022,source8e3c6a79b+packet9bf4683c6 on ce6a96ad6;5paths no base drift,range-diff=,patch-id37135ebe unchanged;manifest968d6ee3,packet93889519 verifies39/39;focused runs carry;Sage publish/Dewey review handoff sent,no push/liveaction.
2026-10-22 05:10:00 UTC | Sage (1ef1e4f8) | serial landing 205 then 268 | 205: 3 commits, 4 paths, digest 858463b1, every scripts/test-*.sh green on ce6a96ad6, Duckworth N1-N4 carried (N1/N3 to 205b or R3, N2 to the 193b2 brief, N4 #1782 before any user thread goes live). 268 r4: c27207f6e on 205, 9 paths, digest caa0fa4e, patch-id 2942acc8 equal to r3. Overlap checks clean before both pushes. No live action; LIVE stays 86f95bb27.
2026-10-22 05:58:59 UTC | Rocko | row 279 #1784: before, deadline overshoot skipped final observation and returned unknown; after, one-line for (;;) retains final mapping and unchanged unreachable fallback. Regression red as specified; whole stop-run 13/13 and processing-control 62/62; M1 assertion kill, no skips, restored and swept. Source 1016b8584, packet cad927137; manifest 312ed511d8f1cff826ee2fd547de8368923130c7bfe06236d8e29d8655b80aaa. Pending Sage publication and Dewey review; no live action.
2026-10-22 06:15:54 UTC | Sage (1ef1e4f8) | row 279 #1784 landed (mos-1269) | Before: stopRun returned unknown for a live run when a sleep overshot the deadline. After: LANDED ceadad993 as a carry of cad927137 onto 343b6dd76 (range-diff 1:= 2:=, patch-ids 6d8ae7f4/e484c297 equal, Dewey carry c30410). Sage gate on cad927137: business 209/0/0, cli 794/0/0, discord processing + processing-stop 9/0/0. Correction: the first discord run wrote to a wrong out path and ran nothing; the rerun is the result. Overlap sweep clean (13, 257). Note rev 3144, done rev 3145. No live action; LIVE stays 86f95bb27.
2026-10-22 06:37:43 UTC | Sage (1ef1e4f8) | row 194 b16 third red (mos-1269/mos-1270) | Gate on ceadad993 + 9cdc47d04: business 228/0, cli 826/0 (T9a passes), control-board 124/0, bus 705/1 at grant-executor.test.mjs G13 (timed out 10044 ms); conversation, webui and scripts/test-*.sh never ran. runb8 green 436/0/0, 17/17 mutants. Correction to sage-2524 (mos-1270): the stuck wait is the first until at :733, the holding file after decision.resolve, so the executor never started the install and hosts.revoke at :734 never ran; it is not a revoke-path hang. Ruling: a diagnosis run, 30 base + 30 candidate alternating under cli load, no gate retry.
2026-10-22 07:51:04 UTC | Rocko | row 280 #1785: before, any TCP connect could accept a port our sshd failed to bind; after, attempt-local exact log proof plus liveness and connect, non-ephemeral picker, bounded scratch remote sleep cleanup. Both occupied regressions red on old acceptance; CRLF build failure captured and fixed under sage-2535. Committed source b765f5cb8, packet d6c924764, manifest27806c0579c76d0999d2e6be4180c3867570df0268af9d7e0d7b971af799e6f5. Repeats07:29:03Z–07:48:38Z grant1230/1230,host780/780,CLI1588/1588; final M1/M2 four assertion kills,0skips/timeouts,sweepclear. Sage publishes/gates; Duckworth reviews.
2026-10-22 08:00:02 UTC | Sage (1ef1e4f8) | row 280 #1785 landed | before: the bus tests' scratch sshd helper returned a port on a connect alone, and 194 b16's gate hung at G13 (base hung too, honker-0127). After: b0fd28b6f on refactor, a ff from da5d3651d (b765f5cb8 + Rocko slim packet; full evidence d6c924764 on rocko/row280-da5d-20261022). Duckworth approve rev 3153 (manifest 27806c05). Sage gate bus 656/0/0, ge 41/0/0, hr 26/0/0 (c30431). Rocko repeat 2010/2010 under cli 1588/1588, no timeout; M1/M2 killed 4/4. Two build-time slips recorded in Rocko's packet: a runner root path (no test ran) and the CRLF sshd log line. Overlap 13/257 clean. Note rev 3154, done 3155, #1785 closed c30432, P19 511 comment 623. 194 b17 rebases on b0fd28b6f (sage-2542).
2026-10-22 08:38:11 UTC | Sage (1ef1e4f8) | row 194 #1692 landed | before: 194 b16 9cdc47d04 went red three times (stopRun deadline, then the bus test sshd port race), fixed by rows 279 and 280. After: fd6dd327c on refactor, a ff on e122aad8e. b18 is b17 3f451772d rebased after my doc and queue push blocked a ff (16 =, series patch-id 64303253f8e6, packages equal b17). Webby approve rev 3160 on manifest 29f131ab. Honker gate on fd6dd327c: runb8 503/0/0, mutants 17/17; 18 packages 3668/0, ten scripts rc=0, Docker up, env skips named. The secret scan hit three fake_*_token fixtures in bus tests (false positive). Note 3161, done 3162; #1692 closed c30435; P19 414 comment 625. LIVE still 86f95bb27.
2026-10-22 08:42:04 UTC | Honker (Claude Opus 5.5, ecd17786) | row 194 #1692 agent lifecycle build | before: no Console or CLI lifecycle for agents (create, launch, terminate, regenerate, delete) and no per-agent hire/fire veto. After: 16 commits landed as fd6dd327c (b18, a rebase of b17 3f451772d on e122aad8e: 16 =, series patch-id 64303253f8e6, packages equal b17). Manifest 53 paths, digest 29f131ab. Final run on fd6dd327c: runb8 39 files whole 503/0/0, mutants 17/17 killed, restores matched; gate.sh merge onto e122aad8e, 18 packages 3668/0, ten scripts rc=0, Docker up, four env skips named (webui esbuild pin, queue render outside canonical root, test-task live provider x2); sweep clean. Corrections: b16 went red at G13; my diagnosis (60 runs, base hang on port 38927 sshd bind EADDRINUSE) placed it outside 194, fixed by row 280; the g13diag load kill missed its process group and overran about 8 minutes; one runb8 launch failed rc=126 on a lost exec bit before any test ran; the b17 runb8 was stopped unscored when refactor moved. In-review revs 3156/3157, Webby approve rev 3160.
2026-10-22 09:43:34 UTC | Sage (Claude Opus 5.5, 1ef1e4f8) | row 236 #1742 Gitea grant landing, and row 281 filing | 236 landed bd5f11ded at 09:37:31Z, a fast-forward on be2b008cc: 08840f3c1 rebased past 194 (commit 1 unions only, 2-7 =), e40b74beb for two stale out-of-manifest pins, bd5f11ded for a gitea-not-configured raise test. Dewey approve rev 3168 on manifest 0b00269b (34 paths). Megavolt gate under my slot: 2c bus 131, cli 224, route 28, docker 1; whole bus 765, business 228, cli 832, ten scripts rc=0; mutants 40/40; skips named, env only. Overlap with 13 and 257 clean. Note 3169, done 3170; #1742 closed c30451; P19 436 comment 639. Correction: the first whole run on ce74477e1 went red 762/764 on the two stale pins; that run is void. Follow-up per mos-1271: row 281 (#1786), a fire or delete revokes host and Gitea grants, Megavolt owns, Dewey reviews; brief docs/plans/2026-10-22_fire-revokes-grants.md; DEFERRED entry points at it.
2026-10-22 10:30:51 UTC | Sage (Claude Opus 5.5, 1ef1e4f8) | row 274 #1779 FED R3 broker user principal landing | 274 landed 4c485c63b at 10:28:26Z, a fast-forward on 47a35bf43: six Morgana commits d20c92bf6..4c485c63b. r5 f58cfc361 moved covers, LEVELS and the all marker into business/src/vocabulary.mjs so the broker keeps its sandbox import closure (M16/M16b/M16c). r6 4c485c63b pins USER_VERBS as the ruled seven and widens the R3 off-list set. Dewey approve rev 3178 on manifest 00047b52 (13 paths), comment 30487. Morgana gate under my slot, 10:09-10:22Z: 23 touched files 0 fail, bus 787, harness 151, business 228, cli 832, seat 167, ten scripts rc=0, mutants 22/22; skips named, env only (test-queue 1, test-task 2). Overlap with 13 and 257 clean. Note 3179, done 3180; #1779 closed c30491; P19 414 comment 646. Corrections: the r5 gate on f58cfc361 went red (M3x/M6x survived the R3 off-list set), void; my gate comment 30490 said 24 touched files, the count is 23; the kit comment guessed human-required for the M3x wall, the run code is not-holder.
2026-10-22 10:57:34 UTC | Sage (Claude Opus 5.5, 1ef1e4f8) | row 256 #1761 the human deletes a creative instance, landing | before: row 194's deleteRefusal refused every END_PROTECTED definition for every actor, so nobody could delete a creative instance; the human could only delist one with launch: false. After: 256 landed f12441d4f, a fast-forward on 0165be266 (the 274 landing plus its docs and queue commits): four Honker commits b5f1e09d6..f12441d4f, patch-id b28e63746f8c. One protectedRefusal predicate serves delete and the listing's per-viewer endProtected; any non-human actor gets organization-creative-human-only, fire unchanged. Rebased twice (past 236, then past 274), each range-diff 4/4 =, carries checked by Webby (webby-0126, webby-0128). Webby APPROVE on manifest-r3 01eb75aa (10 paths), comment 30519, posted by Sage as jarvis because Webby has no token; review request c30518 (Sage, revs 3183/3184) after Honker's request failed (no token, revs 3181/3182). Gate by Honker under Sage's slot 10:33Z-10:52Z on merge tree ced6bf5f8: touched files 31/0/0, 18 packages 3757/0 (bus 788, business 231, cli 832, webui 335), ten scripts/test-*.sh rc=0, mutants M1, M2, M3, M4a, M4b killed with blob-checked restores. Skips, named and environment-only: webui editor rebuild byte check (esbuild 0.28.1 installed, pin 0.28.2), test-queue non-canonical root, test-task live provider x2. Overlap with in-review rows 13 and 257 clean. Order change sage-2594: 256 landed before 277 because 277's gate had not run. LIVE is still 86f95bb27. Queue note rev 3186, done rev 3187; #1761 closed c30520; P19 416 comment 649.
2026-10-22 11:19:28 UTC | Sage (Claude Opus 5.5, 1ef1e4f8) | row 277 #1782 the owner sees a thread agent's claims, landing | before: a thread run's role.claim wrote thread_claims only, and the agents verb read role_claims only, so the owner had no way to see a thread agent's claim (PRD :1083-1084). After: 277 landed 62f53b1e0, a fast-forward on 46dedf925 (the 256 landing plus its docs and queue commits): seven Morgana commits 1d5d00939..62f53b1e0, range patch-id 7f0533520bd2. A bus verb thread.claims serves human and reader sessions; mosaic agents adds thread lines without --tester or --json, --json keeps the agents array, the tester path makes one call, a refused thread.claims prints the role lines and the refusal code, and an error with no bus code still throws. Rebased onto 0165be266, then onto 46dedf925 after 256 landed first (sage-2594); both range-diffs all =, manifest e281aa2c unchanged (duckworth-0126). Duckworth APPROVE comment 30539, recorded rev 3192, posted by Sage as jarvis; review request c30538 (revs 3190/3191) after Morgana's request failed (no token, revs 3188/3189). Gate by Morgana under Sage's slot 11:01:23Z-11:13:56Z: 7 touched files 0 fail (thread-claims 5, message-filter 6, user-principal 22, format 4, tester 11, other-tree 4, host 43), bus 793, cli 836, harness 151, business 231, seat 167, ten scripts/test-*.sh rc=0, M1-M9 killed on committed bytes. Skips named, environment only: test-queue non-canonical root, test-task live provider x2. Overlap with in-review 13 and 257 clean. Duckworth N1 (M8 dies on a rethrown error) to DEFERRED; 0123 N3 per-session claims binds 264a r7. Note rev 3193, done rev 3194; #1782 closed c30540; P19 506 comment 652. Also landed as doc-only picks: Honker's 256 BUILD.md gate results (80620a3a0 as b83173305) and Megavolt's 236 BUILD.md runs (9c6e1a165 as 01ea1fb11). LIVE is still 86f95bb27.
2026-10-22T11:37:16Z | Gander row278 #1783 implementation prepared, verification held | Before: owner thread claims were visible through row277 but absent from the Console Agents view. After: prepared a separate four-field table, a Console-owned read adapter, section-local refusal handling and an explicit tester refusal before busRead. Ten tests and six unique check definitions are prepared but unrun. Base moved from980cec88c to6af85df4b under sage-2625 on new gander/row278-b; no candidate path overlapped. No Node process, syntax check, test, browser, queue command, push helper or live action ran. Next: Sage CLEAR for the queue claim and gate; Webby reviews the verified manifest.
2026-10-22T12:09:45.285844+00:00 | Gander row278 run1 void, loader fake repaired | First new-file run stopped3/1/0 because the fake omitted BusReadError imported by base chat.mjs. Sage-2638 places the first-own-test red and permits the assertion-preserving export; test-only commit964b6b184. Runtime bytes unchanged. All run1 results void, no timeout or run leftovers. Run2 must restart every step after busy CLEAR; a second red goes to Sage then Mos before any change. No product acceptance or push claimed.
### 2026-10-22 | Gander | row278 gate run3
Fresh gate on3e4c77ac6 under sage-2648: bus793/0, WebUI345/0/1 (esbuild version skip), all ten shell files425/0, touched files15/0, M1-M6 killed6/6. No timeout; sweep0 run-created leftovers. Runs1/2 void. Seven-path manifest8fa859a0 goes to Webby for final review. No landing or live change.
2026-10-22 11:29:09 UTC | Rocko | V502 carry/rerun on980cec88c: source407c8d7be and packet04a86cf33 match approved8e3c6a79b/9bf4683c6 patch-ids, no conflicts. Dewey0834 carry conditioned on rerun, satisfied under sage2616: stop-run13,processingHTTP6,bustasks9 allgreen (Node28/28),Python4/4,0skips/timeouts. Manifest5758d699,source5/5restored,cwdsweep[]. Doc rerun packet6af85df4b explicitly pushed to rocko/vikunja502-980c-20261022; no live action.
2026-10-22 11:30:17 UTC | Sage | Vikunja 502 (row 191 follow-up, no queue row) LANDED 6af85df4b, a fast-forward from 980cec88c. Before: the processing failure diagnostics and cleanup in stop-run, processing HTTP and bus tasks tests were Dewey-approved on the pre-194 base only (8e3c6a79b/9bf4683c6). After: Rocko's picks 407c8d7be/04a86cf33 carry the same patch-ids (37135ebe/0dbcda54), plus a doc-only rerun record 6af85df4b. The rerun on the new base was green: stop-run 13/13, processing HTTP 6/6, bus tasks 9/9, Python 4/4, 0 skips. Dewey carried the approve (dewey-0836). mosaic-task.mjs is unchanged, so N7 (runs suite) didn't trigger. Overlap with in-review rows 13 and 257 was clean. LIVE is still 86f95bb27.
2026-10-22 13:10 UTC | Sage | Rows 278 and 281 LANDED. Before: refactor at 6af85df4b (V502). Row 278 (#1783, Gander, Webby): the Console Agents view shows thread claims in their own section. It landed as 385a7194c at 12:39Z, ff, 9 commits, manifest 8fa859a0. Run 3 was green: bus 793, webui 345/0/1, ten shells 425/0 under the 3x limits (mos-1275), M1-M6 killed. Runs 1 and 2 were void, on fixture fixes 964b6b184 (placed by Sage) and 9696d1fcb (ruled by Mos, mos-1275). Webby approved (c30588, rev 3200). Done rev 3202, #1783 closed c30589. Row 281 (#1786, Megavolt, Dewey): a fire or a delete revokes the instance's host and Gitea grants. It landed as e479521d3 at 13:06Z, ff, 17 commits, manifest b73d4c81. Slot on 7979fb41e: bus 819, business 231, cli 837, dewey-bus 76 with the Docker gitea-grant test, shells green, M1-M22 killed. The M1 hang was fixed at its cause in b4a (mos-1273). Dewey approved (c30614, rev 3207). Done rev 3209, #1786 closed c30621. Skips on both: test-task's row 244 live-provider pair and test-queue's canonical-root check, plus webui's esbuild rebuild test on 278. After: refactor at e479521d3. DEFERRED moves the grant gap to Done and opens Dewey's N1/N2 text gaps. LIVE is still 86f95bb27.
2026-10-22 14:18:23 UTC | Sage | Row 264a LANDED (#1769, Gizmoduck, Duckworth): sessions per thread, schema 3k-3l. Before: refactor at e479521d3 (row 281). It landed as 84f53540d, ff, 21 commits, manifest 257408e9 (Duckworth approve rev 3214, comment 30640). Gate r13 on 2cc34aef8: 20 touched files, bus 827, cli 837, webui 345/1 named skip, ten shells under 3x limits, mutants M1-M4 killed on assertions. Corrections on the way: the kit stopped on first red, so four reds surfaced one at a time. r10 later3l missed a trigger (mos-1276). T2 had failed since r2 because refusals log action.refused (mos-1277, my sage-2257 wording). threads.test:341 kept the old trigger text (mos-1278). M2 was caught by the store trigger before any assertion, so it now drops the trigger too (mos-1279, four files with the SCHEMA_SHA256 pin). Deferred: actor_run pin binds row 269, esbuild skip to a later gate, session-scoped user reply binds row 272. No live change; LIVE is still 86f95bb27.
+1
View File
@@ -22,6 +22,7 @@ RUN npm ci --ignore-scripts
# runtime adapters.
COPY contracts /opt/mosaic/contracts
COPY src /opt/mosaic/src
COPY packages/processing-control/src/state.mjs packages/processing-control/src/entrypoint.mjs /opt/mosaic/processing-control/
COPY adapters /opt/mosaic/adapters
RUN chmod 0555 /opt/mosaic/contracts /opt/mosaic/contracts/* \
&& chmod 0555 /opt/mosaic/src /opt/mosaic/src/*.sh \
+24 -4
View File
@@ -75,7 +75,8 @@ session's workspace and its own process group. Same contract, plus:
| `MOSAIC_POLICY_FILE`, `MOSAIC_TOOLS_FILE` | The bundle's gate policy and typed tools. |
| `MOSAIC_TOOL_SOCKET` | The runner's tool socket, which the typed tools call. |
| `MOSAIC_TURN_MARKER` | `pi`: the extension writes it at `agent_end`; a pi turn that exits 0 without it failed. |
| `MOSAIC_EXTENSIONS` | `pi` only: extension files loaded with `-e`; a missing one exits 2. |
| `MOSAIC_EXTENSIONS` | `pi` only: extension files loaded with `-e`; a missing one exits 2. The pi module names two: the gate and typed tools extension, then the unslop check's `tools/unslop-hook/extension.ts` (row 66). |
| `MOSAIC_UNSLOP_LOG` | The unslop check's JSONL log, `<run>/unslop.jsonl`, which the runner sets for both adapters and reads after each turn (row 66). |
| `MOSAIC_CLAUDE_SETTINGS`, `MOSAIC_CLAUDE_MCP_CONFIG` | `claude` only: the bundle's gate hook and MCP server; required. |
| `MOSAIC_THINKING` | The route's thinking level (row 65), which the harness module's `levels()` already checked. `pi` passes `--thinking` (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) and omits it when unset, as for `run-task.sh` workers. `claude` passes `--effort` (`low`, `medium`, `high`, `xhigh`, `max`) and requires it; unset exits 2. |
| `MOSAIC_CLAUDE_BIN` | `claude` only: absolute path of the CLI to run, from the host's environment (the bus unit pins it). Unset or empty runs `claude` from `PATH`; a relative path or a non-executable file exits 2. |
@@ -86,7 +87,8 @@ The layers each adapter relies on, and what they don't cover, are in
### A role's skills (row 64)
A managed session's skills reach both adapters as text in the bundle's
`prompt.md`, which they pass with `--system-prompt`. Neither adapter loads a
`prompt.md`, which they pass as a file: `pi` with `--system-prompt <path>`
and `claude` with `--system-prompt-file <path>` (row 213). Neither adapter loads a
skill of its own: `pi` keeps `--no-skills`, since role sessions never get
`MOSAIC_SKILLS`, and `claude` keeps `--disable-slash-commands` and
`--restricted`. Sage chose this on 2026-10-19 from a probe, recorded in
@@ -104,5 +106,23 @@ skill of its own: `pi` keeps `--no-skills`, since role sessions never get
The cost is prompt size: a role's skill text is in every turn, where the
other routes load a skill when it's used. The bundle caps a role's skills at
64 KiB together, since `claude` passes `prompt.md` as one argument and Linux
caps one argument at 128 KiB.
64 KiB together. The cap dates from when `claude` passed `prompt.md` as one
argument, which Linux caps at 128 KiB; row 213 passes the file instead, so no
local user reads the prompt in `/proc/<pid>/cmdline`. Pi 0.85.1 uses the path
string itself as the prompt when the file is missing or can't be read, so the
pi adapter exits 2 unless the path is a readable regular file.
### The unslop check (row 66)
Both adapters run the mechanical writing check from `tools/unslop-hook`,
driven by one `lists.json`. `pi` loads it as its second `-e` extension.
`claude` runs `claude-hook.js` from the bundle's `settings.json`: the Stop
hook checks the turn's replies, and the UserPromptSubmit hook adds the
correction notice as context on the next turn when the last reply had
tells. Each hook command ends `; exit 0`, so neither blocks. Both log to
`MOSAIC_UNSLOP_LOG`, and the runner adds a note for the operator to the
next RESULT it sends (`packages/harness/README.md`, the runner). The
harness modules mount the three files read-only at their own paths, and
the manifest records their digests. `MOSAIC_UNSLOP_HOOK` and `UNSLOP_LISTS`
aren't in the session environment's allowlist, so a managed session can't
switch the check off or swap its lists.
+10 -3
View File
@@ -27,6 +27,11 @@ need MOSAIC_CLAUDE_MCP_CONFIG
for f in "$MOSAIC_SYSTEM_PROMPT_FILE" "$MOSAIC_CLAUDE_SETTINGS" "$MOSAIC_CLAUDE_MCP_CONFIG"; do
[ -r "$f" ] || { echo "claude adapter: not readable: $f" >&2; exit 2; }
done
PROMPT_FILE=$MOSAIC_SYSTEM_PROMPT_FILE
case "$PROMPT_FILE" in
/*) ;;
*) PROMPT_FILE="$(pwd)/$PROMPT_FILE" ;;
esac
[ "${MOSAIC_INTERACTIVE:-}" != "1" ] || { echo "claude adapter: interactive mode isn't supported" >&2; exit 2; }
CLAUDE=claude
if [ -n "${MOSAIC_CLAUDE_BIN:-}" ]; then
@@ -56,7 +61,10 @@ fi
# Flags:
# -p one-shot: print the answer and exit
# --output-format text stdout is the answer only
# --system-prompt the generated prompt replaces the default
# --system-prompt-file the generated prompt replaces the default, given
# as a file so no local user reads it in
# /proc/<pid>/cmdline (row 213); absolute, since
# the cd above changed the working directory
# --effort the instance's thinking var (row 65; 2.1.302 takes
# low, medium, high, xhigh, max)
# --restricted no user/project/local settings files; --settings
@@ -76,10 +84,9 @@ fi
# text in the system prompt (row 64)
ALLOWED=mcp__mosaic
[ -z "${MOSAIC_TOOLS:-}" ] || ALLOWED="$MOSAIC_TOOLS,mcp__mosaic"
PROMPT_CONTENT="$(cat "$MOSAIC_SYSTEM_PROMPT_FILE")"
"$CLAUDE" -p "$MOSAIC_REQUEST" \
--output-format text \
--system-prompt "$PROMPT_CONTENT" \
--system-prompt-file "$PROMPT_FILE" \
--model "$MOSAIC_MODEL" \
--effort "$MOSAIC_THINKING" \
--restricted \
+14 -4
View File
@@ -8,7 +8,17 @@
set -eu
[ -n "${MOSAIC_SYSTEM_PROMPT_FILE:-}" ] || { echo "pi adapter: MOSAIC_SYSTEM_PROMPT_FILE is required" >&2; exit 2; }
[ -r "$MOSAIC_SYSTEM_PROMPT_FILE" ] || { echo "pi adapter: system prompt not readable: $MOSAIC_SYSTEM_PROMPT_FILE" >&2; exit 2; }
# Row 213 (C2-08): pi gets the prompt as a path, so no local user reads it in /proc/<pid>/cmdline.
# Pi 0.85.1 reads --system-prompt as a file only when the path exists and reads, and otherwise
# uses the path string itself as the prompt, without a warning for a missing file
# (dist/core/resource-loader.js resolvePromptInput). So the path must be a regular readable
# file here, and is made absolute before the cd below, since pi resolves it from its own cwd.
PROMPT_FILE=$MOSAIC_SYSTEM_PROMPT_FILE
case "$PROMPT_FILE" in
/*) ;;
*) PROMPT_FILE="$(pwd)/$PROMPT_FILE" ;;
esac
[ -f "$PROMPT_FILE" ] && [ -r "$PROMPT_FILE" ] || { echo "pi adapter: system prompt not readable: $MOSAIC_SYSTEM_PROMPT_FILE" >&2; exit 2; }
# MOSAIC_AGENT_NAME is optional in headless mode (identity section is then
# omitted); interactive launches always set it via scripts/agent.sh.
@@ -94,7 +104,8 @@ fi
# All flags documented in the pi package README (CLI Reference):
# -p/--print one-shot mode: print the response and exit (omitted in
# interactive TUI mode)
# --system-prompt replace the default prompt with the generated one
# --system-prompt replace the default prompt with the generated one, given
# as the file's absolute path (checked above), never its text
# --no-* no ambient context/skills/extensions/templates/themes
# EXT_FLAGS the explicitly provided extensions only (-e)
# SESSION_FLAGS ephemeral | persistent | forked (per env)
@@ -103,7 +114,6 @@ fi
# --offline no startup network operations (update checks/telemetry)
# --no-approve ignore project-local .pi/ files (settings, SYSTEM.md)
# whatever trust is saved for the workspace
PROMPT_CONTENT="$(cat "$MOSAIC_SYSTEM_PROMPT_FILE")"
set -- \
--offline \
--no-approve \
@@ -118,7 +128,7 @@ set -- \
--provider "$PI_PROVIDER" \
--model "$PI_MODEL" \
$THINKING_FLAG \
--system-prompt "$PROMPT_CONTENT"
--system-prompt "$PROMPT_FILE"
# One-shot mode appends -p and the request (both safely quoted);
# interactive mode appends nothing - clean TUI.
[ "$INTERACTIVE" = "1" ] || set -- "$@" -p "$MOSAIC_REQUEST"
+161
View File
@@ -0,0 +1,161 @@
# Row 195 build: `scripts/case1-accept.sh`
Row 195 (#1693), the Case 1 install on 10.1.1.53. Design r7 at 5425ea2f3, approved by Duckworth
(duckworth-0087, `agents/duckworth/work/row195/REVIEW-r7.md` at 58d930f89; Gitea 29962). Sage's go to build
is sage-1817.
## What this commit holds
- `scripts/case1-accept.sh` (new, 100755): section 5's acceptance, F1-F11 and P1-P11.
- `packages/cli/tests/case1-accept.test.mjs` (new): section 5's cases.
- `docs/TOOLS.md`: the `case1-accept.sh` entry after the hostcheck entry.
- This file.
- `DESIGN.md`, doc-only fixes Sage named in sage-1817, with no new design round:
- Duckworth's N1. Section 1's human-id row cited `broker.mjs:245`; the check is `broker.mjs:321`.
- Row 226's state at :21 and :326. It said "unclaimed"; 226 is assigned to Gosalyn, briefed and not
started (sage-1814).
- :340 said I'd send the section 6 items to Gosalyn once 226 was claimed. I sent them on 2026-10-21
and Gosalyn acknowledged (gosalyn-0085), so the line now says that.
Nothing else changes. No `case2-*.sh`, `stack-upgrade.sh`, `stack-release.sh`, `case1-hostcheck.sh` or run
sheet edit, and nothing touches .53 (sage-1809).
## Deviations from section 5, and choices it left open
1. P4's mark is the single token `accepted Q182+Q183`. Section 5 lists `accepted Q182` and `accepted
Q183` as marks and gives P4 both. One line can carry one mark, and P4 is the only Q182 path, so the
count list has `accepted Q182+Q183` in place of `accepted Q182`.
2. The test seam replaces `getent`. Under `--root`, the script reads `DIR/etc/passwd` and `DIR/etc/group`
with awk. Without it, the same helper calls `getent`. The groups of a user are its primary gid, then
each group whose member list names it, which is what `id -G` prints. So there is no fake `id`, and
the script never calls `id` for another user.
3. P10 reads the port floor from `/proc/sys/net/ipv4/ip_unprivileged_port_start` rather than calling
`sysctl`, so the seam covers it the way hostcheck's item 7 is covered. There is no fake `sysctl`.
4. There is no fake `bwrap`, `claude`, `node` or `hostcheck.sh` on PATH. The script runs each by the
absolute path the args file or the install names, so the test puts stubs at those paths under
`--root`, and the fake `sudo` runs the stack's user's commands from the tree.
5. The args file must say `--profile factory` and name `--business`. Both are new refusals beyond
`stack-upgrade.sh`'s rules. A library file, or one for another business, would make F4 and F7
check the wrong thing. After `--`, `--port` and `--tester-port` must be numeric. The args file is the
only source of the ports.
6. F8, F9 and F11 read file metadata as root: `stat`, `-L` and `find -maxdepth 1 -name '*.json'`. None
opens the credential. F9 parses `managed-settings.json` with the pinned node, run by root: that node
and that file are both root's own, installed by ops-01.
7. F7 reads `launch.by` from `$HOME/.config/mosaic-dev/businesses/<id>.json` as the stack's user. That
path is `businessFilePath(id)` under the default config, which is what the unit uses. It doesn't load
the copy's `business.mjs` as `stack-release.sh`'s `plugins launchby` does. The user runs the whole
check and prints one line, and root accepts only `ok <instance> run <run>` (sage-1653: root doesn't
parse the user's output beyond a fixed pattern).
8. F5 names a process claude when its argv0's basename or its `comm` starts with `claude`. The window
confirms this against a real role session. If the bwrap'd claude shows another name, F5 fails closed
and the fix is this match, not the label check.
9. F3 and F5 run together. `talk` goes out in the background under `timeout 330`, and the `/proc` scan
repeats every half second until it finds a labelled pair or `talk` exits. F3's line prints first, then
F4, then F5, so the output keeps id order. F3 passes on exit 0 with the `sent` line and a reply line,
both counted on stdout only (`cli.mjs:395` and the `formatMessage` write); talk's error goes to stderr.
12. `--claude` must match `^/[A-Za-z0-9/._+@-]+$`. The `@` is for `node_modules/@anthropic-ai/...`;
`stack-upgrade.sh` doesn't check `--claude` at all.
10. F1 requires all four uids in `/proc/<MainPID>/status` (real, effective, saved, filesystem) to be the
user's.
11. Evidence text the stack's user controls (talk's last line, the precheck's last line, F6's and F10's
`--version`) is cut to printable ASCII, one line, 200 bytes.
## Tests
`packages/cli/tests/case1-accept.test.mjs`, 22 tests. Every case builds a scratch host with every F check
passing and every P check closed or accepted, then changes one thing:
- all pass: exit 0, ids in order, each P mark, the count lines match the check lines, and the stand-in
credential's value appears nowhere;
- each F check failing alone exits 1 with only its line failing;
- F3 on exit 0 with only the `sent` line, and its evidence taking talk's stderr;
- F1 on a failed unit and on `User=root`; F2 on healthz failing and on another pid holding the port;
- F5 on `unpriv_bwrap (enforce)`, `bwrap//&unpriv_bwrap (complain)`, a trailing space on either label,
no bwrap of the user's, and passing on `comm` alone;
- F6 on a stub that prints nothing and on a path outside `claude-<pin>`;
- F7 on two live PM launches, a live one for another business, and no `launch.by`;
- F8 on 0640, on another owner and on a symlink, never printing the credential;
- F9 on a group-writable mode, another owner and a number for the flag;
- F11 on one `*.json` under `discord/`, and passing on an empty directory;
- each P check's unnamed mark, with the line count each fault makes: P6 one line per member, P9 one per
missing item; P2, P5, P10 and P11 in more than one way;
- every P check unnamed at once still exits 0;
- nine bad args files refuse with exit 2 before any command runs, each with its own refusal text;
- usage errors, and a user's run without `--root`, exit 2;
- every in-instance call goes through `sudo -u mosaic -H env PATH=<node dir>:/usr/local/bin:/usr/bin:/bin`,
read from the fake `sudo`'s argv, and root's other `sudo` calls are exactly `-l -U mosaic`,
`-l -U localadmin` and the jarvis bwrap probe;
- the host check records `--check` and never `--enforce`.
## Mutants
Section 5's twelve, each one exact replacement in `scripts/case1-accept.sh`, run by
`/mnt/storage/scratch/darkwing-195-out/mutants.py` in Sage's slot (sage-1865). All twelve were killed.
After each one the script's bytes were restored, and the final sha256 matched (`d434f15ff638...`). The
killers below are the tests that failed in each mutant's saved log.
| # | Mutant | Killed by |
|---|---|---|
| 1 | F1 passes on a MainPID owned by root | each F alone |
| 2 | F2 accepts a listener on 0.0.0.0 | each F alone |
| 3 | F3 passes without a reply | each F alone; F3 exit 0 with no reply line |
| 4 | F5 matches a substring | F5 labels (the trailing space) |
| 5 | F6 skips the `--version` check | each F alone; F6 stub and path |
| 6 | F8 skips the owner check | F8 0640, owner and symlink |
| 7 | F11 ignores `discord/` | each F alone; F11 `*.json` |
| 8 | P1 closes on any output | P unnamed; every P unnamed |
| 9 | P5 maps to `closed` with jarvis in docker | P unnamed; every P unnamed; P2 and P5 names docker |
| 10 | P9 drops the jarvis item | P unnamed; P9 per item |
| 11 | P11 accepts any `Before=` | P unnamed; every P unnamed |
| 12 | a P check's `unnamed` sets the exit to 1 | P unnamed; every P unnamed; P10 and P11; P2 and P5; P9 per item |
Mutant 1 survived the F1 variants test (a failed unit, `User=root`), because those faults fail F1 on the
unit's state and `User=`, not on the uid line. Each F alone covers the uid line.
## Pre-slot read review
Since every test run is slot work, a read-only subagent traced each case through the script before the
first slot run, executing nothing. It found four defects, all fixed in this commit:
- The `--claude` regex had no `@`, so every run refused the args file, the real .53 one included.
- The fake `stat` logged the args-file call, so the bad-args test's "no command ran" check would fail.
- The P5 and P6 faults each rewrote `etc/group` from the constant, so applying both lost P5's change.
- F3 counted stderr into its line count, so a mutant dropping the exit check survived. F3 now counts
stdout only, and a `sent`-only case covers the line count.
## Run environment
The build commit ddf7dce6c sits on base 4ced5e63d (origin/refactor when it was pushed). It was first built
on c515273db as 4a51d392c. Row 238 then changed `docs/TOOLS.md`, so I cherry-picked the three commits onto
4ced5e63d as `darkwing/row195-b`. `git range-diff` shows all three identical. node v26.8.1 on dragon-lin,
every run behind my busy check and Sage's, chained with `&&`.
- Step 1, sage-1829 (07:41:54Z to 07:42:05Z), TMPDIR `/tmp/dw195`:
`node --test packages/cli/tests/case1-accept.test.mjs`, 22 pass, 0 fail, 11.0 s.
- Step 2, sage-1865 (08:34:27Z to 08:36:21Z), TMPDIR `/mnt/storage/scratch/tmp/r195`: the twelve mutants
above, all killed.
- Step 3, the gate (08:36:21Z to 08:47:06Z), same TMPDIR, `COMPOSE_PROJECT_NAME=darkwing-r195`:
| Suite | Result |
|---|---|
| packages/cli (`node --test tests/*.test.mjs`) | 662 pass, 0 fail, 0 skipped |
| test-auth.sh | 15 passed, 0 failed |
| test-conductor.sh | 17 passed, 0 failed |
| test-config.sh | 31 passed, 0 failed |
| test-discord.sh | 78 passed, 0 failed |
| test-extension-package.sh | 18 passed, 0 failed |
| test-foundation.sh | 44 passed, 0 failed |
| test-land-work.sh | 86 passed, 0 failed |
| test-queue.sh | 156 node pass, 0 fail; 28 passed, 0 failed |
| test-release.sh | 14 passed, 0 failed |
| test-task.sh | 98 passed, 0 failed |
Summed: 818 node tests passed with 0 failed, and 429 selftests passed with 0 failed. The compose network
was removed afterwards, and the sweep found no process left in the worktree, the output directory or the
TMPDIR. This file's results are a doc-only commit on top of the build, so nothing that ran has changed.
## Correction to deviation 6 (follow-up, 2026-10-21)
Deviation 6 says the node F9 runs is root's own. At 37171f65b the script didn't check that. F9 ran
`--node` as root before F10's path check, so the header's "root itself only reads" was false
(Duckworth's N1, `agents/duckworth/work/row195/REVIEW-m1.md` at 6afcee2a5). A host installed as designed
was safe, because `case2-unit.sh` refused a non-root-owned `--node`. Row 245 carries the fix and its
tests: `agents/darkwing/work/queue-245/BUILD.md`.
+388
View File
@@ -0,0 +1,388 @@
# Row 195 design: the Case 1 install on 10.1.1.53 (r7)
Darkwing, 2026-10-21. Brief: `docs/plans/2026-10-20_hub-own-uid.md`, blob 45be7f09afc1, section "Brief: the
Case 1 install on 10.1.1.53 (row 195)". Gitea #1693. Reviewer Duckworth, gate owner Sage. Branch
`darkwing/row195-r7` on c515273db. r6 (b7239bb66 on `darkwing/row195`, approved duckworth-0055) is the base,
carried unchanged as 7398b7dd7. The r6 text is in that commit and in b7239bb66.
## Changes from r6
Q187 (mos-1108) made install and upgrade product commands, and mos-1118 split r6 into the installer rows
(`docs/plans/2026-10-20_installer-rows.md`). That brief says row 195 "shrinks to the factory profile's
values and the Case 1 acceptance". So r7 is mostly a cut. What r6 designed now ships elsewhere:
| r6 piece | Now | State |
|---|---|---|
| `stack-release.sh --units external`: `confirm`, `revert`, `gate`, `rollback --to`, external `adopt` and `status`; `stack-copy.sh check --units external` and bundle copies | row 232, I1 | landed |
| `case1-repin.sh` (A1-A5, A2f, R1-R4) | `scripts/stack-upgrade.sh`, row 233, I3 | landed |
| the host steps 2a, 2a', 2a'' and the window's root steps | `docs/guides/host-run-sheet.md` sections 1-10, row 233 | landed |
| `case1-hostcheck.sh`, `case1-pins.sh`, `mosaic-hostcheck.service` (the drift stop, r6 B2) | row 240, I4 | landed c515273db |
| the unit render, `--profile factory`, `--pm`, `--claude`, the factory serve flags, the precheck | row 230, C2-13a, I2 | landed |
| the install as `mosaic`: bootstrap, business file, copy | row 226, C2-13b, I2, `scripts/case2-install.sh` | assigned to Gosalyn, briefed, not started |
| `docs/guides/case1-install.md` | the host run sheet, plus section 6 of this file | |
Other changes:
- Claude moves under `/opt` (sage-1522, run sheet section 3). `--claude` is
`/opt/mosaic-stack/claude-<pin>/node_modules/@anthropic-ai/claude-code/bin/claude.exe`, root's, and root
installs and upgrades it. r6's `/srv/mosaic/.local/bin/claude` is gone. F6 reads the new path.
- The args file is `/etc/mosaic-stack/dev.args` (run sheet section 7), not `case1-unit.args`. It holds
`--copy` too, and `stack-upgrade.sh` rewrites only that line, after confirm passes.
- Both units are `WantedBy=multi-user.target` and start at boot (Q189, mos-1122). r6's "the Console has no
`[Install]`, root starts it by hand after a reboot" no longer holds.
- The business id is stated, with the DEFERRED 240 N1 reasoning (sage-1809, sage-1813). Section 7.
- The window can't run until row 226 lands. Sage added 226 to row 195's after list at rev 2718
(sage-1813). Section 6 lists what row 195 needs from 226's install.
- The acceptance runs as root through ops-01, not as `localadmin`. `aa-status`, `sudo -l -U`,
`systemd-run --uid` and the hostcheck all need root. It gains four functional checks for items the run
sheet marks "precheck line missing" (F8-F11) and one host line (P11). Section 5.
- The Discord row in section 2 changed. The precheck's "no Discord binding" line is C2-13b's and is
library-only, so for the factory it's F11 in the acceptance.
What row 195 still builds: `scripts/case1-accept.sh` and its test (section 5). The rest of this file is
inputs, the window order and the record the reviewer checks.
## 0. What I checked on the host
Read only, as `localadmin` over ssh, 2026-10-20 between 20:40Z and 21:51Z. Nothing in r7 touched .53
(sage-1809). The window's first step re-reads these, since they can drift in a day: unattended-upgrades
runs daily.
| Item | 10.1.1.53 on 2026-10-20 | Needed |
|---|---|---|
| OS | Ubuntu 24.04.5, kernel 6.8.0-124, x86_64, 12 cores, 94 GiB, 217 GiB free on `/` | fits |
| `mosaic` user, group, `/srv/mosaic` | absent | run sheet section 1 |
| node | `/usr/local/bin/node` v22.22.2, root-owned | 24 or later, under `/opt` (run sheet section 2) |
| claude | not on localadmin's PATH | under `/opt` (run sheet section 3) |
| bwrap | absent; apt candidate `bubblewrap 0.9.0-1ubuntu0.3` | run sheet section 4 |
| user namespaces | `kernel.apparmor_restrict_unprivileged_userns = 1`, apparmor 4.0.1, no bwrap profile loaded | run sheet section 4 |
| profiles that name bwrap | none (`grep -rlw bwrap /etc/apparmor.d` exits 1) | hostcheck item 3 |
| `fs.protected_hardlinks` | 1 | hostcheck item 6 |
| `net.ipv4.ip_unprivileged_port_start` | 1024 | run sheet section 5 |
| listeners below 1024 | 22 (sshd) and 53 (the resolver); 732 is free | the Console's port |
| ports 7330-7333 | free | 7333 is the tester port |
| `localadmin` | NOPASSWD sudo (#423 step 1, mos-1066, mos-1077) | ops-01's root path |
| `jarvis` | groups sudo, docker, lxd, adm | #423 step 4 removes them (P5) |
| unattended-upgrades | on, with the security pocket, which carries bubblewrap | the drift stop (row 240) |
| journald | `SplitMode=uid` | the PM check reads `launches list`, not the journal (row 232) |
## 1. The factory profile's values
Instance `dev`, row 190's default (mos-1118 choice 4). `~` is `mosaic`'s home.
| Input | Value | Who gives it |
|---|---|---|
| user | `mosaic`, primary group `mosaic` with no other member | fixed |
| home | `/srv/mosaic`, 0700 | fixed |
| config dir | `/srv/mosaic/.config/mosaic-dev` | row 190 |
| data root | `/srv/mosaic/.mosaic-dev`, marker `{"instanceVersion":1,"name":"dev"}` | row 190 |
| business | `mosaic-stack`, file `<configDir>/businesses/mosaic-stack.json` | fixed (section 7) |
| profile | `factory` for `case2-install.sh`, `case2-unit.sh` and `case2-precheck.sh` | fixed |
| roles | the factory set from `roles/`, with a chief that has a harness var | the go names the set (section 2) |
| human id | Jason's, not `tester` (`broker.mjs:321`) | the go |
| model credential | `<configDir>/secrets/claude-session.env`, `mosaic` 0600, one line `CLAUDE_CODE_OAUTH_TOKEN=...` | Jason places it (section 3) |
| token slot path | none | section 2 |
| node | `/opt/mosaic-stack/node-<v>/bin/node`, `<v>` 24 or later | the go names `<v>` and its sha256 |
| claude | `/opt/mosaic-stack/claude-<pin>/node_modules/@anthropic-ai/claude-code/bin/claude.exe`, `<pin>` 2.1.304 unless the go names a newer one | the go |
| PM | on (`--pm`) | fixed |
| Console | `--port 732` on 127.0.0.1, with the unit's `CAP_NET_BIND_SERVICE` | fixed |
| tester | `--tester-port 7333` on 127.0.0.1 (P10) | fixed |
| board | none | fixed |
| release | a git bundle of `refs/heads/refactor` and the 40-hex commit (run sheet section 6) | the go names both and the bundle's sha256 |
The args file. `/etc/mosaic-stack/dev.args`, `root:root` 0644, one argument per line (run sheet section 7):
```
--profile
factory
--user
mosaic
--home
/srv/mosaic
--business
mosaic-stack
--copy
<40-hex commit>
--node
/opt/mosaic-stack/node-<v>/bin/node
--claude
/opt/mosaic-stack/claude-<pin>/node_modules/@anthropic-ai/claude-code/bin/claude.exe
--pm
--
--port
732
--business
mosaic-stack
--tester-port
7333
```
`case2-unit.sh` takes exactly these before `--` (`scripts/case2-unit.sh:54`), and `stack-upgrade.sh`
refuses `args-unreadable` on anything else (`scripts/stack-upgrade.sh:126-148`). The factory profile
refuses the preview trio, `--send` and the proof pair (`case2-unit.sh:169`). .53 has no proxy, and Jason
reaches the Console with `ssh -L` (sage-1451 Q3). Changing a serve flag is a re-install with its own go,
not an upgrade.
Why the port is 732 (r6, mos-1101 item 5). Role sessions share the host's network namespace
(`packages/seat/src/sandbox.mjs:67`), so while the Console is down a session could bind a port above the
floor and answer in its place. Below 1024 only the Console unit can bind, through its capability. The
tester port can't go below 1024 (`packages/webui/src/cli.mjs:33`), so P10 records it.
PATH for `mosaic`'s steps. `sudo -u mosaic -H` resets PATH to sudo's `secure_path`, which finds
`/usr/local/bin/node`, v22. So every `mosaic` step runs as
`sudo -u mosaic -H env PATH=/opt/mosaic-stack/node-<v>/bin:/usr/local/bin:/usr/bin:/bin ...`, the list
`case2-unit.sh` renders as the units' PATH. `stack-upgrade.sh` builds it from the args file's `--node`.
## 2. Where Case 1 differs from Case 2
| Case 2 (library) | Case 1 (factory) | Reason |
|---|---|---|
| business file with the library mapping | `mosaic-stack` with no `library` key. The precheck refuses a library project under `factory` (`profile-library-business`, `case2-precheck.sh:127-128`) | the factory has no books repo |
| `bean`, `chet`, persona vars and files, specialists | the factory roles from `roles/`, with a chief that has a harness var | the go names the set. I haven't read Jason's live business file and won't. The acceptance needs only the chief (F3); a chief with no harness var answers `no-route`. The human adds roles later with `instances.set`, no new row |
| token slot `library-gitea` | none | the factory's per-agent git identity is row 199's credential store (Megavolt, #1697). Until it lands, git work stays on dragon-lin (Q182) |
| `bus.tester` off | on; the precheck refuses it off under `factory` (`case2-precheck.sh:135`) | the acceptance and the Q173 test system need the tester |
| persona modes and digests, `library.sync`, `library.status` | skipped | no persona files, no library (C2-13b brief, `factory` profile) |
| `ZAI_API_KEY` in `claude-session.env` | not checked; the file holds `CLAUDE_CODE_OAUTH_TOKEN` | no instance has provider `zai` (run sheet section 9) |
| no Discord binding (C2-13b, library only) | none either. F11 checks that `<dataRoot>/discord/` holds no binding | the factory's connector stays on dragon-lin. Two connectors on one bot token would split its events |
| the claude marker prompt | runs, since the chief's harness is claude-code | |
| serve flags: preview trio, `--send`, proof pair | `--port 732`, `--business mosaic-stack`, `--tester-port 7333` | no proxy on .53 |
| bus: no `--pm`, no `MOSAIC_CLAUDE_BIN` | `--pm`, and `Environment=MOSAIC_CLAUDE_BIN=<--claude>` | the PM dispatches the factory's work; without the path the bus finds no claude on the unit's PATH |
| Console proof file (run sheet section 9, .54) | none | no proof pair |
All of these are inputs to the landed scripts. Row 230 implemented the four factory items r6 asked for
(serve flags, `--pm`, `--claude`, row 190's tokens), and nothing in them hardcodes a Case 1 value.
## 3. Model access
Q185: Case 1 uses the account the factory uses today, the Claude subscription behind dragon-lin's
`claude-session.env`. No script copies that file and none reads its value. In the window, Jason, or the
person he names under the Q173 secrets rule, makes a credential for .53 from that account and writes it
to `/srv/mosaic/.config/mosaic-dev/secrets/claude-session.env` as `mosaic`, mode 0600 (run sheet
section 9). Nobody prints it. The check is `stat -c '%U %a %F' PATH` only (F8).
The bus unit reads it through `EnvironmentFile=-` (`case2-unit.sh:243`). The leading `-` means a missing
file doesn't stop the bus, so the chief's first launch would fail instead. The window places the file
before the units start (section 6, W9), and the precheck's claude marker prompt then proves it works
without printing it.
Quota: the factory on dragon-lin and on .53 share one subscription. Q185's "use existing" accepts that.
The pi harness stays off on .53 until P19 #383 settles (mos-0865). The business file names claude only.
## 4. Upgrade, rollback and backup on .53
All three are `scripts/stack-upgrade.sh` (row 233), run as root by ops-01 from `/root/mosaic-stack` at the
reviewed commit. Usage, exits and the step log are in `docs/TOOLS.md`, "Root's upgrade driver", and run
sheet section 6.
| Action | Command | Who | Go |
|---|---|---|---|
| upgrade | `stack-upgrade.sh upgrade --instance dev --bundle /srv/mosaic/incoming/<sha>.bundle --sha <sha>` after run sheet section 6's per-upgrade lines | ops-01 | Mos per run; `--migrate` also needs Jason present (decision 96) |
| rollback | `stack-upgrade.sh rollback --instance dev --to <copy> [--restore <ACT> [--events N]]` | ops-01 | Mos per run. Mos or Sage picks `<copy>` from `stack-release.sh status mosaic-stack --units external`, read as `mosaic`. The plan refuses unless it is the previous distinct copy |
| backup of the store | A3's `backup_store` into `<dataRoot>/backups/stack/<ACT>`, inside every upgrade | the driver | the upgrade's |
| rehearsal | `stack-release.sh rehearse` against the log's newest backup, before anything stops, on `--rehearse-port`, default 7339, which section 0 found free | the driver | the upgrade's |
| backup of the VM | a PBS backup of VM 1008 before the install window and before any `--migrate` | ops-01 | the window's go (Q182, Q183: agents keep PBS) |
Three .53 specifics:
1. The first upgrade after install needs `--no-rehearsal` in its go. The install's adopt takes no backup,
so the log records none, the rehearsal exits 3 (`no-backup`), and the driver goes on only with the
flag (`stack-upgrade.sh:323-324`). Every later upgrade refuses the flag (`rehearsal-required`).
2. Exit 5 (`args-failed`): the new stack is live and confirmed, but `dev.args` still names the old copy.
ops-01 moves the file the result line names into place with `mv -f`, and nothing else (run sheet
section 6).
3. Exit 2 leaves both units stopped and the activation open. ops-01 sends Mos the exit and the last
lines of `/var/log/mosaic-stack/upgrade-dev.log`, and Jason or Mos settles it with `confirm` or `revert`
as on dragon-lin. A unit that doesn't stop within `--timeout` ends here on purpose (A2f's
`stale-start`, duckworth-0055 N1, now in run sheet section 6).
The store backup doesn't hold the config dir or the credential. PBS backups of VM 1008 hold the whole disk,
the credential included (P4). A restore swaps only the store and leaves `claude-session.env` in place.
Re-install, for a serve flag or role change, is not an upgrade. It needs its own go and runs: stop the
Console, then the bus; rewrite `dev.args` with the same `--copy`; `case2-unit.sh` with it; both units start
again from the render. Row 230 N1 (webby-0046) holds here: a re-render with the units running leaves each on
its old copy, so ops-01 stops both first. `stack-upgrade.sh` already stops both before it renders.
## 5. Acceptance: `scripts/case1-accept.sh`
New in this row. ops-01 runs it as root on .53, from `/root/mosaic-stack`:
```
case1-accept.sh --business mosaic-stack --args /etc/mosaic-stack/dev.args --claude-pin <pin> --node-pin <v>
```
It reads the user, home, node, claude and ports from the args file and refuses (exit 2) when that file
fails `stack-upgrade.sh`'s rules. Every check inside the instance runs as
`sudo -u mosaic -H env PATH=<node dir>:/usr/local/bin:/usr/bin:/bin`. It changes nothing on the host
except what F3's message writes to the store. It prints one line per check, `<id> <path> <mark>
<evidence>`, then a count of each mark. Marks: `closed`, `accepted Q182`, `accepted Q183`, `accepted
mos-1096`, `accepted mos-1101`, and `unnamed`, which means "not named in Q182, Q183 or a Mos ruling".
It exits 1 when any F check fails and 0 otherwise. A P check never changes the exit. Each `unnamed`
line goes to Mos, who takes it to Jason (R8 N1). Duckworth reads the whole output.
It prints no value from `claude-session.env` and never opens it.
Functional checks. Any failure fails the row:
| Id | Check | How |
|---|---|---|
| F1 | the units run as `mosaic` | for `[email protected]` and `mosaic-webui.service`: active, `User=mosaic`, and the uid in `/proc/<MainPID>/status` is `mosaic`'s |
| F2 | the Console answers on 127.0.0.1:732 only | `curl -fsS http://127.0.0.1:732/healthz` succeeds, and `ss -Hltnp` shows 732 bound to 127.0.0.1 only, by the Console's MainPID. Jason reaches it with `ssh -L 7332:127.0.0.1:732 [email protected]`. A LAN listener waits for Q175 SSO (sage-1451 Q3) |
| F3 | one tester message gets a reply | as `mosaic`: `mosaic talk chief <marker> --business mosaic-stack --tester --wait 300`. A stored reply to the marked message passes. The inbox shows decisions only, so it isn't used |
| F4 | the precheck passes | `case2-precheck.sh --business mosaic-stack --profile factory` as `mosaic` exits 0 |
| F5 | a role session runs under bwrap with the profile | while F3's reply is pending: a `/usr/bin/bwrap` process owned by `mosaic` has a claude child. Its `/proc/<pid>/attr/current` equals `bwrap (enforce)` and the child's equals `bwrap//&unpriv_bwrap (enforce)`, exact strings after the trailing newline is cut |
| F6 | claude is the pin | the args file's `--claude` path sits under `/opt/mosaic-stack/claude-<pin>/`, and its `--version` as `mosaic` prints `<pin> (Claude Code)` |
| F7 | the PM run is live | `launches list --json` as `mosaic` has exactly one live entry for the PM's instance (`launch.by`), the check `confirm` runs |
| F8 | the credential's file | `stat -c '%U %a %F'` on `claude-session.env` reads `mosaic 600 regular file`, and it isn't a symlink. Run sheet section 9 marks this "precheck line missing" |
| F9 | the autoupdater is off | `/etc/claude-code/managed-settings.json` is `root:root` 0644 and its `env.DISABLE_AUTOUPDATER` is `"1"`. Run sheet section 3 marks this "precheck line missing" |
| F10 | node is the pin | the args file's `--node` is `/opt/mosaic-stack/node-<v>/bin/node` with `<v>` the `--node-pin`, and its `--version` prints `<v>`. Run sheet section 2 marks this "precheck line missing" |
| F11 | no Discord binding | `/srv/mosaic/.mosaic-dev/discord/` is absent or holds no `*.json` (section 2) |
Host paths. These report and never fail the row:
| Id | Path | Mark | Evidence |
|---|---|---|---|
| P1 | `mosaic` has sudo | closed only when `sudo -l -U mosaic` prints "is not allowed to run sudo"; any other output is unnamed | the `sudo -l` result |
| P2 | `mosaic` has supplementary groups or a key | closed when `id -G mosaic` is one entry and `~mosaic/.ssh/authorized_keys` is absent or empty | `id`, file state |
| P3 | `localadmin` NOPASSWD sudo, reached with the dragon-lin key | accepted Q183 | `sudo -l -U localadmin` |
| P4 | root on pve over VM 1008, and PBS backups that hold `/srv/mosaic` with the credential | accepted Q182 and Q183 | a fixed line; the script can't see pve |
| P5 | `jarvis`, which runs Hermes, reaches `/srv/mosaic` through sudo, docker or lxd | closed when `jarvis` is in none of the three; unnamed otherwise. #423 step 4 removes all four groups before the install (mos-1091 4c) | `id jarvis` |
| P6 | other members of sudo, docker, lxd | closed when sudo holds only `localadmin` and docker and lxd are empty; each other member is its own unnamed line | `getent group` lines |
| P7 | a file under `/etc/sudoers.d` naming `mosaic` | closed when none | file names |
| P8 | the Console or tester reachable from the LAN | closed when 732 and 7333 are bound to 127.0.0.1 only, each by the Console's MainPID, and nothing listens on 7331 | listener table |
| P9 | a user namespace through `/usr/bin/bwrap` | accepted mos-1096 only while all eight hold, unnamed otherwise: hostcheck items 1 to 6, read from `/usr/local/lib/mosaic-stack/hostcheck.sh --check`'s own `ok N` lines (item 7 is P10's floor); `sudo -u jarvis /usr/bin/bwrap --version` fails with "Permission denied"; `getent group mosaic` lists no member and no other account has its gid. F5 adds the label of a real role session | the hostcheck lines and each item |
| P10 | a session binds the tester port 7333 while the Console is down | accepted mos-1101 while the port floor is above 732 and 7333 is held by the Console's MainPID | the floor, the owner pid |
| P11 | the boot check runs before the bus | closed when `mosaic-hostcheck.service` is enabled and `systemctl show -p Before` on it names `mosaic-bus@<business>.service` for the args file's business; unnamed otherwise (section 7) | the `Before=` value |
P9 reads hostcheck's output, which root's own script prints, by matching `^ok [1-6] ` lines. It runs `--check` only,
never `--enforce`, so the acceptance can't close bwrap.
Tests, in `packages/cli/tests/case1-accept.test.mjs`. The script takes a test seam, `--root DIR`, for
`/proc`, `/etc`, `/srv/mosaic` and `getent`, and refuses it when run as root, as the hostcheck does. Fake
`systemctl`, `curl`, `ss`, `sudo`, `bwrap`, `sysctl`, `stat`, `claude`, `node` and `hostcheck.sh` on PATH.
Nothing reaches .53 or dragon-lin's live state, and no test reads a real credential. Cases:
- every check passing exits 0, with the counts matching the lines;
- each F check failing alone exits 1 with its line;
- F5 fails on `unpriv_bwrap (enforce)`, `bwrap//&unpriv_bwrap (complain)` and a trailing space;
- F6 fails on a stub `claude.exe` that prints nothing and on a path outside `claude-<pin>`;
- F8 fails on mode 0640, on another owner and on a symlink, and the stand-in credential's value never
appears in the output;
- F11 fails on one `*.json` under `discord/`;
- each P check in each of its marks: P1 with output that grants nothing but lacks the refusal text
(unnamed), P9 unnamed once for each item missing, P10 unnamed with the floor at 700 and with 7333 held
by another pid, P11 unnamed with `Before=` naming another business;
- every P check `unnamed` still exits 0;
- a bad args file refuses with exit 2 before any check;
- every in-instance call goes through `sudo -u mosaic -H env PATH=<node dir>:...`, read from the fake
`sudo`'s recorded argv;
- the hostcheck fake records `--check` and never `--enforce`.
Mutants, each killed by a named case:
1. F1 passes on a MainPID owned by root.
2. F2 accepts a listener on 0.0.0.0.
3. F3 passes without a reply.
4. F5 matches a substring.
5. F6 skips the `--version` check.
6. F8 skips the owner check.
7. F11 ignores `discord/`.
8. P1 closes on any output.
9. P5 maps to `closed` with `jarvis` in docker.
10. P9 drops the jarvis item.
11. P11 accepts any `Before=`.
12. A P check's `unnamed` sets the exit to 1.
## 6. The .53 window
Nothing in this row touches .53 (sage-1809). Every root step below is ops-01's, over
`ssh [email protected]` with `sudo`, and waits on a Jason decision (mos-1086). The window needs:
- row 226 landed;
- Jason's or Mos's go naming the commit, the bundle's sha256, the node and claude pins, the role set and
Jason's human id;
- a backup first;
- a STATE report after.
| # | Step | Runs as | Source |
|---|---|---|---|
| W0 | re-read section 0's items; stop on any change and report it | `localadmin`, read only | section 0 |
| W1 | PBS backup of VM 1008 | ops-01 on pve | section 4 |
| W2 | the stack's user and home | root | run sheet 1 |
| W3 | node under `/opt` | root | run sheet 2 |
| W4 | claude under `/opt`, managed settings | root | run sheet 3 |
| W5 | bubblewrap, the profile, the statoverride, the no-new-privs test, the drift stop; `hostcheck.sh --check` exits 0 with item 7 at 1023 | root | run sheet 4 |
| W6 | the port floor (read) | root | run sheet 5 |
| W7 | the bundle, root's checkout at `<sha>`, `mosaic`'s clone | root, then `sudo -u mosaic -H` | run sheet 6 |
| W8 | `case2-install.sh --profile factory` with section 1's inputs: bootstrap, the business file, roles, human id, the copy | `sudo -u mosaic -H env PATH=...` | row 226 |
| W9 | place `claude-session.env` | Jason, or who he names | run sheet 9, section 3 |
| W10 | write `dev.args` (section 1); `case2-unit.sh` from it, which enables both units and starts the bus, then the Console | root | run sheet 7, 10 |
| W11 | `case2-precheck.sh --business mosaic-stack --profile factory` exits 0; `hostcheck.sh --check` exits 0 with item 7 at 732 | `mosaic`; root | row 230, 240 |
| W12 | `stack-release.sh adopt mosaic-stack --units external`, unless row 226's install does it | `sudo -u mosaic -H` | row 232 |
| W13 | `case1-accept.sh` (section 5); the output to Duckworth, then Mos confirms | root | this row |
| W14 | STATE report to Mos | ops-01 | brief |
Install rollback, any step before W13 passes. Stop and disable both units, remove their files and
`dev.args`, then the run sheet's rollbacks for sections 4, 3 and 2 in that order. Removing the user and
home (`userdel -r mosaic`) needs its own Mos go, since it deletes the home. W1's backup covers the rest.
What row 195 needs from row 226. Row 226 is assigned to Gosalyn, briefed and not started, so I'm listing what the window
needs from its design, not designing it:
1. `--profile factory` writes the business file with `bus.tester` on and no `library` key, and the roles
the go names.
2. It writes no token slot and no persona files (its brief says so).
3. It runs before the unit render, since the copy must exist for `case2-unit.sh --copy`, and it starts no
unit.
4. Who writes `dev.args`. The C2-13b brief says the install doesn't write unit files, and the run sheet
says "I2's install writes it". `mosaic` can't write `/etc/mosaic-stack`. So either root's part of I2
writes it, or ops-01 writes it from section 1 at W10. Either works for row 195. The file's content is
fixed above.
5. Whether it runs `adopt`. If it doesn't, W12 does.
I sent these to Gosalyn on 2026-10-21 (gosalyn-0085 acknowledged), and the run sheet takes whichever answer 226 gives.
## 7. The business id
.53's business id is `mosaic-stack` (sage-1813). It appears in:
- the args file, twice;
- the bus unit `[email protected]`;
- the business file name;
- `case1-accept.sh --business`.
The landed boot unit `packages/cli/systemd/mosaic-hostcheck.service` has
`[email protected]`. So at boot the drift stop runs before .53's bus, and DEFERRED 240
N1 (da3051ccc: `After=mosaic-hostcheck.service` in `mosaic-bus.service.in`) doesn't bind this row.
If a go ever names another id for .53, the window stops before W8, and the N1 fix lands first as its own
reviewed row. P11 is the check on the host. It reads `unnamed` when the boot unit's `Before=` doesn't
name the installed bus.
DEFERRED 240 N2 (the apt hook goes in before the first `--check`) is a run sheet order note. This row
doesn't edit the run sheet, so it stays deferred.
## 8. Rulings this design rests on
- sage-1451: Q1 system units; Q3 the Console on 127.0.0.1 with `ssh -L`; Q4 a rebase goes to a new branch
name (#426(a), mos-1086).
- mos-1091, mos-1096, mos-1098, mos-1101: the bwrap path, its profile and P9; the port squat and P10; .53
runs the PM. Their r6 sections stand, and rows 232, 233, 240 and 230 implemented them.
- mos-1108 (Q187) and mos-1118: the installer rows and the scope cut. mos-1122 (Q189): both units start at
boot.
- sage-1522: claude under `/opt`, root-owned.
- sage-1809: no step on .53, root steps named and left to ops-01, the business id stated.
- sage-1813: 226 in the after list (rev 2718); the id is `mosaic-stack` and 240 N1 doesn't apply.
- Q185: the factory's model account. Q173: credentials placed by Jason or his named person.
## 9. Manifest (planned)
- `scripts/case1-accept.sh` (new), mode 100755.
- `packages/cli/tests/case1-accept.test.mjs` (new). Section 5's cases and mutants.
- `docs/TOOLS.md`: a `case1-accept.sh` entry with usage, marks and exits, beside the hostcheck entry.
- `agents/darkwing/work/queue-195/BUILD.md` (new): run environment, the mutant results, deviations.
- No change to `case2-*.sh`, `stack-upgrade.sh`, `stack-release.sh`, `case1-hostcheck.sh` or the run
sheet. Two follow-ups stay out of this row:
- row 230 r2 N1. The "still on copy" line reads the id from the unit file. On .53 neither the install
nor `stack-upgrade.sh` reaches that line, since both start from stopped units.
- DEFERRED 240 N2.
- No change to `~/.mosaic-dev`, `~/.config/mosaic-dev`, dragon-lin's units or `~/.mosaic`.
Gate: Duckworth approves this design, then the manifest; the cli suite and every `scripts/test-*.sh`
green on Sage's gate; section 5's twelve mutants killed in a slot Sage grants.
+91
View File
@@ -0,0 +1,91 @@
# Row 245 build: Duckworth's N1-N3 on `scripts/case1-accept.sh` (row 195 follow-up)
Duckworth approved row 195's manifest round 1 (duckworth-0088, `agents/duckworth/work/row195/REVIEW-m1.md`
at 6afcee2a5) with three notes that don't block. Row 195's code landed as b65014647, and the notes are in
`docs/plans/DEFERRED.md` (d6cff0cdd). Row 245 carries them: brief `docs/plans/2026-10-20_hub-own-uid.md` §
"Row 195 follow-up" at 62ddc96cc, owner Darkwing, reviewer Duckworth, gate owner Sage (sage-1923).
The branch is `darkwing/row245`, on 62ddc96cc. Its first commit is a cherry-pick of `darkwing/row195-n1`
1e3c4767c, which was written on 37171f65b and never run. The script, test and TOOLS.md blobs are the same
as in 1e3c4767c, and none of those paths changed between 37171f65b and 62ddc96cc.
## What changes
N1. F9 ran `$ROOT$NODE` as root (`case1-accept.sh:298` at 37171f65b) before F10 checked that `--node` is
the pinned path. Duckworth offered two fixes: F9's parse through `AS_USER`, or F10's path check first. I
took the path check, plus one more:
- F9 now runs node only when `--node` equals `/opt/mosaic-stack/node-<--node-pin>/bin/node`.
- Then `not_root_only` walks from that file up to `/`. Each entry must be the running user's (root's on the
host) with no group or other write, the rule `case2-unit.sh` `root_only` applied when it rendered the
units. A symlink fails it, because its mode is 777. The first entry that breaks the rule goes in the
evidence.
I didn't run the parse through `AS_USER`. That would hand a check about a root file to the stack's user,
and a process running as `mosaic` shares that node's uid. Whether it could change what node prints then
turns on the host's ptrace setting, and the root-only check doesn't depend on that. Sage agreed in
sage-1877. Rechecking ownership costs one loop and doesn't depend on
how the host was installed.
N2. The header (:9-15) and the `docs/TOOLS.md` entry now list what root runs: `systemctl show` and
`is-enabled` (F1, P11), `curl` on the loopback healthz (F2), `sudo -l` (P1, P3), `sudo -u jarvis bwrap
--version` and `hostcheck.sh --check` (P9), and node for F9 under the rule above.
N3. F6 matched `--claude` by prefix, so `/opt/mosaic-stack/claude-<pin>/../claude-2.0.9/...` passed the
path check. F6 now fails on any `..` segment, before it runs `--version`. F10 compares for equality, so
it needed no change.
Row 195's BUILD.md gets a correction entry for deviation 6. Row 195's DESIGN.md is unchanged. Its "either
works" wording at `DESIGN.md:336-338` is superseded by gosalyn-0087 (root writes `dev.args` at W10), and
it stays in place: an approved design isn't edited (sage-1877).
## Tests
`packages/cli/tests/case1-accept.test.mjs`:
- The node stub touches `node-as-root` in the state directory when something runs it outside the fake
`sudo` (which sets HOME to the stack's home). `host()` sets the node file's directories and the scratch
root to 0755, so the umask can't fail F9.
- "every check passing" also asserts that root ran the pinned node.
- New: "F9 won't run --node as root off the pin path or with a writable directory above it". Another node
path fails F9 and F10, with no root run. A group-writable `bin/` and a symlinked node each fail F9
alone, with the bad path in the evidence and no root run.
- The F6 test gains a `..` case: a path under `claude-<pin>/` by prefix that names 2.0.9's binary, which
prints the pin. F6 alone fails, with "has a .. segment".
That makes 23 tests. All 23 pass on Sage's slot (results below).
## Mutants
The twelve from row 195 still apply, unchanged. These four are new, each one exact replacement:
| # | Mutant | Expected killer |
|---|---|---|
| 13 | F9 runs any `--node` (the pin check becomes `true`) | F9 won't run (another node) |
| 14 | F9 skips the ownership walk (`bad=""`) | F9 won't run (writable `bin/`, symlink) |
| 15 | `not_root_only` checks only the file, not the directories above it | F9 won't run (writable `bin/`) |
| 16 | F6 accepts a `..` segment | F6 stub, path and `..` |
The brief's gate asks for a mutant for each of N1 and N3. Mutants 13-15 are N1's, and 16 is N3's.
## Slot plan
Same shape as row 195's steps, on this row's tip: the single test file, then the sixteen mutants, then
the gate (the cli suite and every `scripts/test-*.sh`), each behind the busy checks and chained with
`&&`. The scripts are in `/mnt/storage/scratch/darkwing-245-out/`.
## Slot results (grant sage-1961, 2026-10-21)
All three steps ran on 0590a29fc with node v26.8.1, launched from `/`. Both busy checks were CLEAR
before each step.
- Singles, 11:27:46-11:27:59Z: `case1-accept.test.mjs` passed 23, failed 0.
- Mutants, 11:28:10-11:31:20Z: all 16 killed, each with exit 1. The runner restored the script, and
its sha256 875bb5b7 matches the committed blob. Rows 1-12 died as in row 195. 13, 14 and 15 died on
"F9 won't run --node as root off the pin path or with a writable directory above it". 16 died on
"F6 fails on a stub that prints nothing, on a path outside claude-<pin> and on a .. segment".
- Gate, 11:31:20-11:42:51Z: the cli suite passed 664, failed 0, skipped 0. Every `scripts/test-*.sh`
exited 0: auth 15, conductor 17, config 31, discord 78, extension-package 18, foundation 44,
land-work 86, queue 28 (its node part 156/0), release 14, task 98. That's 429 selftests, none failed.
- Afterwards no process had its cwd in the worktree, the out dir or TMPDIR, and the
`darkwing-r245_default` network was gone.
Logs: `/mnt/storage/scratch/darkwing-245-out/` (`step1.log`, `mut.out`, `mut/m1-16.log`, `gate.out`).
+191
View File
@@ -0,0 +1,191 @@
# Row 251 build: T27 lists no identities right after `ssh-add -t 1` (Vikunja #453)
Brief `docs/plans/2026-10-21_t27-ssh-add-lifetime.md` (rev 2931), Mos ruling mos-1185 item 2, assigned in
sage-2075. Owner Darkwing, reviewer Dewey, gate owner Sage. Branch `darkwing/row251` from 3b0aef995,
claimed in-progress at rev 2938.
## Step 1: the failure names its cause (e5e4b2e5a)
T27's two lists now carry a message that prints only when they fail. It gives the time from addKey's
start to its resolve and to each `ssh-add -l` call, the hrtime at each with how far into its second it
fell, `/proc/uptime` at each, and whether the agent process and its socket were still there. The checks
themselves did not change. The commit holds nothing else.
## Step 2: the cause
ssh-agent counts a key's lifetime in whole seconds of CLOCK_BOOTTIME, at the add and at the reap. I read
OpenSSH 10.5p1, the version on dragon-lin (`ssh -V`: OpenSSH_10.5p1), at tag V_10_5_P1 (ssh-agent.c
sha256 873691c4, misc.c sha256 ee467f43):
- `misc.c:1790-1798` and `:1828`: `monotime()` returns `ts.tv_sec` of `clock_gettime(CLOCK_BOOTTIME)`,
falling back to MONOTONIC. The fraction of the second is dropped.
- `ssh-agent.c:1315`: the `-t` constraint sets `*deathp = monotime() + seconds`. Lines 1410 and 1598
do the same for the agent's default lifetime.
- `ssh-agent.c:1064`: the reaper drops a key when `now >= id->death`, `now` being `monotime()` again.
- `ssh-agent.c:2650`: the main loop runs `reaper()` after every poll, before it reads requests. A list
that arrives after the boundary sees the key gone.
So a key added at second s plus a fraction f dies at s + N, and `-t N` keeps it N - f seconds, between
N - 1 and N. With `-t 1`, an add late in a second leaves the key milliseconds to live. That matches
Sage's probe in the brief: 8 of 80 `-t 1` adds missed, each one made at 0.9947-0.9973 of a monotonic
second and finished at 0.998-0.0008, and none earlier in the second missed. It also matches proof 5's
failure, where the first list ran 31.9 ms into the test and found no identities.
Node's hrtime is CLOCK_MONOTONIC. BOOTTIME differs from it by the time the host spent suspended. On
dragon-lin the difference read 0.000001 s at 19:09Z, so a monotonic second boundary is a BOOTTIME one
here.
`addKey` and the agent start are not the cause. `addKey` passes the lifetime through as `-t`
(`host-run.mjs:90`), and the agent starts with no default lifetime (`:175`). Production adds the key
with `timeout + 30` (`:180`), where losing up to a second makes no difference. The only caller that
can't afford the lost fraction is T27, which asks for 1 s. The fix belongs in the test's lifetime choice,
and `host-run.mjs` doesn't change.
The slot confirms this against T27 itself (below), not just from the source.
## Step 3: the fix (this commit)
T27 adds the key with `-t 2`. The agent then keeps it more than 1 s and at most 2 s. The first list
runs milliseconds after the add, so it has over a second of margin even under load. The sleep before
the second list grows from 2.5 s to 3.5 s, which keeps the old 1.5 s margin past the new 2 s ceiling.
Both checks stay: listed after the add, gone after the lifetime. A comment above the add says why the
lifetime is 2.
I considered `-t 3` with a 4.5 s sleep for a 2 s floor. One second of floor is far above anything the
first list has needed (31.9 ms in proof 5), and the concurrent-suite run below tests it under load, so I
took the smaller change.
## Base
The branch stays on 3b0aef995. By 19:15Z origin/refactor was at 6096b051b, after rows 66 and 243
landed. `git diff 3b0aef995 6096b051b` touches neither `packages/bus/src/host-run.mjs` nor
`packages/bus/tests/host-run.test.mjs`, so there's no rebase (sage-2084). Row 243 did change
`packages/bus/tests/process.test.mjs`. My slot's bus suites run that file as it was at 3b0aef995, and the
gate rerun on Sage's slot runs it as landed.
## Prediction for part A on e5e4b2e5a (written before the slot)
The hook starts `ssh-add -t 1` at the given fraction of a monotonic second. From the brief's probe, the
agent stores the key about 3 ms later. The first list reaches the agent a few ms after addKey resolves:
Node's exit event, the mark, and `ssh-add -l`'s own start. A red needs the add to land before the second
boundary and the list to land after it.
- 0.990: green. The add and the list both land before the boundary.
- 0.993, 0.995, 0.996, 0.997: red expected. The add lands before the boundary, the list after. At 0.993
and 0.997 I'm less sure, because the list (at 0.993) or the add (at 0.997) can land right at the
boundary. A green at either is in line with the cause, and so is a red.
- 0.998: green. The add lands after the boundary, so the key gets almost a full second.
Every red should show "first list got" an answer with no SHA256 line. It should also show addKey
resolving before a second boundary and the first list starting after it or within a few ms of it, with
the agent alive and its socket present.
Under sage-2084's rule, on e5e4b2e5a only a red at 0.990 or 0.998 counts toward the stop, and two such
reds stop the run. On the fix commit any red counts, and two stop it. In parts B to D, the first red stops
the run.
## Slot plan
All scripts are in `/mnt/storage/scratch/darkwing-251-out/`, launched from `/`, each behind the busy
checks and chained with `&&`, TMPDIR under `/mnt/storage/scratch/tmp`.
1. Confirmation. `align-hooks.mjs` is a load hook, outside the repo, that serves `host-run.mjs` with
`addKey` wrapped to start `ssh-add` at a chosen fraction of a monotonic second. T27 runs unchanged
under it, alone (`--test-name-pattern`). It runs at fractions 0.990, 0.993, 0.995, 0.996, 0.997 and
0.998, three times each:
- on e5e4b2e5a (step 1, `-t 1`). Expected: some first lists fail, and the step 1 message shows the
add's resolve and the list on either side of a second boundary, with the agent alive and the
socket present. These reds are the point of the run.
- on the fix commit (`-t 2`). Expected: all 18 pass.
2. `host-run.test.mjs` whole, once, on the fix commit.
3. The bus suite whole, three times in a row.
4. The bus suite whole in two clean worktrees at the same commit, started together.
## Slot results
Sage's CLEAR came in sage-2154 at 20:58:55Z. `slot-251.sh` ran parts A and B from 20:59:22Z to 21:01:33Z,
on node v26.8.1 and OpenSSH_10.5p1, with TMPDIR `/mnt/storage/scratch/tmp/r251`. At the start, BOOTTIME
minus MONOTONIC read 0.000001 s, then 0.000000 s twice (dewey-0769 N1). So the hrtime fractions below
put the agent's second boundary in the right place.
### Part A: T27 alone under `align-hooks.mjs`, 3 runs per fraction
The fraction is when the hook started `ssh-add`. The hook logged each start within 0.0001 of its target.
| fraction | e5e4b2e5a (`-t 1`) | 68f2dfd4b (`-t 2`) |
|---|---|---|
| 0.990 | 3 pass | 3 pass |
| 0.993 | 3 pass | 3 pass |
| 0.995 | 3 red | 3 pass |
| 0.996 | 3 red | 3 pass |
| 0.997 | 3 pass | 3 pass |
| 0.998 | 3 pass | 3 pass |
e5e4b2e5a went red 6 times out of 18, every time at a fraction the prediction named, so none of them
counted toward the stop. 68f2dfd4b passed all 18. The fix runs used 68f2dfd4b, whose test blob is the same
as c19b4167e's (280132c7).
Every red failed on the first list and got `"The agent has no identities.\n"`, with the agent alive and
its socket present. The step 1 message gave these hrtime fractions. "addKey start" is the mark before the
hook's wait, so its fraction is earlier than the ssh-add start.
| run | addKey resolved | first list mark |
|---|---|---|
| 0.995 rep 1 | 0.9992 (+317.6 ms) | 0.9993 |
| 0.995 rep 2 | 0.9991 (+846.5 ms) | 0.9991 |
| 0.995 rep 3 | 0.9988 (+845.0 ms) | 0.9988 |
| 0.996 rep 1 | 0.9999 (+839.8 ms) | 1.0000 |
| 0.996 rep 2 | 0.0004 (+845.0 ms) | 0.0004 |
| 0.996 rep 3 | 0.0002 (+835.9 ms) | 0.0002 |
At 0.995 the add finished about 4 ms in, before the boundary, and the list mark came just before it. The
`ssh-add -l` process then reached the agent after the boundary. At 0.996 the agent stored the key before
the boundary, and addKey resolved just after it. In both cases the key's whole second ended between the
add and the list, which is the cause step 2 gives. The two edge fractions came out green on the first
build. At 0.993 the list still reached the agent before the boundary, and at 0.997 the add landed after
it, so the key got almost a full second. The prediction allowed either result at those two.
### Part B: `host-run.test.mjs` whole on 68f2dfd4b
24 tests, 24 passed (21:01:18Z, 14.0 s).
### The stop before C1, and the resume
At 21:01:33Z the script stopped before C1, with exit 4 and no red. My own `busy.sh` matched two `sleep 60`
processes, mine, in `darkwing-r251/packages/bus`. Part B left them. They come from T27 "the start sweep
keeps a live bus dir and kills only a matching live process" (`host-run.test.mjs:528` and `:536`). Its
`t.after` SIGKILLs the `/bin/sh -c 'sleep 60; :'` parent, but the `sleep` child lives on for up to 60 s.
That code is outside this row's diff, so the row leaves it alone, and it's recorded below as a follow-up.
Sage confirmed (sage-2159) that the right move is to resume only the scope that hadn't run.
`slot-251-cd.sh` runs C and D as `slot-251.sh` has them, with the same two busy checks. Before each check,
it waits up to 75 s for those orphans to exit: my uid, my trees, a command line of exactly `sleep 60`.
It logs them as it waits. Any other process still trips the checks.
### Parts C and D: the bus suite whole on 68f2dfd4b
| run | start | tests | pass | fail | time |
|---|---|---|---|---|---|
| C1 | 21:02:48Z | 598 | 598 | 0 | 21.6 s |
| C2 | 21:04:06Z | 598 | 598 | 0 | 21.4 s |
| C3 | 21:05:26Z | 598 | 598 | 0 | 22.1 s |
| D1, darkwing-r251 | 21:06:44Z | 598 | 598 | 0 | 24.2 s |
| D2, darkwing-r251b, TMPDIR `r251-b` | 21:06:44Z | 598 | 598 | 0 | 24.2 s |
The script waited 33 s before C2, 34 s before C3, 33 s before D and 32 s before the sweep. Each time it
was waiting for that run's `sleep 60` orphans (two per suite, four after D), and nothing else. After the
wait, the sweep of my trees, the out dir and TMPDIR found 0 processes left (21:08:04Z). Sage confirmed
(sage-2159, sage-2160) that the short gitea-api and `node --check` runs they made during the slot weren't
stops. None of my busy checks refused on any of them.
These runs used the bus files as they were at 3b0aef995. Since then, origin/refactor (666173292, then
7247d80c7 and c3d88840c with row 196) has changed `broker.mjs`, `runtime.mjs` and `server.mjs`, which T27's
file imports, along with other bus files. None of those commits touch this row's two paths or
`host-run.mjs`, and `git merge-tree` of c3d88840c with 68f2dfd4b is clean. The gate rerun in
a clean worktree on Sage's slot runs T27 against them.
### Follow-up, not in this row
T27's start-sweep test leaves the `sleep 60` child of each planted shell running for up to 60 s after
the test. Killing the process group (`process.kill(-pid)`; both shells are spawned `detached`) or
`exec sleep 60` in the shell would end the child along with its parent.
+113
View File
@@ -0,0 +1,113 @@
# Row 273 (#1778): activate --send and --no-sso
Darkwing, 2026-10-22. Brief: `docs/plans/2026-10-22_activate-send-nosso.md` (blob in f0d0b31e9), approved by
Mos in mos-1246 (F39). Base: origin/refactor 0042f713d. Reviewer: Filbert. Gate owner: Sage.
## What changed
Only `scripts/stack-release.sh` and its two node test files.
- `activate --send` puts `--send` into the run's Console flags after `--sso` and before the tester
flags, where webui-service.sh renders it. It refuses `send-needs-sso` unless those flags hold `--sso`,
given or carried. The plan line is `send: on; --send was given`, or `send: carried` when the pointer
already holds it. `check_target` lets it name the pointer's copy only when the pointer holds no `--send`,
so a second `--send` on the same copy refuses `already-active`.
- `activate --no-sso` refuses `sso-not-on` when the pointer holds no `--sso`. Otherwise it takes the
Console flags from a rollback set (below) and keeps the pointer's tester flags. `send_for_target`
drops `--send`, whether it came from the set or the pointer. It is the only place that does, so one
mutant there (M3) shows the drop is tested. The plan prints `sso: off; Console flags from <set>/<file>; restores <flags>`
and a send line, `send: dropped; --no-sso drops --send (F39)` or `send: off; --no-sso was given and the
pointer holds no --send`. The steps log gets `drop --send; --no-sso was given` and
`turn off --sso; the Console flags come from <set>/<file>`.
- Usage errors: `--send` with `--no-send`; `--no-sso` with `--sso`, `--send`, a proof pair or
`--no-proof`; either flag on any verb but activate; either flag under `--units external`.
`--no-sso --no-send` is allowed, since the brief doesn't forbid it and both drop the same flag.
- The set read that `sso_base` did inline for a rollback to a Console without `--sso` moved into
`set_flags`, which both paths call. Its three messages are unchanged, and T57 still pins them.
- `from_log` has a new mode, `sets`: the activation of each ok activate and rollback line, newest first,
stopping at the adopt line, which took no rollback set.
## The consequential choice: which set --no-sso reads
The brief says the flags come from "the rollback set of the activation that turned `--sso` on", and that
"a set whose Console already ran with `--sso`" refuses. Each set holds the Console unit from before its
run. So the activation that turned `--sso` on is the newest one whose set holds a Console without
`--sso`: every activation after it ran with `--sso`, and so did every set it left.
`no_sso_base` walks the log's sets newest first and stops at the first set whose Console has no `--sso`.
It refuses `sso-off-flags` at the first set it can't read (missing, failing its SHA256SUMS, or with no
argv the script can parse), since it can't tell whether that set was the one. If every set ran with
`--sso`, it refuses with `the Console in <set>/<file> already ran with --sso, and the log names no
earlier activation`. A log with no set at all refuses with `the log names no activation with a rollback
set`.
The tradeoff: a later same-copy re-pin that carried `--sso` (a `--no-send`, or a re-pin onto a newer
copy) doesn't break `--no-sso`, which the phase 2 window needs if a re-pin lands between step 5 and a
rollback. The cost is that "a set that ran with `--sso` refuses" now applies only when no older set
without `--sso` exists. A tampered set on the walk still refuses, even one newer than the set the walk
would have used. Filbert, please rule on this reading.
## Filbert's early look: B1 and N1 (sage-2315)
Filbert accepted the walk. Sage ruled both findings into this row.
- B1: row 200's rollback to a copy whose Console has no `--sso` took the flags from the set and kept
the pointer's `--send`. From an `--sso --send` pointer, which this row's `--send` can now make, that
gave a Console with `--send` and no `--sso`, which F39 b forbids. `send_for_target` now drops `--send`
whenever the run drops the pointer's `--sso`, so it is still the one place that drops it. The plan
line reads `send: dropped; the run drops --sso, and --send needs it (F39)`, and the steps log gets
`drop --send; the run drops --sso`. Row 200's sso line now names only the tester as following the
pointer.
- Changed existing assertion, for the review to approve by name: T57 item 3 (sage-1389), "the
plain case", ends with `assert.deepEqual(pointer(g).console,[...noSend(gbase),...pair(f)])`. It
used to expect `'--send'` at the end. The case seeds a legacy `--send` pointer, turns `--sso` on
(which carries `--send`), then rolls back to B, whose Console has no `--sso`. A carried `--send`
that ends without `--sso` breaks F39 b whatever its source, so the old pin asserted the wrong
outcome (Sage accepted this in sage-2321). Row 200's two sso plan strings also lose "--send and"
(`ROLLBACK_PLAN` and the round 3 named-instance case), since `--send` no longer follows the pointer
on that path.
- N1: the walk skipped an ok line with no activation. Skipping it could land on an older set that
isn't the right one, so it now refuses `sso-off-flags` with `an ok line in the log names no
activation`. The walk reads the log through `mapfile`. That gives no entry for an empty log, so a
log with no set still gets its own message.
## test-release.sh
The window plan says test-release.sh "gets cases for both". The brief lists it only as a file to run
whole. test-release.sh is release.sh's Docker selftest and doesn't call stack-release.sh, so the cases
live in the node tests and test-release.sh runs unchanged.
## Tests (T58 in stack-release.test.mjs)
- T1: `--sso --send` from B onto C1 with a tester port: plan, pointer, unit and steps. `--send` beside a
carried `--sso` re-pins C1 once; a second `--send` refuses `already-active`; C carries it.
- T2: `--send` without `--sso` refuses on another copy and on the pointer's copy, also when the pointer
carries `--send` alone; `--plan` lists the refusal.
- T2 (sage-2315 B1): `--sso --send` onto C1, then a rollback to B, whose Console has no `--sso`. The
pointer and the unit end with neither flag, and the plan and steps name the drop.
- T2 and T4 usage: every forbidden pairing and verb, checked against the full usage text.
- T3: from an `--sso --send` pointer, `--no-sso` on the same copy gives back the pre-`--sso` ExecStart
line byte for byte, without `--send`. A second case walks past a `--no-send` re-pin that ran with
`--sso` and keeps the pointer's tester port (7334), which differs from the set's (7333). A third
(sage-2305 a) turns `--sso` on, then re-pins twice with `--send` and `--no-send`, so the two newest
sets both hold `--sso`. `--no-sso` then gives back the arrival's ExecStart line byte for byte.
- T4 (sage-2305 b): two sets, both edited or written to hold `--sso` with sums intact, refuse
`sso-off-flags` through `refused()`.
- T4: `sso-not-on`; an ok line with no activation; a set that fails its sums, ran with `--sso`, has no
argv or is missing; a log with no set. Each runs through `refused()`, so nothing stops and nothing else changes.
- T5: stack-release-external.test.mjs adds `--send` and `--no-sso` to the row 232 usage list.
- T55 test 5 and the T57 usage test match the new usage line.
## Mutants
| # | Change | Expected killer |
|---|---|---|
| M1 | `set_flags` skips the SHA256SUMS comparison when `--no-sso` is given | T4 tampered set |
| M2 | `no_sso_base` skips the `sso-not-on` refusal | T4 `sso-not-on` |
| M3 | the `--no-sso` branch of `send_for_target` keeps `--send` | T3 |
| M4 | `--send` skips the `send-needs-sso` refusal | T2 |
| M5 | parse_opts drops the `--send`/`--no-send` rule | T2 and T4 usage |
| M6 | a rollback to a Console without `--sso` keeps `--send` (B1) | T2 (sage-2315 B1) |
| M7 | the walk skips an ok line with no activation (N1) | T4 no-activation line |
Runs and results go in the round's notes once Sage clears the slot.
@@ -0,0 +1,17 @@
{
"old_base": "980cec88c",
"new_base": "6af85df4b",
"old_branch": "gander/row278",
"new_branch": "gander/row278-b",
"replayed_commits": 0,
"source_carried_uncommitted": true,
"upstream_source_test_paths": [
"packages/bus/tests/tasks.test.mjs",
"packages/processing-control/tests/stop-run.test.mjs",
"packages/webui/tests/processing.test.mjs"
],
"overlap_with_candidate_paths": [],
"direct_test_file_reads": false,
"shared_fixture": "packages/webui/tests/fixture.mjs close export, unchanged upstream",
"note": "The focused tests do not import processing.test.mjs, tasks.test.mjs or stop-run.test.mjs, nor their changed fixtures. serve.mjs imports processing-http.mjs, which did not change in this integration. The whole WebUI and bus suites cover the first two changed test files on the new base."
}
+126
View File
@@ -0,0 +1,126 @@
# Row278 / #1783: Console thread claims
Gander, prepared 2026-10-22T11:37:16Z. Reviewer Webby. Brief: docs/plans/2026-10-22_owner-thread-claims.md, section Brief: the Console shows thread claims. Authority sage-2491, design notes gander-0087/0088, Webby acceptances webby-0115/0116 (39c821e7c, 873992a9e), then build instruction sage-2607 after277 landed62f53b1e0. Final277 shape is argument-free [{thread,instance,holder_run,harness,at}], oldest thread first.
## Current state and boundaries
Row253 is not mid-run and has no completed C4 gate. It is held unchanged while278 goes first. Already in the seat's isolated worktree; node_modules remains the plain canonical symlink. No install, new runtime dependency, harness launch, live config/unit/port change, credential read, provider call or paid action. Sage registers sessions. Claim and queue-next commands execute Node, so neither ran while another seat holds the slot. The claimant move belongs in the same CLEAR gap as the gate.
Sage-2625 moved the required base from980cec88c to6af85df4b. New branch gander/row278-b preserves gander/row278 and the row253 branches. There were no row278 commits yet, so the rebase has zero replayed commits; the pending source/test blobs were preserved. BASE-DRIFT.json records upstream's three test paths. No candidate path overlaps. Focused tests do not import/read those test files; shared fixture.mjs close() is unchanged, as is processing-http.mjs imported by serve.mjs. WebUI and bus whole suites include the changed processing.test.mjs and tasks.test.mjs on the new base.
## Implementation decisions under the accepted design
- cli.mjs adds only the normal listener's named thread.claims read adapter. It sends no arguments and makes no eligibility guess. views.mjs and testerBus are unchanged. The bus checks human/reader authority. No --send requirement.
- serve.mjs has a named read allowlist entry, refuses query arguments, and gives the tester listener explicit403 tester-refused before busRead or any supplied bus callback. GET only; no new write route.
- bus.js adds a separate Thread claims table after the unchanged Held roles section. Only thread, holder_run, harness and at are projected through existing text/time escaping. Extra instance/name/body/address fields never render. No s1-agents selector or role count change.
- R1: only signed-out escapes the section catch. Every other error, including403, evicts only thread.claims from the existing cache, shows its reason locally and preserves roles. The following stale repaint cannot recover refused claims.
- Sign-out uses the existing global data/DOM clearing path. The section also rejects an answer that arrives while signed out and deletes that late cache entry. The sign-out tests check the visible data and subsequent fallback behavior; the late-answer test also waits for JSON consumption.
- The section awaits the existing config read before testing known tester mode. This prevents a direct Agents navigation from requesting owner metadata before the tester flag arrives. The server guard is independent of this client display choice.
## Tests written before implementation, not executed
Four tests in thread-claims.test.mjs cover read envelope/no-store/no-send, argument and method refusal, malformed/empty/refused answers, tester-socket403 with zero bus calls, and a loader stand-in proving the normal adapter sends thread.claims with no args. Six browser tests cover:
1. Held/empty/released claims, exact headers/time and byte-equal role section/count before/after refresh.
2. HTTP403 plus not-configured and outcome-unknown stay local; a subsequent all-read failure proves old claims cannot return through the stale cache.
3. Hostile visible fields are escaped; hostile extra instance/name/body/address fields are absent; no injected DOM nodes or scripts execute.
4. A claims401 sign-in-required response uses global sign-out, removes claims/roles and prevents cached re-use.
5. The actual tester socket browser retains role rows, renders no owner section, and makes no claims HTTP or bus call.
6. A held claims response delivered after sign-out is not displayed or recovered on the next unavailable read.
The test-first execution order is intentionally held by Sage's no-Node rule. No RED or GREEN observation is claimed. On CLEAR, window.py red restores all three source files to6af85df4b temporarily, runs the named HTTP/section RED cases, then restores byte-identical source and git status. Only intentional missing-feature failures count as RED.
## Named proposed checks
M1 removes the section and M2 merges thread rows into roles; both are killed only if the named held/release browser test fails. M3 also rethrows403; the named byte-equal role-section test must kill it. M4 removes the tester guard; the socket test must observe the wrong status/call count. M5 dispatches agents instead of thread.claims; the adapter test checks the exact verb/args. M6 retains the claims cache on refusal; the stale repaint in the local403 test must expose that. UNIQUENESS.json is a source-only count/hash check: all six old strings occur exactly once. It is not kill evidence.
## Gate prepared, all steps NOTRUN
On Sage CLEAR: claimant move, syntax preflight, two intended RED cases, both touched files whole, M1-M6 with passing bases and per-change byte-identical restoration, bus whole, webui whole, all ten scripts/test-*.sh. Use TMPDIR from mktemp -d /mnt/storage/scratch/tmp/gXXXXXX, pipefail and tee. Busy check before every start. Log/wrapper names must not match the busy detector. Prepare commands in JSON to keep their text out of wrapper argv. checks.py and window.py were prepared from the proven253 harness but have not run; syntax classification uses node --check only, and runtime failures remain test failures. Per-case timeout is a stop for classification, never silently counted as a kill. Conservative stop on the first unexpected failure and report it to Sage; no retry without a ruling. Return the slot with per-step pass/fail/skip counts, elapsed seconds, kill table and cwd sweep count.
Manifest digest: d6e1476c8c37f41e7b199175bf9fec84696c950c6f169bb4e5c14286103ca882. Final review is Webby's manifest round; no author self-review replaces it. Static author review so far: examined all three source hunks, request/auth dispatch, local versus global refusal, tester config timing, field projection/escaping and fixture cleanup. git diff --check is the only executed check and finds no whitespace errors. No Node, browser, syntax execution or test has run.
## Committed candidate under sage-2630
Source commit e7d21b91b82c6cc1cec0a87995012a87b070b9bf contains all six runnable source/test/doc paths on gander/row278-b. Sage clarifies that invariant8 gates refactor commits, while the seat gate and Webby need a committed candidate tree. The previous packet-only status is superseded. This following commit records the source SHA separately, regenerates the manifest from git blobs and saves sha256sum -c output. Digest remains d6e1476c8c37f41e7b199175bf9fec84696c950c6f169bb4e5c14286103ca882; all six source blobs equal the previously frozen candidate. No Node, test, syntax execution or browser ran. No push until green.
The accepted first-run stop rule is explicit: a red in our new tests stops and goes to Sage; a red in a test already on refactor goes to Mos before Sage places it (mos-1272). Both categories stop immediately. Expected missing-feature RED observations are the intentional red stage, not unexpected failures. No automatic rerun.
## Run1 void, test-only repair and run2
Grant sage-2632: claimant move rev3195 succeeded. Syntax5/0 (0.320s total); two intended RED cases observed (0.265s HTTP404,3.922s missing section) with byte-identical restoration; first new file whole3/1/0 in0.315s. Failure: the adapter loader omitted BusReadError required by the base's chat.mjs import. The runner stopped before the browser whole file or any remaining step. No timeout. Cwd sweep0 run leftovers; the raw match was only pre-existing chrome-devtools-mcp PID2880439, recorded with its start receipt and untouched. No pre-existing test ran red. Reported as gander-0092 and returned the slot.
Sage-2638 places the first own-test red and approves only the fake export, with all assertions unchanged. Webby-0133 confirms the import graph. Test-only source commit 964b6b1848d3bb5f2c15f9c835eb07783596ced9 adds that export. Run1 is void; no result carries, including intended REDs. New manifest digest 188071d851e1f68297a7160a2bd557d9ca1b2776897ea2dd3b2c910ffd1c1f4a; only the new HTTP/adapter test blob changes. Runtime source and other tests are identical.
The harness now wraps every controlled node --test invocation with timeout -k10 300. The wrapper's124/137 outcomes are marked timeout, never pass or killed; the outer330s harness wait is a fallback. Each command uses the busy check, pipefail and tee. The source/test-only repair and record commit execute no Node. Run2 may start on own busy CLEAR without another Sage message, under2638. It repeats syntax, both REDs, both files whole, M1-M6, bus whole, webui whole and ten shells. A second unexpected red of any kind goes to Sage before any further change, then Mos under mos-1272. No automatic rerun. A15-minute status and40-minute notice still apply. Run2 numbers follow here after execution; none is claimed yet.
## Run2 void, awaiting Mos before any repair
Grant sage-2638 on42abda031/source964b6b184: syntax5/0 in0.320s; expected REDs0.214s and3.772s, restored byte-identically; new HTTP/adapter whole4/0/0 in0.365s; new browser whole6/0/0 in4.023s; M1-M6 killed6/6, survivor0, timeout0, passing bases2.159s and changed runs12.765s; bus whole793/0/0 in23.116s; webui whole344/1/1 in55.324s. All ten shell files NOTRUN. run2/SUMMARY.json is assembled from preserved results and raw logs; KILL-TABLE.md names every check. All results are VOID under sage-2644, with no carry into run3.
The second unexpected red is pre-existing shell.test.mjs:415, five states on Board, Inbox, Tasks, Agents and Trail, assertion463: Agents normal state expected0 banners, got1. Static read shows stubBus lacks thread.claims. The section correctly shows the resulting local invalid-response banner. Proposed repair is an empty row array and callback in that existing stub, with every assertion unchanged. No repair, source/test/fixture/driver change or rerun has been made while Mos rules. Reported to Sage, Mos and Webby as gander-0094; slot returned. Sweep0 run leftovers, pre-existing chrome-devtools-mcp excluded with evidence from run1.
Named environment-only skip: editor rebuild from source needs exactly esbuild0.28.2; canonical node_modules has0.28.1. MOSAIC_REQUIRE_EDITOR_BUILD=1 would turn it into a failure. No install attempted; preserve and name this skip in run3.
Sage-2644 settles nested timeouts: do not edit any scripts/test-*.sh, even temporarily. At the call, wrap each whole file as timeout -k10 900 bash scripts/test-X.sh, which bounds all nested children. No such script was edited or run in run2. The planned harness-only call change will be made after Mos's ruling, before run3. Every direct node --test call already uses timeout -k10 300; command JSONs verify that prefix. Run3 starts from the top after Megavolt and on the granted slot. No Node executes while waiting.
## Mos-1274 repair and run3 bounds, before execution
Test-only commit 9696d1fcb78d6082cae8dcb61913225e98c9c138 changes exactly two fixture lines in shell.test.mjs: adds an empty thread.claims row list and the callback using the existing verb() fail/hold path. No assertion changes. No runtime blob changes. This file joins the manifest and the independent whole-file phase, for seven paths and digest 8fa859a0c617defe42e50028b057a603c6634f6db47ac2e3f7c01dfb290228a3. Webby rechecks this digest. No Node or test has executed after the second stop.
Run3 waits for Sage's slot-to-you after Megavolt. It starts from the top. window.py now includes shell.test.mjs in the touched whole-file phase and wraps each whole shell invocation as timeout -k10 LIMIT bash scripts/test-X.sh. No scripts/test-*.sh bytes are edited. Any such timeout is unplaced to Sage and Mos. A further red or moved existing assertion is likewise unplaced; no automatic rerun.
Longest receipt selection: scanned every available Gander row196 JSON result/summary at ec1e7fad8 for successful, complete bash whole-file entries with one scripts/test-*.sh argument. This is the recorded-duration set available to this seat, not a claim to all fleet timings. Row278 runs1/2 ran no shell file. Each bound is ceil(3*longest)+120 seconds for headroom against newer-base changes; if no record existed it would be900 per sage-2646. All ten have receipts. SHELL-LIMITS.json records the exact durations, sources, script hashes and consulted set.
| Whole shell file | Longest recorded seconds | Limit seconds | Receipt |
|---|---:|---:|---|
| scripts/test-auth.sh | 1.908123 | 126 | ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json |
| scripts/test-conductor.sh | 8.057174 | 145 | ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json |
| scripts/test-config.sh | 3.167892 | 130 | ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json |
| scripts/test-discord.sh | 8.776728 | 147 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
| scripts/test-extension-package.sh | 3.012857 | 130 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
| scripts/test-foundation.sh | 39.708726 | 240 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
| scripts/test-land-work.sh | 12.623263 | 158 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
| scripts/test-queue.sh | 23.443742 | 191 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
| scripts/test-release.sh | 12.168674 | 157 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
| scripts/test-task.sh | 36.783798 | 231 | ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json |
Run3 numbers will be appended here after execution. Run1/run2 remain void next to their numbers above. No result carries.
## Run3 green under sage-2648
Candidate3e4c77ac6, source9696d1fcb, manifest8fa859a0. Fresh run from the top; nothing carried from void runs1/2. Started12:26:46Z and completed verification12:31:45Z,299 wall seconds. No unexpected failure, assertion change or timeout.
| Step | Pass/fail/skip | Wall seconds |
|---|---:|---:|
| syntax-0 | 1/0/0 | 0.064 |
| syntax-1 | 1/0/0 | 0.064 |
| syntax-2 | 1/0/0 | 0.064 |
| syntax-3 | 1/0/0 | 0.064 |
| syntax-4 | 1/0/0 | 0.064 |
| syntax-6 | 1/0/0 | 0.064 |
| red-0 | 0/1/0 intended RED | 0.214 |
| red-1 | 0/1/0 intended RED | 3.773 |
| focused-0 | 4/0/0 | 0.365 |
| focused-1 | 6/0/0 | 3.922 |
| focused-2 | 5/0/0 | 8.082 |
| bus whole | 793/0/0 | 22.463 |
| webui whole | 345/0/1 | 56.982 |
| scripts/test-auth.sh whole | 15/0/0 | 0.816 |
| scripts/test-conductor.sh whole | 17/0/0 | 6.078 |
| scripts/test-config.sh whole | 31/0/0 | 1.868 |
| scripts/test-discord.sh whole | 81/0/0 | 7.431 |
| scripts/test-extension-package.sh whole | 18/0/0 | 1.366 |
| scripts/test-foundation.sh whole | 44/0/0 | 39.901 |
| scripts/test-land-work.sh whole | 86/0/0 | 11.338 |
| scripts/test-queue.sh whole | 28/0/0 | 21.158 |
| scripts/test-release.sh whole | 14/0/0 | 2.67 |
| scripts/test-task.sh whole | 91/0/0 | 13.843 |
Syntax6/0. Both intended REDs repeat and restore byte-identical source and tracked status. Touched files whole: new HTTP4/0, new browser6/0, existing shell5/0. M1-M6 killed6/6, survivor0, timeout0, with passing bases and exact restores; run3/KILL-TABLE.md records named killers and times. Bus793/0, WebUI345/0/1, ten shell whole files425/0. Whole-phase reported assertions1563/0/1; this counts shell summary assertions, without adding nested TAP tests again. Focused repeats are listed separately. All direct test command JSONs use timeout -k10 300. Each whole shell command matches its pre-recorded limit exactly. No script changed.
Named skip: rebuilding from the source gives the same bytes, because esbuild0.28.1 is installed and0.28.2 is required. MOSAIC_REQUIRE_EDITOR_BUILD=1 would fail instead. No dependency install. The log line is saved in SUMMARY.json.
Sweep:0 run-created leftovers. The broad sweep found eight additional MCP/npm/code-mode processes plus the previously known browser helper; all predate the gate by over an hour. Their11:23:49-11:24:06Z start times are recorded with /proc ticks and UTC ps in run3/sweep.json and preexisting-processes.txt; initial broad output retained. Nothing signalled. Source and all ten script hashes still match their frozen values. No product/test bytes changed during the gate.
Seven-path manifest remains8fa859a0c617defe42e50028b057a603c6634f6db47ac2e3f7c01dfb290228a3. Records commit follows; publish own branch only under sage-2648, then hand directly to Webby and Sage. BUILD-LOG stays outside the landing manifest.
@@ -0,0 +1,9 @@
{
"packages/webui/src/cli.mjs": "7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a",
"packages/webui/src/serve.mjs": "aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d",
"packages/webui/src/public/bus.js": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"packages/webui/tests/thread-claims.test.mjs": "48117fe02ef9b76ad12f15dfb0d25e77d187c088c0bff572f33e18418e566913",
"packages/webui/tests/thread-claims-browser.test.mjs": "3b2770db03a2fcce87512b600f386a51f822b251ccb992a46208ee484ee99f7e",
"packages/webui/README.md": "426007525d15ad0fa11ba02d6cc5d8436c7ff3fa38beb01e9a651c202169d6a5",
"packages/webui/tests/shell.test.mjs": "fd7ad903b682f8f6ceee2d75111b01aa97f50233cd875dd5553e3e83de33ce32"
}
@@ -0,0 +1,273 @@
--- a/packages/webui/src/cli.mjs
+++ b/packages/webui/src/cli.mjs
@@ -86 +86,3 @@
- bus = { ...views({ call }), names: () => call('names'), instances: () => call('instances'), routes: () => call('routes') };
+ // Row 278: this owner/reader read belongs to the Console, not the shared
+ // role views or the tester adapter. The bus decides caller eligibility.
+ bus = { ...views({ call }), names: () => call('names'), instances: () => call('instances'), routes: () => call('routes'), 'thread.claims': () => call('thread.claims') };
--- a/packages/webui/src/serve.mjs
+++ b/packages/webui/src/serve.mjs
@@ -64 +64 @@
-const BUS_VERBS = ['inbox', 'tasks', 'agents', 'trail', 'decisions', 'credentials', 'replies', 'messages', 'usage', 'limits', 'names', 'instances', 'routes'];
+const BUS_VERBS = ['inbox', 'tasks', 'agents', 'thread.claims', 'trail', 'decisions', 'credentials', 'replies', 'messages', 'usage', 'limits', 'names', 'instances', 'routes'];
@@ -71,0 +72 @@
+ if (verb === 'thread.claims' && search) return json(res, 400, { error: 'invalid-request', message: 'thread.claims takes no arguments' });
@@ -737,0 +739,2 @@
+ // Owner/reader metadata is never a tester read, even with a supplied bus.
+ if (tester && verb === 'thread.claims') return json(res, 403, { error: 'tester-refused' });
--- a/packages/webui/src/public/bus.js
+++ b/packages/webui/src/public/bus.js
@@ -271,0 +272 @@
+ let configRead = Promise.resolve();
@@ -471,0 +473,18 @@
+ // Row 278: a claims refusal belongs to this section. Only sign-out reaches
+ // the global handler; a 403 here must not forget the successful role read.
+ async function threadClaimsSection(get) {
+ await configRead;
+ if (isTester) return '';
+ const title = '<h2 id="b-thread-claims">Thread claims</h2>';
+ try {
+ const claims = await get('thread.claims');
+ if (out()) { last.delete('thread.claims'); throw signedOut(); }
+ if (!claims.every(c => c && ['thread', 'holder_run', 'harness', 'at'].every(k => typeof c[k] === 'string'))) throw new ReadError('invalid-response', '');
+ const rows = claims.map(c => `<tr><th scope="row">${txt(c.thread)}</th><td>${txt(c.holder_run)}</td><td>${txt(c.harness)}</td><td>${when(c.at)}</td></tr>`).join('');
+ return `<section aria-labelledby="b-thread-claims">${title}${claims.length ? `<div class="table-wrap" tabindex="0" role="region" aria-label="Thread claims, scroll for all columns"><table class="s1-table s1-thread-claims"><thead><tr>${['Thread', 'Holder run', 'Harness', 'Claimed at'].map(h => `<th scope="col">${h}</th>`).join('')}</tr></thead><tbody>${rows}</tbody></table></div>` : empty('No thread claim is held right now.', 'A thread appears while a run holds its claim on the bus.')}</section>`;
+ } catch (err) {
+ if (err.code === 'signed-out') throw err;
+ last.delete('thread.claims');
+ return `<section aria-labelledby="b-thread-claims">${title}<div class="banner err" role="alert"><p>${why(err)}</p>${retry}</div></section>`;
+ }
+ }
@@ -473,0 +493 @@
+ const threadSection = await threadClaimsSection(get);
@@ -477,0 +498 @@
+ ${threadSection}
@@ -1296 +1317 @@
- fetch('/api/config', { cache: 'no-store', redirect: 'manual' }).then(r => { if (r.type === 'opaqueredirect') { signOut(); return null; } return r.json(); }).then(c => {
+ configRead = fetch('/api/config', { cache: 'no-store', redirect: 'manual' }).then(r => { if (r.type === 'opaqueredirect') { signOut(); return null; } return r.json(); }).then(c => {
--- /dev/null
+++ b/packages/webui/tests/thread-claims.test.mjs
@@ -0,0 +1,68 @@
+// Row 278 (#1783): Console-owned read adapter and the listener boundary.
+// All listeners and config are fixtures; no live bus or host configuration.
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { spawnSync } from 'node:child_process';
+import { readFileSync, writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { tmp, fixture } from '../../cli/tests/helpers.mjs';
+import { startServer } from '../src/serve.mjs';
+import { startTesterSocket } from '../src/tester-socket.mjs';
+import { testerRequest } from '../../cli/src/tester-http.mjs';
+import { BusReadError } from '../src/bus.mjs';
+import { close } from './fixture.mjs';
+
+const rows = [{ thread: '11111111-1111-4111-8111-111111111111', instance: 'assistant', holder_run: 'thread-run', harness: 'pi', at: '2026-01-01T00:00:00Z' }];
+
+test('row278 HTTP read returns held claims without send and refuses arguments before the bus', async t => {
+ const calls = [];
+ const bus = { 'thread.claims': async arg => { calls.push(arg); return rows; } };
+ const web = await startServer({ port: 0, board: 'http://127.0.0.1:9', bus });
+ t.after(() => close(web));
+ const url = `http://127.0.0.1:${web.address().port}/api/bus/thread.claims`;
+ const result = await fetch(url);
+ assert.equal(result.status, 200); assert.equal(result.headers.get('cache-control'), 'no-store');
+ const body = await result.json(); assert.deepEqual(body.rows, rows); assert.ok(body.at);
+ assert.deepEqual(calls, [undefined]);
+ for (const query of ['?thread=one', '?subject=one', '?limit=1', '?unknown=']) {
+ const r = await fetch(url + query); assert.equal(r.status, 400); assert.equal((await r.json()).error, 'invalid-request');
+ }
+ assert.equal((await fetch(url, { method: 'POST' })).status, 405);
+ assert.equal(calls.length, 1);
+});
+
+test('row278 HTTP read preserves bus refusal and rejects a malformed result', async t => {
+ let value = new BusReadError('human-required');
+ const web = await startServer({ port: 0, bus: { 'thread.claims': async () => { if (value instanceof Error) throw value; return value; } } });
+ t.after(() => close(web));
+ const url = `http://127.0.0.1:${web.address().port}/api/bus/thread.claims`;
+ let r = await fetch(url); assert.equal(r.status, 403); assert.equal((await r.json()).error, 'human-required');
+ value = {};
+ r = await fetch(url); assert.equal(r.status, 502); assert.equal((await r.json()).error, 'invalid-response');
+ value = [];
+ r = await fetch(url); assert.equal(r.status, 200); assert.deepEqual((await r.json()).rows, []);
+});
+
+test('row278 tester socket refuses thread claims explicitly with zero bus calls', async t => {
+ const dataRoot = tmp(t, 'claims-tester-'); let calls = 0;
+ const web = await startTesterSocket({ dataRoot, bus: { 'thread.claims': async () => { calls++; return rows; } } });
+ t.after(() => close(web));
+ const r = await testerRequest({ dataRoot, path: '/api/bus/thread.claims' });
+ assert.equal(r.status, 403); assert.equal(r.body.error, 'tester-refused'); assert.equal(calls, 0);
+});
+
+test('row278 Console adapter calls argument-free thread.claims through the normal transport', t => {
+ const root = tmp(t, 'claims-cli-'), f = fixture(root), log = join(root, 'calls.jsonl'), hook = join(root, 'hooks.mjs');
+ writeFileSync(log, '');
+ const serveSource = `export const DEFAULT_BOARD='http://127.0.0.1:9';export const previewOptions=()=>null;export const proofOptions=()=>null;export async function startServer(o){await o.bus['thread.claims']();return {address:()=>({port:0}),close:()=>{}};}`;
+ const busSource = `import {appendFileSync} from 'node:fs';export class BusReadError extends Error{};export const busCaller=o=>async(verb,...args)=>{appendFileSync(${JSON.stringify(log)},JSON.stringify({verb,args,tester:!!o.cli})+'\\n');return [];};`;
+ writeFileSync(hook, `import {registerHooks} from 'node:module';registerHooks({load(url,context,next){
+ if(url.endsWith('/webui/src/serve.mjs'))return {format:'module',shortCircuit:true,source:${JSON.stringify(serveSource)}};
+ if(url.endsWith('/webui/src/bus.mjs'))return {format:'module',shortCircuit:true,source:${JSON.stringify(busSource)}};
+ return next(url,context);
+ }});`);
+ const r = spawnSync(process.execPath, [new URL('../src/cli.mjs', import.meta.url).pathname, 'serve', '--business', 'acme', '--port', '0'],
+ { env: { ...f.env, NODE_OPTIONS: `--import=${hook}` }, encoding: 'utf8', timeout: 10000 });
+ assert.equal(r.status, 0, r.stdout + r.stderr);
+ assert.deepEqual(readFileSync(log, 'utf8').trim().split('\n').map(JSON.parse), [{ verb: 'thread.claims', args: [], tester: false }]);
+});
--- /dev/null
+++ b/packages/webui/tests/thread-claims-browser.test.mjs
@@ -0,0 +1,132 @@
+// Row 278: real Console rendering and HTTP with mutable bus-answer stand-ins.
+// Broker claim/release semantics are covered by row 277; this tests the reader.
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { startServer } from '../src/serve.mjs';
+import { BusReadError } from '../src/bus.mjs';
+import { fixture, close } from './fixture.mjs';
+import { browser } from './browser.mjs';
+import { startTesterSocket, TESTER_ORIGIN } from '../src/tester-socket.mjs';
+import { testerBrowser } from './tester-browser-fixture.mjs';
+import { tmp } from '../../cli/tests/helpers.mjs';
+
+const AT = '2026-01-01T00:00:00Z';
+const THREAD = '11111111-1111-4111-8111-111111111111';
+const claim = { thread: THREAD, holder_run: 'thread-run', harness: 'pi', at: AT };
+async function setup(t) {
+ const f = await fixture(); t.after(() => f.close());
+ const state = { rows: [], failure: null, offline: false, calls: [], hold: false, release: null };
+ t.after(() => { state.hold = false; state.release?.(); });
+ const role = { role: 'coder', holder_run: 'role-run', harness: 'pi', at: AT, state: 'idle', inputNeeded: [] };
+ const read = (verb, answer) => async () => {
+ state.calls.push(verb);
+ if (state.offline) throw new BusReadError('outcome-unknown');
+ if (verb === 'thread.claims' && state.failure) throw new BusReadError(state.failure);
+ if (verb === 'thread.claims' && state.hold) await new Promise(resolve => { state.release = resolve; });
+ return typeof answer === 'function' ? answer() : answer;
+ };
+ const bus = { agents: read('agents', [role]), inbox: read('inbox', []), messages: read('messages', { messages: [], unread: 0 }), 'thread.claims': read('thread.claims', () => state.rows) };
+ const web = await startServer({ port: 0, board: f.boardURL, bus }); t.after(() => close(web));
+ const b = await browser(); t.after(() => b.close());
+ const wait = expression => b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(${expression})return true;await new Promise(r=>setTimeout(r,30));}throw Error(${JSON.stringify(expression)})})()`);
+ await b.navigate(`http://127.0.0.1:${web.address().port}/#/agents`);
+ await wait(`!!document.querySelector('#b-thread-claims')`);
+ const roleHtml = () => b.evaluate(`document.querySelector('[aria-labelledby="b-claims"]').outerHTML`);
+ const refresh = () => b.evaluate(`document.querySelector('#refresh').click(),true`);
+ return { b, state, wait, roleHtml, refresh };
+}
+
+test('row278 browser lists held claims and release preserves role rows and totals', async t => {
+ const { b, state, wait, roleHtml, refresh } = await setup(t);
+ const before = await roleHtml();
+ assert.match(await b.evaluate(`document.querySelector('[aria-labelledby="b-thread-claims"]').textContent`), /No thread claim is held/);
+ state.rows = [claim]; await refresh();
+ await wait(`document.querySelector('.s1-thread-claims tbody')?.textContent.includes('${THREAD}')`);
+ assert.deepEqual(await b.evaluate(`Array.from(document.querySelectorAll('.s1-thread-claims thead th'),e=>e.textContent)`), ['Thread', 'Holder run', 'Harness', 'Claimed at']);
+ assert.equal(await b.evaluate(`document.querySelector('#b-claims .count').textContent`), '1');
+ assert.equal(await roleHtml(), before);
+ assert.equal(await b.evaluate(`document.querySelector('.s1-thread-claims time').dateTime`), AT);
+ state.rows = []; await refresh();
+ await wait(`document.querySelector('[aria-labelledby="b-thread-claims"]').textContent.includes('No thread claim is held')`);
+ assert.equal(await b.evaluate(`document.querySelectorAll('.s1-thread-claims tbody tr').length`), 0);
+ assert.equal(await roleHtml(), before);
+});
+
+test('row278 browser claims 403 stays local and role section remains byte-equal', async t => {
+ const { b, state, wait, roleHtml, refresh } = await setup(t);
+ const before = await roleHtml(); state.rows = [claim]; await refresh();
+ await wait(`!!document.querySelector('.s1-thread-claims tbody tr')`);
+ for (const code of ['human-required', 'not-configured', 'outcome-unknown']) {
+ state.failure = code; await refresh();
+ await wait(`document.querySelector('[aria-labelledby="b-thread-claims"] code')?.textContent===${JSON.stringify(code)}`);
+ assert.equal(await roleHtml(), before, code);
+ assert.equal(await b.evaluate(`document.querySelector('#b-claims .count').textContent`), '1');
+ assert.equal(await b.evaluate(`document.querySelectorAll('.s1-thread-claims tbody tr').length`), 0, 'failed read drops claims only');
+ }
+ state.offline = true; await refresh();
+ await wait(`!!document.querySelector('.s1-stale') && document.querySelector('[aria-labelledby="b-thread-claims"] code')?.textContent==='not-read'`);
+ assert.equal(await roleHtml(), before, 'other reads may use the kept role section');
+ assert.equal(await b.evaluate(`document.querySelectorAll('.s1-thread-claims tbody tr').length`), 0, 'a later stale repaint must not recover refused claims');
+});
+
+test('row278 browser renders only four escaped claim fields and never instance or other extras', async t => {
+ const { b, state, wait, refresh } = await setup(t);
+ const hostile = '<img src=x onerror="window.claimInjected=1">';
+ state.rows = [{ ...claim, thread: hostile, holder_run: '<script>window.claimInjected=2</script>', harness: '<b>pi</b>',
+ instance: 'NEVER_INSTANCE', name: 'NEVER_THREAD_NAME', body: 'NEVER_MESSAGE_BODY', address: 'NEVER_ADDRESS' }];
+ await refresh(); await wait(`document.querySelector('.s1-thread-claims tbody')?.textContent.includes('onerror')`);
+ const text = await b.evaluate(`document.querySelector('[aria-labelledby="b-thread-claims"]').textContent`);
+ assert.ok(text.includes(hostile)); assert.ok(text.includes('<script>window.claimInjected=2</script>')); assert.ok(text.includes('<b>pi</b>'));
+ assert.doesNotMatch(text, /NEVER_INSTANCE|NEVER_THREAD_NAME|NEVER_MESSAGE_BODY|NEVER_ADDRESS/);
+ assert.equal(await b.evaluate(`document.querySelectorAll('.s1-thread-claims tbody tr > *').length`), 4);
+ assert.equal(await b.evaluate(`document.querySelectorAll('.s1-thread-claims script,.s1-thread-claims img,.s1-thread-claims b').length`), 0);
+ assert.equal(await b.evaluate(`!!window.claimInjected`), false);
+});
+
+test('row278 browser sign-out removes claims and prevents reuse of cached answers', async t => {
+ const { b, state, wait, refresh } = await setup(t);
+ state.rows = [claim]; await refresh(); await wait(`!!document.querySelector('.s1-thread-claims tbody tr')`);
+ await b.evaluate(`window.claimFetch=fetch;window.fetch=(url,options)=>url==='/api/bus/thread.claims'?Promise.resolve(new Response(JSON.stringify({error:'sign-in required'}),{status:401})):window.claimFetch(url,options);true`);
+ await refresh();
+ await wait(`document.body.classList.contains('signed-out') && !document.querySelector('#b-thread-claims')`);
+ const calls = state.calls.length; await refresh(); assert.equal(state.calls.length, calls);
+ // Simulate returning to the route while the bus is unavailable. A cache that
+ // survived sign-out would repopulate the held thread from reader(false).
+ state.offline = true;
+ await b.evaluate(`window.fetch=window.claimFetch;document.body.classList.remove('signed-out');location.hash='#/agents?after-signout=1';true`);
+ await wait(`document.querySelector('#bus-view h1')?.textContent==='The read failed'`);
+ assert.doesNotMatch(await b.evaluate(`document.querySelector('#bus-view').textContent`), new RegExp(THREAD));
+});
+
+test('row278 tester browser keeps role rows without requesting the owner claims section', async t => {
+ const dataRoot = tmp(t, 'claims-view-'), calls = [], reads = [];
+ const web = await startTesterSocket({ dataRoot, board: 'http://127.0.0.1:9', bus: {
+ agents: async () => [{ role: 'coder', holder_run: 'role-run', harness: 'pi', at: AT }],
+ messages: async () => ({ messages: [], unread: 0 }),
+ 'thread.claims': async () => { calls.push('thread.claims'); return [claim]; },
+ } });
+ t.after(() => close(web));
+ const b = await testerBrowser(web); t.after(() => b.close());
+ b.on('Fetch.requestPaused', ({ request }) => { if (new URL(request.url).pathname === '/api/bus/thread.claims') reads.push(request.url); });
+ await b.navigate(TESTER_ORIGIN + '/#/agents');
+ await b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(document.querySelector('#tester-banner')&&document.querySelector('.s1-agents tbody tr'))return true;await new Promise(r=>setTimeout(r,30));}throw Error('tester Agents view did not render')})()`);
+ assert.equal(await b.evaluate(`document.querySelector('#b-claims .count').textContent`), '1');
+ assert.equal(await b.evaluate(`document.querySelector('#b-thread-claims')===null`), true);
+ assert.deepEqual(calls, []);
+ assert.deepEqual(reads, []);
+});
+
+test('row278 browser discards a late claims answer after sign-out', async t => {
+ const { b, state, wait, refresh } = await setup(t);
+ await b.evaluate(`window.claimFetch=fetch;window.fetch=async(url,options)=>{const r=await window.claimFetch(url,options);if(url==='/api/bus/thread.claims'){const json=r.json.bind(r);r.json=async()=>{const body=await json();window.lateClaimsFinished=true;return body;};}return r;};true`);
+ state.rows = [claim]; state.hold = true; await refresh();
+ for (let n = 0; !state.release && n < 100; n++) await new Promise(resolve => setTimeout(resolve, 10));
+ assert.equal(typeof state.release, 'function');
+ await b.evaluate(`document.dispatchEvent(new Event('mosaic-signed-out')),true`);
+ state.release(); state.hold = false;
+ await wait(`window.lateClaimsFinished && document.body.classList.contains('signed-out') && !document.querySelector('#b-thread-claims')`);
+ state.offline = true;
+ await b.evaluate(`window.fetch=window.claimFetch;document.body.classList.remove('signed-out');location.hash='#/agents?late-answer=1';true`);
+ await wait(`document.querySelector('#bus-view h1')?.textContent==='The read failed'`);
+ assert.doesNotMatch(await b.evaluate(`document.querySelector('#bus-view').textContent`), new RegExp(THREAD));
+});
--- a/packages/webui/README.md
+++ b/packages/webui/README.md
@@ -384,0 +385,9 @@
+The same view has a separate **Thread claims** section (row 278, #1783).
+It reads `thread.claims` and shows thread id, holder run, harness and claim time,
+in the bus's order. Thread names, messages, instance and address are not shown.
+An empty read has an empty-state line. A refused or failed read clears only
+this section's kept claims and shows its reason; the held roles and their
+count stay intact. Sign-out clears the claims with the other bus reads.
+The read needs no `--send`. The bus permits human and reader sessions;
+the tester listener refuses it with HTTP 403 `tester-refused` before any bus call.
+
--- a/packages/webui/tests/shell.test.mjs
+++ b/packages/webui/tests/shell.test.mjs
@@ -97 +97 @@
- const rows = { inbox: [], tasks: [], agents: [], trail: [] };
+ const rows = { inbox: [], tasks: [], agents: [], trail: [], 'thread.claims': [] };
@@ -101 +101 @@
- return { rows, hold, fail: code => { fail = code; }, bus: { inbox: verb('inbox'), tasks: verb('tasks'), agents: verb('agents'), trail: verb('trail') } };
+ return { rows, hold, fail: code => { fail = code; }, bus: { inbox: verb('inbox'), tasks: verb('tasks'), agents: verb('agents'), trail: verb('trail'), 'thread.claims': verb('thread.claims') } };
+11
View File
@@ -0,0 +1,11 @@
# Row278 committed candidate manifest, run3
Base6af85df4b, branch gander/row278-b. Runnable source commit 9696d1fcb78d6082cae8dcb61913225e98c9c138. Original runtime source remains e7d21b91b, unchanged. The assertion-preserving test repairs are964b6b184 (new adapter loader) and9696d1fcb (existing shell fixture, authorized mos-1274).
Seven manifest paths are pinned from committed blobs; shell.test.mjs is now included. Digest 8fa859a0c617defe42e50028b057a603c6634f6db47ac2e3f7c01dfb290228a3. SOURCE.json identifies the source reference. sha256sum -c verifies the working tree matches the source commit. CANDIDATE.patch matches the complete pending change from the base.
Run1 and run2 are void. Run3 must repeat syntax, both expected REDs, all three touched test files whole, M1-M6, bus and webui whole, and ten whole shell files. Direct Node test calls use timeout -k10 300. The whole shell-file calls use their SHELL-LIMITS.json value, derived and recorded in BUILD.md, with no script edit. No Node or test has run since the second stop. Sage grants the slot after Megavolt.
A further unexpected red, any moved existing assertion or a shell timeout goes to Sage and Mos unplaced, with no change/rerun. The editor rebuild environment skip (installed esbuild0.28.1 versus required0.28.2) stays named; no install. No push until green. BUILD-LOG is excluded from the landing manifest and lands as a doc-only append after code.
Run3 is now GREEN under sage-2648 on3e4c77ac6. run3/SUMMARY.json, raw command/log files and KILL-TABLE.md are the acceptance records. Bus793/0, WebUI345/0/1 (named esbuild version skip), ten shells425/0, touched whole files15/0, M1-M6 killed6/6, no timeout, sweep0 run-created leftovers. Source/test/script bytes match the pinned candidate. Run1/run2 remain void. Webby final manifest review is next after publication.
@@ -0,0 +1,7 @@
426007525d15ad0fa11ba02d6cc5d8436c7ff3fa38beb01e9a651c202169d6a5 packages/webui/README.md
7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a packages/webui/src/cli.mjs
c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0 packages/webui/src/public/bus.js
aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d packages/webui/src/serve.mjs
fd7ad903b682f8f6ceee2d75111b01aa97f50233cd875dd5553e3e83de33ce32 packages/webui/tests/shell.test.mjs
3b2770db03a2fcce87512b600f386a51f822b251ccb992a46208ee484ee99f7e packages/webui/tests/thread-claims-browser.test.mjs
48117fe02ef9b76ad12f15dfb0d25e77d187c088c0bff572f33e18418e566913 packages/webui/tests/thread-claims.test.mjs
@@ -0,0 +1,101 @@
{
"authority": [
"mos-1274",
"sage-2646"
],
"scope": "Longest durations in all available Gander row196 successful whole-file receipts at ec1e7fad8; run1/run2 of row278 ran no shells.",
"consulted_records": [
"ec1e7fad8:agents/gander/work/queue-196/evidence/suite-results-run1.json",
"ec1e7fad8:agents/gander/work/queue-196/evidence/suite-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r2/mutants/results.json",
"ec1e7fad8:agents/gander/work/queue-196/r2/run2/base-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r2/run2/killers/results.json",
"ec1e7fad8:agents/gander/work/queue-196/r3/gate/base-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r3/gate/killers/results.json",
"ec1e7fad8:agents/gander/work/queue-196/r3/gate/sso-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r4/gate/base-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r4/gate/killers/results.json",
"ec1e7fad8:agents/gander/work/queue-196/r4/gate/sso-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r4/gate/whole-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r5/gate/whole-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r5/resume/summary.json",
"ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r6/base-results.json",
"ec1e7fad8:agents/gander/work/queue-196/r6/first-attempt/results.json",
"ec1e7fad8:agents/gander/work/queue-196/r6/killers/results.json",
"ec1e7fad8:agents/gander/work/queue-196/r6/summary.json",
"ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json"
],
"scripts": {
"scripts/test-auth.sh": {
"recorded_duration_seconds": 1.9081228229999543,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json",
"limit_seconds": 126,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "dd4720cb0cbecd2fc523a318f2222d21d257c8c5889996a3d69e522ee971a707"
},
"scripts/test-conductor.sh": {
"recorded_duration_seconds": 8.057173820000026,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json",
"limit_seconds": 145,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "da84150467494a4c979759f400854411bd93a7efce981139757bf526d688a23b"
},
"scripts/test-config.sh": {
"recorded_duration_seconds": 3.1678915339999367,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r6/whole-results.json",
"limit_seconds": 130,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "3301c1fabf616bb961d62f6decd0a46dadb0f399b8ba7f3c2ca60023d2b24c78"
},
"scripts/test-discord.sh": {
"recorded_duration_seconds": 8.776727847000002,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 147,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "a5dcf783c51a5d5d184a357f91ebf9fa1c4e054f0cb84a3d1d7668f6156e025e"
},
"scripts/test-extension-package.sh": {
"recorded_duration_seconds": 3.01285702399991,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 130,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "5d7b687f16fd1a9414b229501177d530ba3af4eadd3cac319b33f38fdba9bf99"
},
"scripts/test-foundation.sh": {
"recorded_duration_seconds": 39.70872647900006,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 240,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "2e11038e7f784ec4f539eb768f63bab0fab9c9940334388a1fe2d47ab9e2b008"
},
"scripts/test-land-work.sh": {
"recorded_duration_seconds": 12.623263413000037,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 158,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "c9d1d5c9b006d5c12e5f796a9828361059f8e0410846fc55c070c0148b15cef4"
},
"scripts/test-queue.sh": {
"recorded_duration_seconds": 23.443742031000088,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 191,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "c270f181d1fa8b6d42ff4131c339beba786a8fd620bb66f8afdcec05e8b10868"
},
"scripts/test-release.sh": {
"recorded_duration_seconds": 12.168674453999964,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 157,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "be706dff832257bd4781abeabd19faa4ac16edf9a4af0c96457e33cf3bb6deb3"
},
"scripts/test-task.sh": {
"recorded_duration_seconds": 36.783798266,
"receipt": "ec1e7fad8:agents/gander/work/queue-196/r5/resume/whole-results.json",
"limit_seconds": 231,
"derivation": "ceil(3 * longest successful whole-file receipt) + 120s headroom",
"script_sha256": "10c4abb70bf9b83e617089b06a5436cc7fa6b866a176458b22128c3a15163f94"
}
}
}
+20
View File
@@ -0,0 +1,20 @@
{
"source_commit": "9696d1fcb78d6082cae8dcb61913225e98c9c138",
"runtime_commit": "e7d21b91b82c6cc1cec0a87995012a87b070b9bf",
"new_test_fix_commit": "964b6b1848d3bb5f2c15f9c835eb07783596ced9",
"legacy_fixture_fix_commit": "9696d1fcb78d6082cae8dcb61913225e98c9c138",
"branch": "gander/row278-b",
"base": "6af85df4b",
"manifest_sha256": "8fa859a0c617defe42e50028b057a603c6634f6db47ac2e3f7c01dfb290228a3",
"paths": {
"packages/webui/src/cli.mjs": "7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a",
"packages/webui/src/serve.mjs": "aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d",
"packages/webui/src/public/bus.js": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"packages/webui/tests/thread-claims.test.mjs": "48117fe02ef9b76ad12f15dfb0d25e77d187c088c0bff572f33e18418e566913",
"packages/webui/tests/thread-claims-browser.test.mjs": "3b2770db03a2fcce87512b600f386a51f822b251ccb992a46208ee484ee99f7e",
"packages/webui/README.md": "426007525d15ad0fa11ba02d6cc5d8436c7ff3fa38beb01e9a651c202169d6a5",
"packages/webui/tests/shell.test.mjs": "fd7ad903b682f8f6ceee2d75111b01aa97f50233cd875dd5553e3e83de33ce32"
},
"verification": "Run3 green under sage-2648; run3/SUMMARY.json contains fresh evidence. Runs1/2 void.",
"publication": "authorized after green under sage-2648"
}
@@ -0,0 +1,56 @@
[
{
"id": "M1",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "e1b693b5ddf3cd55091dd4c0a47934ca22fe7851c6e942f2386a6eefdcb5a1a0",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser lists held claims"
},
{
"id": "M2",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "6a7274e2d2281ac2d927a00e6cabe72656f648f721607f0896cac107a4e22fdb",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser lists held claims"
},
{
"id": "M3",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "7c30c0cfa6908bc0946df325d417f726ea67373b8afffe72fd3aebcd6a52c52b",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser claims 403 stays local"
},
{
"id": "M4",
"file": "packages/webui/src/serve.mjs",
"occurrences": 1,
"before": "aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d",
"after": "10324c3a22dbefac6286af4f06e53a6e8057aef56f744eaf7bdd879ac76626e1",
"killer": "packages/webui/tests/thread-claims.test.mjs",
"pattern": "row278 tester socket refuses thread claims"
},
{
"id": "M5",
"file": "packages/webui/src/cli.mjs",
"occurrences": 1,
"before": "7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a",
"after": "3fa30f91b19a1ea0348214b927925b163e51a6184b97910ded2dbc2282e1ddf6",
"killer": "packages/webui/tests/thread-claims.test.mjs",
"pattern": "row278 Console adapter calls argument-free"
},
{
"id": "M6",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "c1c4f97a962d8da9055373ca7ac4441712c2c9f4ea675d7b137a3306d0621012",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser claims 403 stays local"
}
]
+50
View File
@@ -0,0 +1,50 @@
[
{
"id": "M1",
"file": "packages/webui/src/public/bus.js",
"old": " async function threadClaimsSection(get) {",
"new": " async function threadClaimsSection(get) {\n return \"\";",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser lists held claims"
},
{
"id": "M2",
"file": "packages/webui/src/public/bus.js",
"old": " const threadSection = await threadClaimsSection(get);",
"new": " const threadSection = await threadClaimsSection(get);\n claims.push(...(last.get('thread.claims')?.rows ?? []));",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser lists held claims"
},
{
"id": "M3",
"file": "packages/webui/src/public/bus.js",
"old": " if (err.code === 'signed-out') throw err;\n last.delete('thread.claims');",
"new": " if (err.code === 'signed-out' || err.status === 403) throw err;\n last.delete('thread.claims');",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser claims 403 stays local"
},
{
"id": "M4",
"file": "packages/webui/src/serve.mjs",
"old": " if (tester && verb === 'thread.claims') return json(res, 403, { error: 'tester-refused' });",
"new": " // tester guard removed",
"killer": "packages/webui/tests/thread-claims.test.mjs",
"pattern": "row278 tester socket refuses thread claims"
},
{
"id": "M5",
"file": "packages/webui/src/cli.mjs",
"old": "'thread.claims': () => call('thread.claims')",
"new": "'thread.claims': () => call('agents')",
"killer": "packages/webui/tests/thread-claims.test.mjs",
"pattern": "row278 Console adapter calls argument-free"
},
{
"id": "M6",
"file": "packages/webui/src/public/bus.js",
"old": " last.delete('thread.claims');\n return `<section aria-labelledby=\"b-thread-claims\">",
"new": " // keep the old claims\n return `<section aria-labelledby=\"b-thread-claims\">",
"killer": "packages/webui/tests/thread-claims-browser.test.mjs",
"pattern": "row278 browser claims 403 stays local"
}
]
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env python3
"""Run explicit row278 changes only under Sage's grant. --static runs no tests."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import signal
import subprocess
import time
HERE = Path(__file__).resolve().parent
REPO = HERE.parents[3]
def digest(data):
return hashlib.sha256(data).hexdigest()
def busy():
p = subprocess.run(['bash', '/mnt/storage/scratch/sage-busy-now.sh'], text=True, capture_output=True)
if p.returncode or p.stdout.splitlines()[-1:] != ['CLEAR']:
raise RuntimeError('busy refusal: ' + p.stdout + p.stderr)
def run(command, path, seconds=330):
busy()
if command[:2] == ['node', '--test']:
command = ['timeout', '-k', '10', '300', *command]
started = time.monotonic()
command_file = path.with_suffix('.command.json')
command_file.write_text(json.dumps(command))
# Keep command text out of wrapper argv: the busy guard scans every argv.
# launch.py execs the structured command. bash owns a pipefail/tee pipeline.
p = subprocess.Popen(['bash','-o','pipefail','-c',
'python3 "$1" "$2" 2>&1 | tee "$3"', '--',str(HERE/'launch.py'),str(command_file),str(path)],
cwd=REPO,start_new_session=True)
expired = False
try:
code = p.wait(timeout=seconds)
expired = code in (124, 137)
except subprocess.TimeoutExpired:
expired = True
os.killpg(p.pid, signal.SIGKILL)
code = p.wait()
finally:
try:
os.killpg(p.pid, signal.SIGKILL)
except ProcessLookupError:
pass
return dict(code=code, timeout=expired, seconds=round(time.monotonic()-started, 3), log=str(path))
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--static', action='store_true')
ap.add_argument('--grant')
ap.add_argument('--out', type=Path)
args = ap.parse_args()
expected = json.loads((HERE/'CANDIDATE-SHAS.json').read_text())
for name, sha in expected.items():
assert digest((REPO/name).read_bytes()) == sha, name
definitions = json.loads((HERE/'changes.json').read_text())
checked = []
for d in definitions:
original = (REPO/d['file']).read_bytes()
count = original.count(d['old'].encode())
if count != 1:
raise RuntimeError(f"{d['id']}: target occurs {count} times")
changed = original.replace(d['old'].encode(), d['new'].encode(), 1)
checked.append(dict(id=d['id'], file=d['file'], occurrences=count,
before=digest(original), after=digest(changed)))
if args.static:
print(json.dumps(checked, indent=2))
return
if not args.grant or not args.out:
ap.error('execution needs --grant and --out')
if not os.environ.get('TMPDIR', '').startswith('/mnt/storage/scratch/tmp/g'):
raise RuntimeError('TMPDIR must be the granted scratch directory')
status = subprocess.check_output(['git','status','--porcelain','--untracked-files=no'],cwd=REPO)
args.out.mkdir(parents=True, exist_ok=True)
results = dict(grant=args.grant, static=checked, bases={}, changes=[])
failures = 0
for d in definitions:
key = d['killer']+'|'+d['pattern']
command = ['node','--test','--test-reporter=tap','--test-name-pattern',d['pattern'],d['killer']]
if key not in results['bases']:
base = run(command, args.out/(d['id']+'-base.log'))
results['bases'][key] = base
(args.out/'results.json').write_text(json.dumps(results,indent=2)+'\n')
if base['code'] != 0 or base['seconds'] > 30:
raise RuntimeError('base failed or exceeded 30 seconds: '+d['id'])
target = REPO/d['file']
original = target.read_bytes()
try:
target.write_bytes(original.replace(d['old'].encode(),d['new'].encode(),1))
busy()
pre = subprocess.run(['node','--check',str(target)],capture_output=True)
if pre.returncode:
raise RuntimeError('invalid syntax: '+d['id'])
result = run(command,args.out/(d['id']+'.log'))
result.update(id=d['id'], base_seconds=results['bases'][key]['seconds'],
outcome='timeout' if result['timeout'] else 'killed' if result['code'] != 0 else 'survived')
results['changes'].append(result)
if result['timeout']:
raise RuntimeError('timeout requires Sage/Mos classification: '+d['id'])
if result['outcome'] != 'killed':
failures += 1
finally:
target.write_bytes(original)
assert target.read_bytes() == original
assert subprocess.check_output(['git','status','--porcelain','--untracked-files=no'],cwd=REPO) == status
(args.out/'results.json').write_text(json.dumps(results,indent=2)+'\n')
if failures >= 1:
raise RuntimeError('first unexpected failure: end the granted window')
print(json.dumps(results,indent=2))
if __name__ == '__main__':
main()
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env python3
"""Exec a structured command without putting its text in wrapper argv."""
import json
import os
import sys
with open(sys.argv[1]) as source:
command = json.load(source)
os.execvp(command[0], command)
@@ -0,0 +1,7 @@
packages/webui/README.md: OK
packages/webui/src/cli.mjs: OK
packages/webui/src/public/bus.js: OK
packages/webui/src/serve.mjs: OK
packages/webui/tests/shell.test.mjs: OK
packages/webui/tests/thread-claims-browser.test.mjs: OK
packages/webui/tests/thread-claims.test.mjs: OK
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Assemble run3 evidence from complete logs without running tests."""
import hashlib, json, re
from pathlib import Path
HERE=Path(__file__).resolve().parent
RUN=HERE/'run3'
def main():
sections={n:json.loads((RUN/n/'results.json').read_text()) for n in ['syntax','red','focused','changes','whole']}
for n in ['syntax','focused','whole']:
assert all(s['code']==0 and not s['timeout'] for s in sections[n]['steps']), n
assert len(sections['whole']['steps'])==12
assert all(s['code']!=0 and not s['timeout'] for s in sections['red']['steps'])
changes=sections['changes']['changes']
assert len(changes)==6 and all(s['outcome']=='killed' and not s['timeout'] for s in changes)
limits=json.loads((HERE/'SHELL-LIMITS.json').read_text())['scripts']
shells=[]
for s in sections['whole']['steps'][2:]:
command=json.loads(Path(s['log']).with_suffix('.command.json').read_text())
script=command[-1]
assert command==['timeout','-k','10',str(limits[script]['limit_seconds']),'bash',script]
raw=Path(s['log']).read_text(errors='replace')
matches=re.findall(r'([^\n]*?: (\d+) passed, (\d+) failed)',raw)
assert matches, script
line, passed, failed=matches[-1]
assert int(failed)==0
shells.append(dict(script=script,pass_count=int(passed),fail_count=int(failed),seconds=s['seconds'],limit_seconds=limits[script]['limit_seconds'],summary_line=line,command=command))
webui=Path(sections['whole']['steps'][1]['log']).read_text(errors='replace')
skips=[line for line in webui.splitlines() if '# SKIP' in line]
direct=[]
for p in RUN.rglob('*.command.json'):
cmd=json.loads(p.read_text())
if 'node' in cmd and '--test' in cmd:
assert cmd[:5]==['timeout','-k','10','300','node']
direct.append(str(p))
expected=json.loads((HERE/'CANDIDATE-SHAS.json').read_text())
repo=HERE.parents[3]
assert all(hashlib.sha256((repo/n).read_bytes()).hexdigest()==v for n,v in expected.items())
assert all(hashlib.sha256((repo/n).read_bytes()).hexdigest()==v['script_sha256'] for n,v in limits.items())
result=dict(status='GREEN',grant='sage-2648',candidate='3e4c77ac6056e8efa887eecdbc4001d249b880f6',source='9696d1fcb78d6082cae8dcb61913225e98c9c138',manifest=hashlib.sha256((HERE/'MANIFEST.sha256').read_bytes()).hexdigest(),sections=sections,shells=shells,named_skips=skips,killed=len(changes),survived=0,timeouts=0,timeout_wrapped_direct_test_commands=direct,all_candidate_and_script_hashes_match=True)
(RUN/'SUMMARY.json').write_text(json.dumps(result,indent=2)+'\n')
defs={d['id']:d for d in json.loads((HERE/'changes.json').read_text())}
lines=['# Run3 kill table','','All six bases passed; no timeout. Every change restored exact bytes and tracked git status.','','| Check | Named killer | Base seconds | Changed seconds | Result |','|---|---|---:|---:|---|']
lines += [f"| {s['id']} | {defs[s['id']]['pattern']} | {s['base_seconds']} | {s['seconds']} | {s['outcome']} |" for s in changes]
(RUN/'KILL-TABLE.md').write_text('\n'.join(lines)+'\n')
print(json.dumps(dict(shells=shells,named_skips=skips,killed=len(changes)),indent=2))
if __name__=='__main__': main()
@@ -0,0 +1,138 @@
{
"grant": "sage-2632",
"candidate": "0011fe357",
"source": "e7d21b91b",
"status": "VOID_UNDER_SAGE_2638",
"queue_rev": 3195,
"syntax": {
"grant": "sage-2632",
"stage": "syntax",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-0.log",
"name": "syntax-0",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-1.log",
"name": "syntax-1",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-2.log",
"name": "syntax-2",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-3.log",
"name": "syntax-3",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-4.log",
"name": "syntax-4",
"expected_red": false,
"counts": {}
}
]
},
"red": {
"grant": "sage-2632",
"stage": "red",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.265,
"log": "agents/gander/work/queue-278/run1/red/red-0.log",
"name": "red-0",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 3.922,
"log": "agents/gander/work/queue-278/run1/red/red-1.log",
"name": "red-1",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
}
]
},
"focused": {
"grant": "sage-2632",
"stage": "focused",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.315,
"log": "agents/gander/work/queue-278/run1/focused/focused-0.log",
"name": "focused-0",
"expected_red": false,
"counts": {
"tests": 4,
"pass": 3,
"fail": 1,
"skipped": 0
}
}
]
},
"unrun": [
"thread-claims-browser whole",
"M1-M6",
"bus whole",
"webui whole",
"ten shell files"
],
"sweep": {
"timestamp": "2026-10-22T12:07:11.740057+00:00",
"raw_matches": 1,
"count": 0,
"excluded_preexisting_infrastructure": [
{
"pid": 2880439,
"comm": "chrome-devtools",
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196",
"args": "chrome-devtools-mcp ",
"start_receipt": " PID STARTED ELAPSED COMMAND\n2880439 Thu Oct 22 06:23:50 2026 43:20 chrome-devtools\n"
}
],
"remaining": [],
"note": "The only raw match is the pre-existing chrome-devtools-mcp harness helper, started before this grant. No node, tee, timeout, browser test process or FIFO reader from this run remains. No process was signalled."
},
"diagnosis": "New adapter test replaces webui bus.mjs without exporting BusReadError required by chat.mjs. Proposed test-only fix: export a stand-in BusReadError alongside busCaller; assertions unchanged. No fix or rerun made.",
"results_carry": false,
"test_fix_commit": "964b6b1848d3bb5f2c15f9c835eb07783596ced9"
}
@@ -0,0 +1 @@
ok gander-278-start rev 3195 row 278 briefed→in-progress
@@ -0,0 +1,77 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 32.1613
type: 'test'
...
# Subtest: row278 HTTP read preserves bus refusal and rejects a malformed result
ok 2 - row278 HTTP read preserves bus refusal and rejects a malformed result
---
duration_ms: 8.353095
type: 'test'
...
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
ok 3 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 4.686299
type: 'test'
...
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
not ok 4 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 99.361185
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:54:1'
failureType: 'testCodeFailure'
error: |-
file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/src/chat.mjs:7
import { BusReadError } from './bus.mjs';
^^^^^^^^^^^^
SyntaxError: The requested module './bus.mjs' does not provide an export named 'BusReadError'
at #asyncInstantiate (node:internal/modules/esm/module_job:463:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:561:5)
at async node:internal/modules/esm/loader:650:26
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
Node.js v26.8.1
1 !== 0
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 0
actual: 1
operator: 'strictEqual'
stack: |-
#asyncInstantiate (node:internal/modules/esm/module_job:463:21)
async ModuleJob.run (node:internal/modules/esm/module_job:561:5)
async node:internal/modules/esm/loader:650:26
async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:66:10)
Test.runInAsyncScope (node:async_hooks:226:14)
Test.run (node:internal/test_runner/test:1402:25)
Test.processPendingSubtests (node:internal/test_runner/test:974:18)
Test.postRun (node:internal/test_runner/test:1542:19)
Test.run (node:internal/test_runner/test:1467:12)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
...
1..4
# tests 4
# suites 0
# pass 3
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 267.798271
Traceback (most recent call last):
File "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/agents/gander/work/queue-278/window.py", line 83, in <module>
main()
File "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/agents/gander/work/queue-278/window.py", line 72, in main
step('focused-'+str(index), ['node', '--test', '--test-reporter=tap', name])
File "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/agents/gander/work/queue-278/window.py", line 50, in step
raise RuntimeError('unexpected failure: stop and report')
RuntimeError: unexpected failure: stop and report
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,69 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 32.1613
type: 'test'
...
# Subtest: row278 HTTP read preserves bus refusal and rejects a malformed result
ok 2 - row278 HTTP read preserves bus refusal and rejects a malformed result
---
duration_ms: 8.353095
type: 'test'
...
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
ok 3 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 4.686299
type: 'test'
...
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
not ok 4 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 99.361185
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:54:1'
failureType: 'testCodeFailure'
error: |-
file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/src/chat.mjs:7
import { BusReadError } from './bus.mjs';
^^^^^^^^^^^^
SyntaxError: The requested module './bus.mjs' does not provide an export named 'BusReadError'
at #asyncInstantiate (node:internal/modules/esm/module_job:463:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:561:5)
at async node:internal/modules/esm/loader:650:26
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
Node.js v26.8.1
1 !== 0
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 0
actual: 1
operator: 'strictEqual'
stack: |-
#asyncInstantiate (node:internal/modules/esm/module_job:463:21)
async ModuleJob.run (node:internal/modules/esm/module_job:561:5)
async node:internal/modules/esm/loader:650:26
async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:66:10)
Test.runInAsyncScope (node:async_hooks:226:14)
Test.run (node:internal/test_runner/test:1402:25)
Test.processPendingSubtests (node:internal/test_runner/test:974:18)
Test.postRun (node:internal/test_runner/test:1542:19)
Test.run (node:internal/test_runner/test:1467:12)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
...
1..4
# tests 4
# suites 0
# pass 3
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 267.798271
@@ -0,0 +1,20 @@
{
"grant": "sage-2632",
"stage": "focused",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.315,
"log": "agents/gander/work/queue-278/run1/focused/focused-0.log",
"name": "focused-0",
"expected_red": false,
"counts": {
"tests": 4,
"pass": 3,
"fail": 1,
"skipped": 0
}
}
]
}
@@ -0,0 +1,94 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
not ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 19.9422
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:17:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
404 !== 200
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 200
actual: 404
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:24:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 168.23002
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 3702.361642
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: "Uncaught (in promise) Error: !!document.querySelector('#b-thread-claims'): undefined"
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async setup (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:33:3)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:40:49)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3825.651636
{
"grant": "sage-2632",
"stage": "red",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.265,
"log": "agents/gander/work/queue-278/run1/red/red-0.log",
"name": "red-0",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 3.922,
"log": "agents/gander/work/queue-278/run1/red/red-1.log",
"name": "red-1",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
}
]
}
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 HTTP read returns held claims", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,33 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
not ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 19.9422
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:17:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
404 !== 200
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 200
actual: 404
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:24:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 168.23002
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser lists held claims", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,27 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 3702.361642
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: "Uncaught (in promise) Error: !!document.querySelector('#b-thread-claims'): undefined"
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async setup (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:33:3)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:40:49)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3825.651636
@@ -0,0 +1,34 @@
{
"grant": "sage-2632",
"stage": "red",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.265,
"log": "agents/gander/work/queue-278/run1/red/red-0.log",
"name": "red-0",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 3.922,
"log": "agents/gander/work/queue-278/run1/red/red-1.log",
"name": "red-1",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
}
]
}
@@ -0,0 +1 @@
2026-10-22T12:04:14Z
@@ -0,0 +1,14 @@
{
"timestamp": "2026-10-22T12:06:39.845905+00:00",
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196",
"count": 1,
"processes": [
{
"pid": 2880439,
"comm": "chrome-devtools",
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196",
"args": "chrome-devtools-mcp "
}
],
"method": "read-only proc cwd sweep; own ancestry excluded; node, tee, timeout, Chromium and FIFO commands; no signalling"
}
@@ -0,0 +1,16 @@
{
"timestamp": "2026-10-22T12:07:11.740057+00:00",
"raw_matches": 1,
"count": 0,
"excluded_preexisting_infrastructure": [
{
"pid": 2880439,
"comm": "chrome-devtools",
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196",
"args": "chrome-devtools-mcp ",
"start_receipt": " PID STARTED ELAPSED COMMAND\n2880439 Thu Oct 22 06:23:50 2026 43:20 chrome-devtools\n"
}
],
"remaining": [],
"note": "The only raw match is the pre-existing chrome-devtools-mcp harness helper, started before this grant. No node, tee, timeout, browser test process or FIFO reader from this run remains. No process was signalled."
}
@@ -0,0 +1,51 @@
{
"grant": "sage-2632",
"stage": "syntax",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-0.log",
"name": "syntax-0",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-1.log",
"name": "syntax-1",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-2.log",
"name": "syntax-2",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-3.log",
"name": "syntax-3",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-4.log",
"name": "syntax-4",
"expected_red": false,
"counts": {}
}
]
}
@@ -0,0 +1,51 @@
{
"grant": "sage-2632",
"stage": "syntax",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-0.log",
"name": "syntax-0",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-1.log",
"name": "syntax-1",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-2.log",
"name": "syntax-2",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-3.log",
"name": "syntax-3",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run1/syntax/syntax-4.log",
"name": "syntax-4",
"expected_red": false,
"counts": {}
}
]
}
@@ -0,0 +1 @@
["node", "--check", "packages/webui/src/cli.mjs"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/src/serve.mjs"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/src/public/bus.js"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1 @@
/mnt/storage/scratch/tmp/gJZKyzz
@@ -0,0 +1,10 @@
# Run2 proposed-check table, void under sage-2644
| Check | Outcome | Base seconds | Changed seconds | Timeout |
|---|---|---:|---:|---|
| M1 | killed | 0.715 | 3.774 | False |
| M2 | killed | 0.715 | 0.816 | False |
| M3 | killed | 0.916 | 3.773 | False |
| M4 | killed | 0.214 | 0.214 | False |
| M5 | killed | 0.314 | 0.315 | False |
| M6 | killed | 0.916 | 3.873 | False |
@@ -0,0 +1,342 @@
{
"status": "VOID_UNDER_SAGE_2644",
"results_carry": false,
"grant": "sage-2638",
"candidate": "42abda031f419bc51fe09a784081afaa9d04d8a3",
"source": "964b6b1848d3bb5f2c15f9c835eb07783596ced9",
"manifest": "188071d851e1f68297a7160a2bd557d9ca1b2776897ea2dd3b2c910ffd1c1f4a",
"sections": {
"syntax": {
"grant": "sage-2638",
"stage": "syntax",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-0.log",
"name": "syntax-0",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-1.log",
"name": "syntax-1",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-2.log",
"name": "syntax-2",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-3.log",
"name": "syntax-3",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-4.log",
"name": "syntax-4",
"expected_red": false,
"counts": {}
}
]
},
"red": {
"grant": "sage-2638",
"stage": "red",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/red/red-0.log",
"name": "red-0",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 3.772,
"log": "agents/gander/work/queue-278/run2/red/red-1.log",
"name": "red-1",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
}
]
},
"focused": {
"grant": "sage-2638",
"stage": "focused",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.365,
"log": "agents/gander/work/queue-278/run2/focused/focused-0.log",
"name": "focused-0",
"expected_red": false,
"counts": {
"tests": 4,
"pass": 4,
"fail": 0,
"skipped": 0
}
},
{
"code": 0,
"timeout": false,
"seconds": 4.023,
"log": "agents/gander/work/queue-278/run2/focused/focused-1.log",
"name": "focused-1",
"expected_red": false,
"counts": {
"tests": 6,
"pass": 6,
"fail": 0,
"skipped": 0
}
}
]
},
"changes": {
"grant": "sage-2638",
"static": [
{
"id": "M1",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "e1b693b5ddf3cd55091dd4c0a47934ca22fe7851c6e942f2386a6eefdcb5a1a0"
},
{
"id": "M2",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "6a7274e2d2281ac2d927a00e6cabe72656f648f721607f0896cac107a4e22fdb"
},
{
"id": "M3",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "7c30c0cfa6908bc0946df325d417f726ea67373b8afffe72fd3aebcd6a52c52b"
},
{
"id": "M4",
"file": "packages/webui/src/serve.mjs",
"occurrences": 1,
"before": "aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d",
"after": "10324c3a22dbefac6286af4f06e53a6e8057aef56f744eaf7bdd879ac76626e1"
},
{
"id": "M5",
"file": "packages/webui/src/cli.mjs",
"occurrences": 1,
"before": "7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a",
"after": "3fa30f91b19a1ea0348214b927925b163e51a6184b97910ded2dbc2282e1ddf6"
},
{
"id": "M6",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "c1c4f97a962d8da9055373ca7ac4441712c2c9f4ea675d7b137a3306d0621012"
}
],
"bases": {
"packages/webui/tests/thread-claims-browser.test.mjs|row278 browser lists held claims": {
"code": 0,
"timeout": false,
"seconds": 0.715,
"log": "agents/gander/work/queue-278/run2/changes/M1-base.log"
},
"packages/webui/tests/thread-claims-browser.test.mjs|row278 browser claims 403 stays local": {
"code": 0,
"timeout": false,
"seconds": 0.916,
"log": "agents/gander/work/queue-278/run2/changes/M3-base.log"
},
"packages/webui/tests/thread-claims.test.mjs|row278 tester socket refuses thread claims": {
"code": 0,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/changes/M4-base.log"
},
"packages/webui/tests/thread-claims.test.mjs|row278 Console adapter calls argument-free": {
"code": 0,
"timeout": false,
"seconds": 0.314,
"log": "agents/gander/work/queue-278/run2/changes/M5-base.log"
}
},
"changes": [
{
"code": 1,
"timeout": false,
"seconds": 3.774,
"log": "agents/gander/work/queue-278/run2/changes/M1.log",
"id": "M1",
"base_seconds": 0.715,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.816,
"log": "agents/gander/work/queue-278/run2/changes/M2.log",
"id": "M2",
"base_seconds": 0.715,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 3.773,
"log": "agents/gander/work/queue-278/run2/changes/M3.log",
"id": "M3",
"base_seconds": 0.916,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/changes/M4.log",
"id": "M4",
"base_seconds": 0.214,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.315,
"log": "agents/gander/work/queue-278/run2/changes/M5.log",
"id": "M5",
"base_seconds": 0.314,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 3.873,
"log": "agents/gander/work/queue-278/run2/changes/M6.log",
"id": "M6",
"base_seconds": 0.916,
"outcome": "killed"
}
]
},
"whole": {
"grant": "sage-2638",
"stage": "whole",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 23.116,
"log": "agents/gander/work/queue-278/run2/whole/bus.log",
"name": "bus",
"expected_red": false,
"counts": {
"tests": 793,
"pass": 793,
"fail": 0,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 55.324,
"log": "agents/gander/work/queue-278/run2/whole/webui.log",
"name": "webui",
"expected_red": false,
"counts": {
"tests": 346,
"pass": 344,
"fail": 1,
"skipped": 1
}
}
]
}
},
"killed": 6,
"survived": 0,
"timeouts": 0,
"failure": {
"file": "packages/webui/tests/shell.test.mjs",
"test": "five states on Board, Inbox, Tasks, Agents and Trail",
"assertion_line": 463,
"expected_banner_count": 0,
"actual_banner_count": 1,
"static_diagnosis": "stubBus supplies no thread.claims callback, so the section correctly shows an invalid-response banner",
"ruling": "Mos pending; no source, test, fixture or driver change made after the stop"
},
"named_skips": [
{
"tap_line": "ok 98 - rebuilding from the source gives the same bytes (needs the pinned esbuild; MOSAIC_REQUIRE_EDITOR_BUILD=1 makes its absence a failure) # SKIP esbuild 0.28.1 is installed at /mnt/storage/src/mosaic-stack/node_modules/esbuild; the editor rebuild needs exactly 0.28.2 (npm ci --ignore-scripts in packages/webui) (set MOSAIC_REQUIRE_EDITOR_BUILD=1 to fail instead of skip)"
}
],
"unrun": [
"all ten shell files"
],
"sweep": {
"timestamp": "2026-10-22T12:17:12.732808+00:00",
"count": 0,
"remaining": [],
"excluded_preexisting_infrastructure": [
{
"pid": 2880439,
"comm": "chrome-devtools"
}
],
"note": "Read-only cwd proc sweep, own ancestry excluded. No signalling. Slot already returned in gander-0094."
},
"timeout_wrapped_direct_test_commands": [
"agents/gander/work/queue-278/run2/focused/focused-0.command.json",
"agents/gander/work/queue-278/run2/focused/focused-1.command.json",
"agents/gander/work/queue-278/run2/changes/M1-base.command.json",
"agents/gander/work/queue-278/run2/changes/M4-base.command.json",
"agents/gander/work/queue-278/run2/changes/M1.command.json",
"agents/gander/work/queue-278/run2/changes/M4.command.json",
"agents/gander/work/queue-278/run2/changes/M6.command.json",
"agents/gander/work/queue-278/run2/changes/M2.command.json",
"agents/gander/work/queue-278/run2/changes/M3-base.command.json",
"agents/gander/work/queue-278/run2/changes/M3.command.json",
"agents/gander/work/queue-278/run2/changes/M5-base.command.json",
"agents/gander/work/queue-278/run2/changes/M5.command.json",
"agents/gander/work/queue-278/run2/whole/bus.command.json",
"agents/gander/work/queue-278/run2/whole/webui.command.json",
"agents/gander/work/queue-278/run2/red/red-1.command.json",
"agents/gander/work/queue-278/run2/red/red-0.command.json"
]
}
@@ -0,0 +1,388 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 535.499612
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 651.310935
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 3566.368806
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: "Uncaught (in promise) Error: !!document.querySelector('#b-thread-claims'): undefined"
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async setup (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:33:3)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:40:49)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3677.584834
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 598.604567
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
'2' !== '1'
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: '1'
actual: '2'
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:46:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 716.536553
TAP version 13
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
ok 1 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 715.095255
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 831.950838
TAP version 13
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
not ok 1 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 3591.462679
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:55:1'
failureType: 'testCodeFailure'
error: `Uncaught (in promise) Error: document.querySelector('[aria-labelledby="b-thread-claims"] code')?.textContent==="human-required": undefined`
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:61:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3706.82009
TAP version 13
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
ok 1 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 14.65787
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 133.295747
TAP version 13
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
not ok 1 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 14.509095
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:46:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
200 !== 403
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 403
actual: 200
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:51:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 125.024128
TAP version 13
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
ok 1 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 117.719722
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 229.873766
TAP version 13
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
not ok 1 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 116.367834
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:54:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly deep-equal:
+ actual - expected
[
{
args: [],
tester: false,
+ verb: 'agents'
- verb: 'thread.claims'
}
]
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected:
0:
verb: 'thread.claims'
args:
tester: false
actual:
0:
verb: 'agents'
args:
tester: false
operator: 'deepStrictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:67:10)
Test.runInAsyncScope (node:async_hooks:226:14)
Test.run (node:internal/test_runner/test:1402:25)
Test.start (node:internal/test_runner/test:1262:17)
startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 230.973133
TAP version 13
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
not ok 1 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 3697.026047
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:55:1'
failureType: 'testCodeFailure'
error: `Uncaught (in promise) Error: !!document.querySelector('.s1-stale') && document.querySelector('[aria-labelledby="b-thread-claims"] code')?.textContent==='not-read': undefined`
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:67:3)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3817.114582
{
"grant": "sage-2638",
"static": [
{
"id": "M1",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "e1b693b5ddf3cd55091dd4c0a47934ca22fe7851c6e942f2386a6eefdcb5a1a0"
},
{
"id": "M2",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "6a7274e2d2281ac2d927a00e6cabe72656f648f721607f0896cac107a4e22fdb"
},
{
"id": "M3",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "7c30c0cfa6908bc0946df325d417f726ea67373b8afffe72fd3aebcd6a52c52b"
},
{
"id": "M4",
"file": "packages/webui/src/serve.mjs",
"occurrences": 1,
"before": "aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d",
"after": "10324c3a22dbefac6286af4f06e53a6e8057aef56f744eaf7bdd879ac76626e1"
},
{
"id": "M5",
"file": "packages/webui/src/cli.mjs",
"occurrences": 1,
"before": "7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a",
"after": "3fa30f91b19a1ea0348214b927925b163e51a6184b97910ded2dbc2282e1ddf6"
},
{
"id": "M6",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "c1c4f97a962d8da9055373ca7ac4441712c2c9f4ea675d7b137a3306d0621012"
}
],
"bases": {
"packages/webui/tests/thread-claims-browser.test.mjs|row278 browser lists held claims": {
"code": 0,
"timeout": false,
"seconds": 0.715,
"log": "agents/gander/work/queue-278/run2/changes/M1-base.log"
},
"packages/webui/tests/thread-claims-browser.test.mjs|row278 browser claims 403 stays local": {
"code": 0,
"timeout": false,
"seconds": 0.916,
"log": "agents/gander/work/queue-278/run2/changes/M3-base.log"
},
"packages/webui/tests/thread-claims.test.mjs|row278 tester socket refuses thread claims": {
"code": 0,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/changes/M4-base.log"
},
"packages/webui/tests/thread-claims.test.mjs|row278 Console adapter calls argument-free": {
"code": 0,
"timeout": false,
"seconds": 0.314,
"log": "agents/gander/work/queue-278/run2/changes/M5-base.log"
}
},
"changes": [
{
"code": 1,
"timeout": false,
"seconds": 3.774,
"log": "agents/gander/work/queue-278/run2/changes/M1.log",
"id": "M1",
"base_seconds": 0.715,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.816,
"log": "agents/gander/work/queue-278/run2/changes/M2.log",
"id": "M2",
"base_seconds": 0.715,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 3.773,
"log": "agents/gander/work/queue-278/run2/changes/M3.log",
"id": "M3",
"base_seconds": 0.916,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/changes/M4.log",
"id": "M4",
"base_seconds": 0.214,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.315,
"log": "agents/gander/work/queue-278/run2/changes/M5.log",
"id": "M5",
"base_seconds": 0.314,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 3.873,
"log": "agents/gander/work/queue-278/run2/changes/M6.log",
"id": "M6",
"base_seconds": 0.916,
"outcome": "killed"
}
]
}
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser lists held claims", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,16 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 535.499612
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 651.310935
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser lists held claims", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,27 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 3566.368806
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: "Uncaught (in promise) Error: !!document.querySelector('#b-thread-claims'): undefined"
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async setup (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:33:3)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:40:49)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3677.584834
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser lists held claims", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,33 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 598.604567
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
'2' !== '1'
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: '1'
actual: '2'
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:46:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 716.536553
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser claims 403 stays local", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,16 @@
TAP version 13
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
ok 1 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 715.095255
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 831.950838
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser claims 403 stays local", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,26 @@
TAP version 13
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
not ok 1 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 3591.462679
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:55:1'
failureType: 'testCodeFailure'
error: `Uncaught (in promise) Error: document.querySelector('[aria-labelledby="b-thread-claims"] code')?.textContent==="human-required": undefined`
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:61:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3706.82009
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 tester socket refuses thread claims", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,16 @@
TAP version 13
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
ok 1 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 14.65787
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 133.295747
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 tester socket refuses thread claims", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,33 @@
TAP version 13
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
not ok 1 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 14.509095
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:46:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
200 !== 403
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 403
actual: 200
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:51:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 125.024128
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 Console adapter calls argument-free", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,16 @@
TAP version 13
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
ok 1 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 117.719722
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 229.873766
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 Console adapter calls argument-free", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,50 @@
TAP version 13
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
not ok 1 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 116.367834
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:54:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly deep-equal:
+ actual - expected
[
{
args: [],
tester: false,
+ verb: 'agents'
- verb: 'thread.claims'
}
]
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected:
0:
verb: 'thread.claims'
args:
tester: false
actual:
0:
verb: 'agents'
args:
tester: false
operator: 'deepStrictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:67:10)
Test.runInAsyncScope (node:async_hooks:226:14)
Test.run (node:internal/test_runner/test:1402:25)
Test.start (node:internal/test_runner/test:1262:17)
startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 230.973133
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser claims 403 stays local", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,26 @@
TAP version 13
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
not ok 1 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 3697.026047
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:55:1'
failureType: 'testCodeFailure'
error: `Uncaught (in promise) Error: !!document.querySelector('.s1-stale') && document.querySelector('[aria-labelledby="b-thread-claims"] code')?.textContent==='not-read': undefined`
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:67:3)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3817.114582
@@ -0,0 +1,129 @@
{
"grant": "sage-2638",
"static": [
{
"id": "M1",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "e1b693b5ddf3cd55091dd4c0a47934ca22fe7851c6e942f2386a6eefdcb5a1a0"
},
{
"id": "M2",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "6a7274e2d2281ac2d927a00e6cabe72656f648f721607f0896cac107a4e22fdb"
},
{
"id": "M3",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "7c30c0cfa6908bc0946df325d417f726ea67373b8afffe72fd3aebcd6a52c52b"
},
{
"id": "M4",
"file": "packages/webui/src/serve.mjs",
"occurrences": 1,
"before": "aa25b50543b5bc632ac984e85b0d8b43b1c9af2d617bfc7c19351d07310f396d",
"after": "10324c3a22dbefac6286af4f06e53a6e8057aef56f744eaf7bdd879ac76626e1"
},
{
"id": "M5",
"file": "packages/webui/src/cli.mjs",
"occurrences": 1,
"before": "7ac85787f614aabce4b8eccef01fcdbf1018003e806c5de97d40f47c4041710a",
"after": "3fa30f91b19a1ea0348214b927925b163e51a6184b97910ded2dbc2282e1ddf6"
},
{
"id": "M6",
"file": "packages/webui/src/public/bus.js",
"occurrences": 1,
"before": "c0306a4db82c286826b157cceb036496666f58ce8073d14280e58c10377ed0d0",
"after": "c1c4f97a962d8da9055373ca7ac4441712c2c9f4ea675d7b137a3306d0621012"
}
],
"bases": {
"packages/webui/tests/thread-claims-browser.test.mjs|row278 browser lists held claims": {
"code": 0,
"timeout": false,
"seconds": 0.715,
"log": "agents/gander/work/queue-278/run2/changes/M1-base.log"
},
"packages/webui/tests/thread-claims-browser.test.mjs|row278 browser claims 403 stays local": {
"code": 0,
"timeout": false,
"seconds": 0.916,
"log": "agents/gander/work/queue-278/run2/changes/M3-base.log"
},
"packages/webui/tests/thread-claims.test.mjs|row278 tester socket refuses thread claims": {
"code": 0,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/changes/M4-base.log"
},
"packages/webui/tests/thread-claims.test.mjs|row278 Console adapter calls argument-free": {
"code": 0,
"timeout": false,
"seconds": 0.314,
"log": "agents/gander/work/queue-278/run2/changes/M5-base.log"
}
},
"changes": [
{
"code": 1,
"timeout": false,
"seconds": 3.774,
"log": "agents/gander/work/queue-278/run2/changes/M1.log",
"id": "M1",
"base_seconds": 0.715,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.816,
"log": "agents/gander/work/queue-278/run2/changes/M2.log",
"id": "M2",
"base_seconds": 0.715,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 3.773,
"log": "agents/gander/work/queue-278/run2/changes/M3.log",
"id": "M3",
"base_seconds": 0.916,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/changes/M4.log",
"id": "M4",
"base_seconds": 0.214,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 0.315,
"log": "agents/gander/work/queue-278/run2/changes/M5.log",
"id": "M5",
"base_seconds": 0.314,
"outcome": "killed"
},
{
"code": 1,
"timeout": false,
"seconds": 3.873,
"log": "agents/gander/work/queue-278/run2/changes/M6.log",
"id": "M6",
"base_seconds": 0.916,
"outcome": "killed"
}
]
}
@@ -0,0 +1,114 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 33.448366
type: 'test'
...
# Subtest: row278 HTTP read preserves bus refusal and rejects a malformed result
ok 2 - row278 HTTP read preserves bus refusal and rejects a malformed result
---
duration_ms: 8.452867
type: 'test'
...
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
ok 3 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 4.790522
type: 'test'
...
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
ok 4 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 122.251062
type: 'test'
...
1..4
# tests 4
# suites 0
# pass 4
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 295.403076
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 628.085767
type: 'test'
...
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
ok 2 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 716.110463
type: 'test'
...
# Subtest: row278 browser renders only four escaped claim fields and never instance or other extras
ok 3 - row278 browser renders only four escaped claim fields and never instance or other extras
---
duration_ms: 586.771059
type: 'test'
...
# Subtest: row278 browser sign-out removes claims and prevents reuse of cached answers
ok 4 - row278 browser sign-out removes claims and prevents reuse of cached answers
---
duration_ms: 653.839485
type: 'test'
...
# Subtest: row278 tester browser keeps role rows without requesting the owner claims section
ok 5 - row278 tester browser keeps role rows without requesting the owner claims section
---
duration_ms: 583.925999
type: 'test'
...
# Subtest: row278 browser discards a late claims answer after sign-out
ok 6 - row278 browser discards a late claims answer after sign-out
---
duration_ms: 649.933183
type: 'test'
...
1..6
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3944.33987
{
"grant": "sage-2638",
"stage": "focused",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.365,
"log": "agents/gander/work/queue-278/run2/focused/focused-0.log",
"name": "focused-0",
"expected_red": false,
"counts": {
"tests": 4,
"pass": 4,
"fail": 0,
"skipped": 0
}
},
{
"code": 0,
"timeout": false,
"seconds": 4.023,
"log": "agents/gander/work/queue-278/run2/focused/focused-1.log",
"name": "focused-1",
"expected_red": false,
"counts": {
"tests": 6,
"pass": 6,
"fail": 0,
"skipped": 0
}
}
]
}
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,34 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 33.448366
type: 'test'
...
# Subtest: row278 HTTP read preserves bus refusal and rejects a malformed result
ok 2 - row278 HTTP read preserves bus refusal and rejects a malformed result
---
duration_ms: 8.452867
type: 'test'
...
# Subtest: row278 tester socket refuses thread claims explicitly with zero bus calls
ok 3 - row278 tester socket refuses thread claims explicitly with zero bus calls
---
duration_ms: 4.790522
type: 'test'
...
# Subtest: row278 Console adapter calls argument-free thread.claims through the normal transport
ok 4 - row278 Console adapter calls argument-free thread.claims through the normal transport
---
duration_ms: 122.251062
type: 'test'
...
1..4
# tests 4
# suites 0
# pass 4
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 295.403076
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,46 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 628.085767
type: 'test'
...
# Subtest: row278 browser claims 403 stays local and role section remains byte-equal
ok 2 - row278 browser claims 403 stays local and role section remains byte-equal
---
duration_ms: 716.110463
type: 'test'
...
# Subtest: row278 browser renders only four escaped claim fields and never instance or other extras
ok 3 - row278 browser renders only four escaped claim fields and never instance or other extras
---
duration_ms: 586.771059
type: 'test'
...
# Subtest: row278 browser sign-out removes claims and prevents reuse of cached answers
ok 4 - row278 browser sign-out removes claims and prevents reuse of cached answers
---
duration_ms: 653.839485
type: 'test'
...
# Subtest: row278 tester browser keeps role rows without requesting the owner claims section
ok 5 - row278 tester browser keeps role rows without requesting the owner claims section
---
duration_ms: 583.925999
type: 'test'
...
# Subtest: row278 browser discards a late claims answer after sign-out
ok 6 - row278 browser discards a late claims answer after sign-out
---
duration_ms: 649.933183
type: 'test'
...
1..6
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3944.33987
@@ -0,0 +1,34 @@
{
"grant": "sage-2638",
"stage": "focused",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.365,
"log": "agents/gander/work/queue-278/run2/focused/focused-0.log",
"name": "focused-0",
"expected_red": false,
"counts": {
"tests": 4,
"pass": 4,
"fail": 0,
"skipped": 0
}
},
{
"code": 0,
"timeout": false,
"seconds": 4.023,
"log": "agents/gander/work/queue-278/run2/focused/focused-1.log",
"name": "focused-1",
"expected_red": false,
"counts": {
"tests": 6,
"pass": 6,
"fail": 0,
"skipped": 0
}
}
]
}
@@ -0,0 +1,94 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
not ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 19.724699
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:17:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
404 !== 200
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 200
actual: 404
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:24:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 135.150334
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 3569.516596
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: "Uncaught (in promise) Error: !!document.querySelector('#b-thread-claims'): undefined"
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async setup (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:33:3)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:40:49)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3689.416702
{
"grant": "sage-2638",
"stage": "red",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/red/red-0.log",
"name": "red-0",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 3.772,
"log": "agents/gander/work/queue-278/run2/red/red-1.log",
"name": "red-1",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
}
]
}
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 HTTP read returns held claims", "packages/webui/tests/thread-claims.test.mjs"]
@@ -0,0 +1,33 @@
TAP version 13
# Subtest: row278 HTTP read returns held claims without send and refuses arguments before the bus
not ok 1 - row278 HTTP read returns held claims without send and refuses arguments before the bus
---
duration_ms: 19.724699
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:17:1'
failureType: 'testCodeFailure'
error: |-
Expected values to be strictly equal:
404 !== 200
code: 'ERR_ASSERTION'
name: 'AssertionError'
expected: 200
actual: 404
operator: 'strictEqual'
stack: |-
TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims.test.mjs:24:10)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 135.150334
@@ -0,0 +1 @@
["timeout", "-k", "10", "300", "node", "--test", "--test-reporter=tap", "--test-name-pattern", "row278 browser lists held claims", "packages/webui/tests/thread-claims-browser.test.mjs"]
@@ -0,0 +1,27 @@
TAP version 13
# Subtest: row278 browser lists held claims and release preserves role rows and totals
not ok 1 - row278 browser lists held claims and release preserves role rows and totals
---
duration_ms: 3569.516596
type: 'test'
location: '/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:39:1'
failureType: 'testCodeFailure'
error: "Uncaught (in promise) Error: !!document.querySelector('#b-thread-claims'): undefined"
code: 'ERR_TEST_FAILURE'
stack: |-
Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/browser.mjs:49:35)
process.processTicksAndRejections (node:internal/process/task_queues:104:5)
async setup (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:33:3)
async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/packages/webui/tests/thread-claims-browser.test.mjs:40:49)
async Test.run (node:internal/test_runner/test:1409:7)
async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
...
1..1
# tests 1
# suites 0
# pass 0
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms 3689.416702
@@ -0,0 +1,34 @@
{
"grant": "sage-2638",
"stage": "red",
"steps": [
{
"code": 1,
"timeout": false,
"seconds": 0.214,
"log": "agents/gander/work/queue-278/run2/red/red-0.log",
"name": "red-0",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
},
{
"code": 1,
"timeout": false,
"seconds": 3.772,
"log": "agents/gander/work/queue-278/run2/red/red-1.log",
"name": "red-1",
"expected_red": true,
"counts": {
"tests": 1,
"pass": 0,
"fail": 1,
"skipped": 0
}
}
]
}
@@ -0,0 +1 @@
2026-10-22T12:10:18Z
@@ -0,0 +1,12 @@
{
"timestamp": "2026-10-22T12:17:12.732808+00:00",
"count": 0,
"remaining": [],
"excluded_preexisting_infrastructure": [
{
"pid": 2880439,
"comm": "chrome-devtools"
}
],
"note": "Read-only cwd proc sweep, own ancestry excluded. No signalling. Slot already returned in gander-0094."
}
@@ -0,0 +1,51 @@
{
"grant": "sage-2638",
"stage": "syntax",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-0.log",
"name": "syntax-0",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-1.log",
"name": "syntax-1",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-2.log",
"name": "syntax-2",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-3.log",
"name": "syntax-3",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-4.log",
"name": "syntax-4",
"expected_red": false,
"counts": {}
}
]
}
@@ -0,0 +1,51 @@
{
"grant": "sage-2638",
"stage": "syntax",
"steps": [
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-0.log",
"name": "syntax-0",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-1.log",
"name": "syntax-1",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-2.log",
"name": "syntax-2",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-3.log",
"name": "syntax-3",
"expected_red": false,
"counts": {}
},
{
"code": 0,
"timeout": false,
"seconds": 0.064,
"log": "agents/gander/work/queue-278/run2/syntax/syntax-4.log",
"name": "syntax-4",
"expected_red": false,
"counts": {}
}
]
}
@@ -0,0 +1 @@
["node", "--check", "packages/webui/src/cli.mjs"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/src/serve.mjs"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/src/public/bus.js"]
@@ -0,0 +1 @@
["node", "--check", "packages/webui/tests/thread-claims.test.mjs"]

Some files were not shown because too many files have changed in this diff Show More