darkwing: merged B+C window packet, STATE.md (sha256 7be42b6bcab5657d), W0-W11 transcripts, S1/S2/S2b snapshots, P3 rehearsals and snapshot.mjs checks (#1673, #1674; P19 386, 382)

Evidence for the STATE report Sage checked and filed in 88f3253d9 (sage-1151). The skills-enabled
tar stays out of git; it is the W0b restore point under $WIN only. No credential or Environment
values: unit reads record ExecStart only, and the P3 credential files were fake placeholders.
This commit is contained in:
jason.woltje committed 2026-10-19 21:26:49 -05:00
1 parent 88f3253d98
commit c5ae4d7ac4
183 files changed
+13439

No files matched your search

@@ -0,0 +1,148 @@
# Merged B+C window, STATE report (W11)
Operator: Darkwing. Plan: `agents/sage/work/window-plan/repin-merged-bc.md` draft 9, sha256 523f20e03be8aa11
(commit c49de08e8). OLD 5fa9cc8f2c66b52408b652b59c3070f7210b44d0, NEW 89af38a83afa22a8a4f0d368a0a4030ad15a0efa.
Transcripts are in `window/`. Every stamp below comes from them. Written 2026-10-20 after W10 (mos-0922).
## Outcome
NEW is live for mosaic-stack with its PM. The store is on 3i, and the tester listener is on 127.0.0.1:7333.
W0 to W10 passed. Three plan deviations are recorded below, and Mos accepted each one. No stop condition
fired and nothing was rolled back. The only stop in the window was the planned 15-minute coder stop at W9o.
## Stamps and activations
| Step | Start (UTC) | Result | Activation id |
| --- | --- | --- | --- |
| pre / W0 | 01:33:05Z / 01:33:22Z | copy NEW, business-check OLD and NEW pass | |
| W0b backups | 01:33:51Z | business file and skills-enabled tar saved | |
| W1 + S1 | 01:34:42.608Z / 01:34:49.332Z | chief idle; S1 taken | |
| W2 status | 01:34:52.183Z | pointer OLD, check pass | |
| W3 plan | 01:34:58.880Z | exit 0 | |
| W4 unit read | 01:35:16.787Z | OLD units, no drop-ins | |
| W5 activate (mos-0910) | 01:37:08.484Z, end 01:37:11.255Z | exit 0, 3h to 3i, gate passed | 20261020T013708Z-89af38a83afa |
| W6 plugins set harness (tester) | 01:39:58.308Z | exit 0, transaction 0a63a1dc | |
| W7 pm-on (mos-0912) | 01:41:02.949Z, end 01:41:05.278Z | exit 0, gate passed, chief rc78c9700c8e9 launched | 20261020T014103Z-89af38a83afa |
| W8 skills carry (mos-0913, mos-0914) | 01:43:16.793Z | all seven match NEW | |
| W9 tester checks, coder, S2 | 01:44:03.003Z to 02:12:46Z | verified by Mos (mos-0918) | |
| W10 browser, 7332, P4 | 02:10:27.070Z to 02:15:46.240Z | pass with deviation 3 (mos-0920, mos-0922) | |
| W11 reads | after 02:16Z | W11.txt | |
## Backups and hashes
- Store backup: `~/.mosaic-dev/backups/stack/20261020T013708Z-89af38a83afa`. STAMP 2026-10-20T01:37:08.917Z,
SCHEMA 3h. SHA256SUMS sha256 ef78f7d4f4ea7dd9262393eea4b77f84928d9b945ad8585d471e877f85e169fc. bus.sqlite
sha256 eadd96d0d10663a95034303b337933227f90ccbb2378b38afe1541f1e40e09d6. Its `sha256sum -c` was OK at W5 and
again at S2b, and the hash didn't change across S2b.
- Rollback sets: `~/.mosaic-dev/state/stack-rollback/20261020T013708Z-89af38a83afa` (W5) and
`.../20261020T014103Z-89af38a83afa` (W7).
- Business file before W6: 82e726b9c416ddeaac699580bfa3b2854a40597bfe481679a3e88cc133d830b0, with the same hash
in the W0b backup `~/.config/mosaic-dev/businesses/mosaic-stack.json.pre-window-20261020T013351Z`. After W6:
1e49bdf05e62607972958f5b7298cfd600c7825812370e26d7c2a842f2af9b93 (actor tester, transaction 0a63a1dc).
`$WIN/harness.json` sha256 77fd493ffc9f3901.
- Skills restore point: `$WIN/skills-enabled-20261020T013351Z.tar`, sha256 d124631408e3801c.
- snapshot.mjs was 639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67 before S1 and before S2.
## Pointer
- Before (W2): `stack-active.json` copy 5fa9cc8f2c66, pm true, check pass, bus pid 1338933 since
2026-10-19T21:45:25.614Z, drift 149 commits.
- After (W7b, and again at W11c): copy 89af38a83afa, pm true, check pass for bus, Console and CLI, bus pid 1514133
since 2026-10-20T01:41:03.795Z, unit flags match the pointer. At W11c, drift is 7 commits.
## Units (ExecStart only, no Environment values)
Before (W4):
- bus: `copies/5fa9cc8f2c66.../scripts/mosaic bus start mosaic-stack --pm`, DropInPaths empty.
- Console: `/usr/bin/node copies/5fa9cc8f2c66.../packages/webui/src/cli.mjs serve --checkout /mnt/storage/src/mosaic-stack --port 7332 --public-host mosaic.woltje.com --auth-header X-authentik-username --allow-user jason.woltje --send`, DropInPaths empty.
After (W11a, W11b, W11d):
- bus: `copies/89af38a83afa.../scripts/mosaic bus start mosaic-stack --pm`, WorkingDirectory the NEW copy,
DropInPaths empty. active/running, MainPID 1514133, since 2026-10-19 20:41:03 CDT.
- Console: `/usr/bin/node copies/89af38a83afa.../packages/webui/src/cli.mjs serve --checkout /mnt/storage/src/mosaic-stack --port 7332 --public-host mosaic.woltje.com --auth-header X-authentik-username --allow-user jason.woltje --send --tester-port 7333`,
DropInPaths empty. active/running, MainPID 1475392, since 2026-10-19 20:37:09 CDT.
- W11e: healthz 7332 200, listening 127.0.0.1:7332 and 127.0.0.1:7333.
- P4 tunnel (W10i, W10j): ExecStart byte-identical to pre.txt:29, one spec `R:0.0.0.0:7332:127.0.0.1:7332`,
DropInPaths empty, active since 2026-10-13 08:40:19 CDT.
## S1, S2, S2b
S1 at 01:34:49.332Z on 3h, S2 at 02:05:17.993Z on 3i. Unchanged: decision_events 20, decisions 20,
instance_names 0, message_threads 0, projects 0, thread_claims 0, thread_opens 0, threads 0, with the same sha256
where snapshot.mjs prints one. Changed:
| Table | S1 | S2 |
| --- | --- | --- |
| deliveries | 1654 | 1673 |
| events | 1383 | 1396 |
| messages (count only) | 543 | 550 |
| role_claims | 87 | 91 |
| task_comment_cursors | 145 | 146 |
| task_snapshots | 349 | 351 |
| usage_records | 4 | 12 |
meta changed only schema_digest and schema_version. Usage byRun at S2: r8fba7e598156 0/0 with unknownTurns 1, and
r4a96e2142e4d 2/52, both as in S1. New: chief rc78c9700c8e9 input 14, output 1519, unknownTurns 0, and coder
r293f33bcbc63 input 2, output 44, unknownTurns 0.
S2b (an extra read, S2 against the W5 backup, opened immutable) shows priorSame true for every table and onlyInBackup
[]. stopTables lists deliveries, messages, role_claims, task_comment_cursors, task_snapshots and usage_records.
Those are the rows added since W5. It's a pre-restore test, not a W9 stop, and if a rollback is ever chosen it names
what a restore would drop.
File hashes (sha256, first 16): S1.json a4b48c69188ef856, S1.out 2de540bbf9908904, S2.json 92c3a66930db59ca,
S2.out edfd2e18ae3d1806, S2b.json a703b109cd5a5f68, S2b.out eded254a8dd25328.
## W9 outputs
- Tester reads all exit 0: status, console-check (5 PASS: markdown-preview, /api/config, project.files,
project.file north-star, loopback save 403), launches, agents, plugins, names, threads, limits, usage.
- Chief talk (W9e): reply 49c7dc51, "I took no action and sent no staffing request".
- Coder via the chief (W9l): chief message 5b58f447 to coder r293f33bcbc63 at 01:45:48.780Z. The coder replied
7815907c at 01:45:54.714Z with "ms-unslop, ms-sdlc, ms-file-read, ms-file-write". That matches its bundle
manifest (W9m), and each SKILL.md sha256 equals NEW's. The chief relayed it to the tester as 97139ccd at
01:45:59.450Z. 97139ccd is still unreceived, as Mos ruled in mos-0918.
- The coder made no tool calls. It left no repo write, push, PR, issue or outward message. I stopped it at
02:01:41.636Z (W9o, exit 0), and W9p shows only the chief live.
## W10 outputs
- Browser on 127.0.0.1:7333 (W10b) showed the tester banner, the instance, routes and name editors, and only
tester forms. No launch settings, assistant, limit reset or send appeared. The Board reads. All 20 requests were
GET. Screenshots: `window/w10-settings.png`, `window/w10-board.png`.
- 7332 with `x-mosaic-tester: 1` and Host 127.0.0.1:7332: 403 `{"error":"tester listener required"}`. The
control without the header got 200.
## Plan deviations (all accepted by Mos)
1. W8 (mos-0914). carry-past-row64.md:23 cds into the pinned copy, which has no scripts/skill.sh or skills/. The
loop ran from REPO after an empty diff against 89af38a83, followed by a per-file sha256 check that all seven
skills match NEW.
2. W9 (mos-0917). Plan lines 202-203 call for "a coder session the tester starts", but TESTER_VERBS
(broker.mjs:97) has no role.launch. Instead a tester talk asked the chief to start one coder.
3. W10 (mos-0920, mos-0922). "Board and Settings read. The tester Settings has no Token limits panel, by design at
bus.js settingsView isTester branch. No daily quota entry shows. Token limits read as the tester: W9i mosaic
limits shows tokens [] (none set), and W10b's tester page GETs /api/bus/limits without refusal. No step
rendered the human Token limits panel." Mos's code read: "bus.js tokenLimits (:599-609) renders 'No token limits
are set.' for an empty row list, and its daily line appears only when a row's path[1] is 'daily'. With W9i's
tokens [], the human panel would show no daily quota entry. This is a code read, not a rendered check." No human
Console read ran, because on 7332 it would mean sending Jason's auth header.
## Corrections during the window
- W9 no-reply. My interim said the coder hadn't answered. It had answered within 5 s. My wait polled
`inbox --tester --json`, which prints decisions only (cli.mjs:298-300). A message to the tester arrives only
through message.receive. So the stop at 02:01:41Z hit an idle coder. W9s, W9t.
- My own `git status` in the coder workspace moved its .git directory mtime to 02:07:22Z through the index lock.
The index file itself didn't change.
- W10a failed on two selector bugs in my script, not in the Console: the Board is #board-view, and conv-form is the
global hidden form. W10b reran the same read-only check.
- My 02:14Z message claimed token limits were read on the human path at W9b console-check. That was false.
console-check has no limits check. I corrected it at 02:15Z (W10d).
## After-window items, not part of this report's pass
- Sage: fold the plan line 222 text fix into #394 with the carry doc fix (mos-0920). Decide whether the
inbox --json point belongs with row 177 (W9t).
- Mos: a separate Console task for the "Read never." settings subtitle against the top bar's read time.
- P19 390: the --restore guard tool fix, unchanged by this window.
@@ -0,0 +1,6 @@
# W0b backups, 2026-10-20T01:33:51Z (repin-merged-bc.md draft 9, Backups table)
business file: 82e726b9c416ddeaac699580bfa3b2854a40597bfe481679a3e88cc133d830b0 live /home/jwoltje/.config/mosaic-dev/businesses/mosaic-stack.json
business file: 82e726b9c416ddeaac699580bfa3b2854a40597bfe481679a3e88cc133d830b0 backup /home/jwoltje/.config/mosaic-dev/businesses/mosaic-stack.json.pre-window-20261020T013351Z
business backup mode/size/mtime: 600 4260 1792446594; live: 600 4260 1792446594
skills-enabled tar: d124631408e3801ccf3453614832a4fe3cf26c275e2e963100338e6ab7c7239e /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/skills-enabled-20261020T013351Z.tar
skills-enabled entries: skills-enabled/ skills-enabled/ms-communications/ skills-enabled/ms-communications/SKILL.md
@@ -0,0 +1 @@
{"revision":"82e726b9c416ddeaac699580bfa3b2854a40597bfe481679a3e88cc133d830b0","plugins":{"harness":["claude-code"]}}
@@ -0,0 +1,13 @@
{
"business": "mosaic-stack",
"revision": "c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
]
}
}
@@ -0,0 +1,16 @@
{
"business": "mosaic-stack",
"revision": "486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
],
"harness": [
"claude-code"
]
}
}
@@ -0,0 +1 @@
{"revision":"486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a","plugins":{"harness":null}}
@@ -0,0 +1,36 @@
9cbf9a23e41e546a6b92a3403ee800e6e325ca5c9065e9580fd3678c304dd979 ./b/all.sh
6b25b038e3d7f4d12d169613a6f7e214d2c4f69e34fb98d446f4adad3876e44d ./b/claude
bbb6dbe133f9974db5e88def4cc2859d9d6a14c0cb58c4c3806a99f382ca3183 ./b/cmp.mjs
90e464119c5991480f097ad2904b8054bf1ef40297ac16e4a179ed4c4e83f5cb ./b/d3report.mjs
0bfda2843595f7058105c0f716f354450ac0311e0596e0e9041865035efb0649 ./b/env.sh
89c201e59d7bb6427041734757d170df7c9b39d96d8cb680a57fbb9eff5ab5aa ./b/healthz.cjs
fb1f19bb5a464d575ffdeb133a9a2df7fdf507218e683fddaaa170280d5c9fed ./b/jget.mjs
e1dcabdd3e43cae6f885a44fc1fe357406c00d896c03fff889f8b61dd4e15683 ./b/journalctl
2aed6b4762c6f48cd338f15134822118dddac9ce6246ef5c4fc9faff6f80178e ./b/load-check.mjs
dc9ebad483d55f8016b73d6fb36a7b6e6d7921bc052a605aeabec8a650136ed0 ./b/mkbiz.mjs
7a0821f59d23d318d7d2d5a24b24f774548acc25c31da15d92566e9d6c614f42 ./b/prep.sh
fd719a11ee9f6abd8d1f12fe8ca3f06544019b0a3dc62352fdf817724f7caf10 ./b/run.sh
073f1952e35f464fe26fa9c86161b322c3f10f20814128b000b9c368e5c9de2a ./b/seed.sh
98d10dc85c7ea32e032529935d2cf39b4d63196e5e7ab05bd4332b43833e88fb ./b/store-seed.mjs
e3669292be33f8b8298d9d1a00ba19e5ca42e3b50fc995007c9fc4587d0df6cd ./b/systemctl
30908331d33adead6e32b9da5b77ca29283f42446636527946541618331dc8a2 ./b/systemd-analyze
6e9494e2b4f306ca2320f0cc274d9d4aeb925c73cc94a9c678f607a2b14667ed ./b/teardown.sh
0a4884269bd5914075294e803262078bd7aa12c8b8e119b1aa7b8d58fb8c5f72 ./b/wait-run.sh
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-after.txt
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-before.txt
c15ce1d568ace97cde5e53194b738a742c856fa147581ef35a97d2b6d89eaa06 ./p3-live-store-stat.txt
2feac959b95ea8664f5097fe1261864c7815f8a6d2d980c03bfb1df1d365ffd0 ./p3-steps.log
70587fda4b78d37a9f952f51026f1c293673311e23611d649c21ff1e2a118e00 ./p3-teardown.txt
80f59e1f0a8b32edc04e94b90ff21d541cbf13f3265f5cb04a8f96618468a9ac ./p3.txt
c15a0ab6898c3841929fc0ea1c7dc91c83c0c14caaf35f576f42459428f3d0fc ./R1-after.json
813399ad5b05721b3e332783d15f4c66c788fd4edb6d8395c335fa21c22c7664 ./R1.json
3381436016f77d9845361d469fd0d77dd67ae1227bd573c1b4bd82abc7e50df4 ./R1-read.json
4d212bcfad0d6a0f4724f1120222944413871345cbf864107ed4527a7af9804f ./snap/D3.json
a651882c443cc17ddf927a72a1e87e72466ceb32adefaa9983c92dda4f2abca9 ./snap/F.json
a651882c443cc17ddf927a72a1e87e72466ceb32adefaa9983c92dda4f2abca9 ./snap/S1.json
2d0d2fe1bf456a24542026c710f9fb4b464be91eb1afbcff1f24747586f93a1a ./snap/S2.json
2d0d2fe1bf456a24542026c710f9fb4b464be91eb1afbcff1f24747586f93a1a ./snap/W5.json
06db4a217ece559b9fca7b4385a94cb0dd6efbda5c8ed11c36735eed957a5b07 ./W3-plan.txt
3381436016f77d9845361d469fd0d77dd67ae1227bd573c1b4bd82abc7e50df4 ./W6-after.json
387d31ef17e1b1dfbd0ae26298418aa9fff5a0a1d6b836a7bc4be282c4f6a654 ./W6.json
c15a0ab6898c3841929fc0ea1c7dc91c83c0c14caaf35f576f42459428f3d0fc ./W6-read.json
@@ -0,0 +1,157 @@
plan: activate for mosaic-stack
from: 5fa9cc8f2c66b52408b652b59c3070f7210b44d0
to: 89af38a83afa22a8a4f0d368a0a4030ad15a0efa
store schema: 3h (read from the store the running bus holds)
target schema: 3i
migration: 3h to 3i, after a backup of the stopped store
migration steps: 3h to 3i
needs: --migrate (given)
needs: Jason present for this run (decision 96 condition 2)
commits: the run adds 143 (newest first, at most 200):
89af38a83 webui, bus, scripts: a loopback-only Console listener for the tester; 7332 refuses x-mosaic-tester (row 176, #1674)
06a82c9fb sessions: Dewey row 176 r2 review, approve (comment 29322)
548b61a5b sessions: Dewey row 176 r1 review, changes (comment 29309)
0a478dfc3 queue: revs 2079-2082: row 176 round 1 in-review on candidate b05cbf08 (Rocko 2079), the request failed without a token as expected (Rocko 2080), posted as jarvis, comment 29305 (Sage 2081, 2082)
60d6e6755 queue: revs 2077-2078: row 176 claimed by Rocko on 473258a51 (Rocko 2077); busStatus ruling note, the tester-off and tester-required 403 goes in a serve.mjs coreBusStatus wrapper and bus.mjs stays pinned (Sage 2078)
8e888014d log: row 175 landed (98d29769e), row 176 brief amended and launched, merged window drafted; sessions: Sage
473258a51 queue: revs 2072-2076: row 175 round 3 approve on 2e30f2a1 (Filbert 2072, comment 29279), landing note and done after 98d29769e (Sage 2073, 2074); row 176 brief re-pinned to 0f7119af9566 for the stack-release --tester-port pointer change and row 175 F1 (Sage 2075), queued to briefed (Sage 2076)
2fecddfba sage: row 176 brief: activate --tester-port N writes the flag into the pointer's Console flags, a rollback or an activate to a copy whose Console lacks it drops it, tester-port-target refuses before anything stops; tests and three mutants; row 175 F1 (TOOLS.md step 2) rides along
98d29769e bus, cli: tester reads and the W1-W7 tester writes, recorded as tester; scripts/mosaic sends plugins, name and names to the CLI (row 175, #1673)
1d81c54ff sessions: Filbert row 175 r3 review, approve
716ddcf1e queue: revs 2058-2071: row 179 start, in-review and request (Darkwing 2058, 2060, 2061), issue #1677 (Sage 2059), r1 approve (Dewey 2062, comment 29271), landing note and done after 9e74925c2 (Sage 2063, 2064); row 175 r2 request on f9e41b918 (Dewey 2065-2067, comment 29275), back to in-progress to rebase onto 9e74925c2 (Sage 2068, 2069), round 3 request on the rebased candidate 2e30f2a1 (Dewey 2070, 2071, comment 29276)
0f45a3e6e sessions: Dewey row 175 round 2 to in-review on 989699f7c, row 179 approved
9e74925c2 docs: TOOLS.md follow-ups F1-F3 from the row 169 review (row 179, #1677)
ce5807989 log: row 169 landed (264756a30), row 179 briefed, row 175 to round 2 (1bfc9833b)
1bfc9833b queue: revs 2052-2057: row 179 added and briefed (Sage 2052, 2057), row 169 landing notes and done after 264756a30 (Sage 2053, 2054, 2056), row 175 r1 approve recorded (Filbert 2055, comment 29264)
c98a5d17a sessions: Dewey row 175 round 1 approved
8f2ac5236 sessions: Filbert row 175 r1 review, approve
264756a30 stack-release: activate --pm-after-harness, pm-on and the pending pointer, so a re-pin past c216f47db starts the PM after the harness kind is set (row 169, #1666)
b2a75f318 sage: brief for the row 169 TOOLS.md follow-ups F1-F3 (Filbert, #1666 comment 29263), owner Darkwing, reviewer Dewey, after row 169
e7d47c346 log: rows 169 and 175 in-review, row 169 r1 approve, queue revs 2046-2051 (cb4a8bf1f)
cb4a8bf1f queue: revs 2046-2051: row 169 in-review round 1 (Darkwing 2046-2047), row 175 brief re-pin for the wrapper fix (Sage 2048), row 175 in-review round 1 on 7b27ab3f9 (Dewey 2049-2050), row 169 r1 approve recorded (Filbert 2051, comment 29263)
c7939a568 sessions: Filbert row 169 r1 review, approve
423ff5c86 sessions: Dewey row 175 round 1 in-review
3dfaea286 sage: row 175 brief carries the scripts/mosaic dispatch fix (plugins, name, names, follow, threads, thread go to packages/cli), test 12 and a mutant; found in Darkwing's row 169 rehearsal
d63cfca22 log: row 178 brief for mos-0881 (30622a229, c6ef51ee1)
c6ef51ee1 queue: row 178 re-pinned to the mos-0881 brief (rev 2045, Sage)
30622a229 sage: row 178 brief, the turn-on doesn't wait for Jason (mos-0881), with roll-back-at-once on a failed signed-in check; bc310ee pod-label part recorded
47a351add log: rows 176 and 178 briefs revised for mos-0878 (80cabd935, c4e049319)
c4e049319 queue: rows 176 and 178 re-pinned to the mos-0878 briefs, row 178 piece updated and after set to 169, 175, 176 (revs 2041-2044, Sage, mos-0878)
80cabd935 sage: row 176 brief adds the credentials-body and project-root tests (mos-0878 Q1); row 178 brief rewritten for mos-0878 Q2: partial fix after the window rows, console-proof.token slot, ops-01 SealedSecret and middleware under R27, console-allowed-uid recorded as decision 101's uid and left alone
0750b6a49 log: rows 176-178 filed (#1674-#1676, mos-0872, mos-0874), row 175 briefed and claimed
58e173535 queue: rows 176 (#1674), 177 (#1675) and 178 (#1676) added (revs 2038-2040, Sage, mos-0872, mos-0874)
6ee7285c0 sage: briefs for rows 176 (#1674, Console tester listener on 127.0.0.1, 7332 refuses x-mosaic-tester, mos-0872/0874), 177 (#1675, tester threads, scoping) and 178 (#1676, Traefik proof for signed-in requests, Vikunja #385, mos-0874)
835941b7c queue: row 175 widened to tester writes and briefed with no after (revs 2032-2036, Sage, mos-0870 N2, mos-0872); also Dewey's rev 2037 (dewey-175-claim, row 175 in-progress)
1c90c68c5 sage: row 175 brief widened to tester reads and writes (#1673, Q173, mos-0870 N2, mos-0872 Q1-Q3): seven writes recorded as tester, nine human-only items, prefix lifted, project init --tester inside the data root's project area only
d195d171c log: row 166 landed (4b738e2da, #1663 closed), row 175 filed (#1673, mos-0868)
6b8f94524 queue: row 166 done with landing note (revs 2029-2030), row 175 added after 169 (#1673, mos-0868, rev 2031); Sage revs only
f8ac674cc sage: brief for row 175 (#1673, --tester on the window reads, mos-0868); Window B doc after mos-0866 F1-F3 and mos-0868: W4 from the unit template, agents to Mos with --tester, Jason's reads in J1 and J2
4b738e2da stack-release: refuse unreadable drop-ins and quoted units, recheck the bus after a held read, gate on the target copy (row 166, #1663)
64922106d sage: carry-past-row64 names Vikunja P19 #383, no pi window before the pi credential is settled (mos-0865 D2)
c7424db50 log: row 64 closed, D2 coder sessions on both harnesses, #1557 closed (mos-0863, mos-0864)
5cabf919e queue: row 64 done, landing note with D2 #1557 comment 29228 (mos-0864; Sage revs 2027-2028)
c87865ee0 sage: row 64 D2 evidence, scratch-root builder, driver, check and both coder manifests (mos-0863 D2, #1557 comment 29228)
3510c3cbf queue: row 174 for #1672, skill read BOM and fs errors after row 173, not started (mos-0863 D4; Sage rev 2026)
9c80ba7f1 plans: brief for #1672, skill reads keep a leading BOM and report fs errors as skill-refused (row 64 N2/N3, mos-0863 D4)
46de60893 sage: window carry step for any pin past row 64, install and activate the seven role skills from the pinned copy (mos-0863 D3, #1557)
ebfc23c43 sage: row 64 packet, build notes, both gates, mutants and the landing manifest; BUILD.md item 5 corrected for Darkwing N1 (mos-0863 D5, #1557)
6b6567b8b harness: README names bundle-refused for the skill content refusals, skill-refused at the launcher (row 64 F1, #1557 comment 29218)
9f0039711 roles, harness, cli: a managed session gets its role's skills as prompt text on both harnesses (row 64, #1557)
1a01f63ea queue: row 64 round 1 approvals, Filbert rev 2024 and Darkwing rev 2025 on manifest 7689cd9b (#1557)
7c81d5e9c sessions: Filbert row 64 r1 review, approve
12ac2c428 sessions: Sage line for row 64 candidate, gate and in-review round 1
e76c73f72 queue: row 64 started and in-review round 1 on c6d7d538f, reviewers darkwing and filbert (#1557, Sage revs 2022-2023 and the start rev)
087d202bc queue: row 173 for the Seen click intent gap after row 172 (#1671, mos-0861 A1; Sage rev 2021)
a0da43dab plans: brief for the Seen click intent gap after row 172 (#1671, mos-0861 A1)
b5d4d0f22 sessions: Sage line for the row 172 landing and close-out
c24fe5d0f build-log: row 172 landing, the dropped Seen click and the row 165 reload race (#1670)
83db85aa3 queue: row 172 round 1 Darkwing approve (darkwing rev 2018), landing note and done (Sage revs 2019-2020)
be10e0c83 webui: a Seen click during a Board read waits for the read and posts, and the row 165 test loads the page instead of reloading from an evaluate (row 172, #1670)
7f38a2f54 sage: row 172 packet, base control and trace lines corrected (Darkwing D1, D2 on #1670)
0ed9412fc sessions: Sage line for the 170/171/134 build-log and row 172 round 1
9d6e47dd5 queue: row 172 brief re-pin, briefed, start and round 1 in-review on 15c3d8ca1 (Sage revs 2013-2017)
17d566305 sage: row 172 packet, candidate 15c3d8ca1 (cause trace, mutants, 10-run loop, gate)
164e1f97f row 172 brief: the cause is a Seen click dropped during a Board read, and the reload race in the row 165 test (P19 366, #1670)
bab069b3c build-log: rows 170, 171 and 134 landings, with the row 134 range-diff evidence (mos-0859/0860)
b42934b85 queue: row 134 done on 3a600cf5b (Sage revs 2011-2012: note, done)
a85e573d4 cli README: the chief of staff reads the organization revision with organization_revision, not from the human (row 134 follow-up, Filbert #1669 29193)
3a600cf5b bus, harness: a role holding organization.change reads the organization revision itself with organization.revision and the organization_revision tool (row 134, #1669)
04155deff queue: row 171 done on 078518e4e, plus revs 1996-2010 (Sage: 171 reopen/request/note/done, 172 add, 134 review request; Rocko 1997-1998 row 171 round 2 in-review; Researcher 2002-2004 row 134 start and round 1 in-review; Dewey 2007 row 171 approve; Filbert 2008 row 134 approve)
078518e4e bus, cli, webui: a thread project named like a business-file repo refuses project-name-is-repo unless --repo matches, with a clearer CLI refusal (row 171, #1668)
b2d3b6c47 sessions: Filbert row 134 r1 review, approve
ed045ac84 dewey: SESSIONS line for the row 171 round 2 review (#1668)
4d9114ab4 sage: row 172 brief, the board-held sign-out wait under gate load (P19 366, #1670, mos-0858); cause section open until traced
d58c9c5cd queue: row 170 done on cb43dcb45, plus revs 1970-1994 (Sage: 171 scope/re-pin/request/note, 134 re-pins/assign/issue/briefed, 64 and 66 re-pins, 64 start, 170 note and range-diff; Rocko 1970, 1973-1974 row 171 start and round 1; Dewey 1971, 1981-1982 row 170 claim and in-review, 1990 row 171 approve; Filbert 1986 row 170 approve)
cb43dcb45 bus, cli: a tester message to a role nobody holds refuses tester-target-not-running, and talk --tester exits 3 (row 170, #1667)
228aeb503 sage: rows 64/66 brief, skills reach both harnesses as prompt text (pi read is workspace-confined, Claude Code Skill tool offers its own skills; probe in agents/sage/work/queue-64/probe.md)
c9f6e214f dewey: SESSIONS line for the row 171 round 1 review (#1668)
2cef8cd35 sage: row 134 brief owns the three stale revision-from-the-human sentences (Researcher build report)
9b11b8731 sessions: Filbert row 170 r1 review, approve
2e9fe381f docs: register Sage's rows 171, 134, 64 and 66 brief work and the b0721a0b0 push correction
e0bf9960d sage: rows 64 and 66 brief refreshed to 7319bd867 after row 65 (harness module files owned, plugins suite in the gates), row 64 candidate names Sage as author and gate owner (mos-0855)
b0721a0b0 dewey: SESSIONS line for the row 170 build and in-review (#1667)
7319bd867 sage: row 171 brief names cli.mjs (sage-1021, mos-0855), row 134 brief refreshed to 000730949 with owner Researcher, row 42 run log takes mos-0855's triggers (#1668)
000730949 queue: rows 170 and 171 briefed on Mos's approval, row 171 re-pinned to the mos-0854 brief (mos-0854, #1667, #1668) (revs 1964-1969)
fcfa577f2 sage: row 171 brief cites mos-0854 (D1 withdrawn, option B approved) in place of its open decision section (#1668)
92160cb30 queue: rows 170 (P19 380, #1667) and 171 (P19 379, #1668) added queued, briefs 97cc7f0a3 await Mos; Darkwing's row 169 claim (revs 1961-1963)
97cc7f0a3 sage: briefs for P19 380 (tester refusal, #1667, row 170) and P19 379 (project names vs repos, option B, #1668, row 171), for Mos's approval
42817065e queue: row 169 after cleared, in-review waits on 166's landing by note (mos-0852 point 5, #1666) (revs 1959-1960)
56534526b sage: Window B last section rewritten for the approved two-phase path, row 169 (mos-0848 (b), mos-0852, #1558, #1666)
cbdcf1967 queue: row 169 briefed on Mos's brief approval (mos-0852, #1666) (rev 1958)
3ff2360dc sage: Window B P3 recorded done from Darkwing's rehearsal, with what it didn't exercise (#1558)
c5b74bef2 darkwing: Window B P3 scratch rehearsal, activate --pm --migrate 3h to 3i and rollback --restore on blob 4b16e848 (sage-1004, mos-0838 D2, #1558)
3b5c964eb queue: row 169, the stack-release.sh two-phase PM start (P19 382, #1666), brief pinned at bfc5fa7ba36e (revs 1956-1957)
b201760c5 sage: W6 business instances from $C_NEW and the project list channel note in plan A, verb routes checked in A and B (mos-0851), row 169 in the 382 brief (#1558, #1666)
bd8416bc2 plans: brief for P19 382, activate past c216f47db with the PM launched after the harness kind is set (mos-0848, #1666)
421217411 sage: Window A P2 CONSOLE_PASS and the post-W5b channel undo before rollback (mos-0849, #1558)
6e7c23d7d sage: Darkwing's Window A and B scratch --plan and load checks, cited in both plans (#1558)
855c9eb01 sage: Window A and B plans with mos-0846 U1, the 382 bus-exit finding, mos-0845 P19 comments (#1558)
6dbc67302 sage: Window A and B plans with mos-0845 rulings, P19 378-382 filing scripts (#1558)
894ce3f37 sage: file row 65 follow-ups as P19 376 and 377 (mos-0842 item 4, #1558)
73bbbee81 sessions: Sage row 65 landing, c216f47db with gate g3 green (#1558)
a5810fc84 build-log: row 65 landed as c216f47db, gate g3 green, mos-0841 conditions met, not live (#1558)
71fd9b922 queue: row 65 done, landed as c216f47db on #1558 (sage rev 1955)
aed9062b4 sage: row 65 landing notes, c216f47db with gate g3 green, the mos-0840 Routing view, the plugins set patch for Jason, follow-up 5 (#1558)
c216f47db plugins, cli, bus, business, webui: harness, model and thinking from the instance vars, a fallback route, and a harness plug-in kind (row 65, #1558)
866f3c5a8 queue: row 65 round 2 in review on #1558 with candidate 8d7c9e2f1, request 29143 (sage revs 1951-1952); darkwing approve (rev 1953, comment 29144) and dewey approve (rev 1954, comment 29145), both on manifest 8df15e39
24320f80c sessions: Dewey row 65 round 2 review, approve (comment 29145, rev 1954)
b4c9cb359 sage: row 65 round 2 packet, candidate 8d7c9e2f1 on 89ddb0225, manifest, diff, public/ diff (digest a91cf866 unchanged), build notes, gate and 18 mutants (#1558)
89ddb0225 queue: row 65 round 1 verdicts, dewey changes (rev 1947, comment 29136) and darkwing changes (rev 1948, comment 29137); sage moves row 65 back to in-progress (rev 1949) and re-pins the brief to blob 0cdff8739051 (rev 1950) for round 2 (#1558)
0235fa9fd brief: row 65 routing table names the chief of staff's Q169 assistant exception and its tests (round 2 ruling, sage-1006, #1558)
ff9edc778 sessions: Dewey row 65 round 1 review, changes (comment 29136, rev 1947)
9014f9f72 sessions: Sage row 65 build, Mos decision 123 go (mos-0841) and in-review
4c6649454 queue: row 65 in review, round 1 on #1558 with candidate ccdbc2232, request 29133 (sage revs 1945-1946)
1d5897024 sage: row 65 packet, candidate ccdbc2232 manifest, diff, public/ diff, build notes, gate and mutants (#1558)
d8336daef queue: row 65 brief re-pinned for the human-only routes.set verb (sage rev 1944)
841e0b0a2 brief: row 65 routing table saves through a human-only routes.set verb, outside ORGANIZATION_KEYS
4d856a0cd queue: row 65 brief re-pinned to 54cbf1a2 for the Console routing table, and its gate names Mos's decision 123 check (sage revs 1942-1943)
d3af6db97 brief: row 65 adds a Console routing table for harness, model, thinking and fallback (mos-0840), and refuses thinking a harness can't apply
b65e6d5fe sessions: Sage row 168 landing, row 65 brief amendment (decision 151), row 7 posts
e1bfc2cd4 queue: row 65 in progress and brief re-pinned to 802e046c with its gate, row 168 approved by Dewey and done (sage revs 1937, 1939-1941; dewey rev 1938)
8e2cbb555 brief: row 65 keeps the instance vars as its one source, adds fallback vars and the full harness list (decision 151, #1558)
efb51169d ledger: count only stack issue numbers, a tracker-name skip and a --first-issue floor (#1665)
54786df03 sessions: Dewey row 168 review round 1, approve (29121)
c34deedf9 sessions: Sage row 168 build and review request, P19 371 rulings
3bf16114a queue: row 168 in review round 1, manifest candidate, request 29120 (sage, revs 1935-1936)
6da8fdaa9 sage: row 168 packet, candidate f3a966ea4 manifest, diff, build notes and gate (#1665)
e2ad3aa10 queue: row 168 in progress, brief re-pinned to 52ac1975 and piece updated (sage, revs 1932-1934)
03586947a docs: row 168 brief amended before build, floor moves to a --first-issue option (#1665); window-plan: mos-0838 rulings in the 3i draft
e69e646b4 window-plan: P19 371 3i window draft for Mos, one or two windows and the restore caveat
c16ba2f0c queue: row 168 ledger stack refs added and briefed, #1665 (sage)
a1572a8f7 docs: brief for the ledger counting only stack issue numbers (#1665, P19 372, row 7 follow-up)
15357b4ba sessions: Sage AM standup and row 7 week 10-11 ledger rerun record
b90d944c8 queue: row 7 note, 10-11..10-17 ledger rerun 29089 (sage)
296972652 queue: row 126 Filbert r2 approve and done (sage)
a267a64b1 sessions: Sage row 126 landing, P19 371 and 372, row 7 week ledger; Dewey queue-126 packet
ca15d73e9 limits: a daily token quota for the account the stack uses, and bus schema 3h to 3i (row 126, #1620)
54319f552 sessions: Filbert row 126 r2 review, approve
4c385db45 sessions: Dewey row 126 round 4 build and review rounds 1-2
2124cfa76 queue: row 126 Filbert r1 approve, brief re-pin for 3h to 3i, row 7 week note, round 2 in-review (sage)
e264db51b plans: row 126 brief names the 3h to 3i step and the account guard (#1620)
1df04f52f sessions: Filbert row 126 r1 review, approve
9e2b26866 queue: row 167 Filbert approve and done, row 126 round 1 in-review (sage)
640a1ee97 sessions: Sage row 167 landing and row 126 3i ruling
pm: the bus starts without --pm and the PM stays pending; next: Jason's plugins set of harness, then pm-on
bus: scripts/bus-service.sh install --copy 89af38a83afa22a8a4f0d368a0a4030ad15a0efa --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
Console: scripts/webui-service.sh install --copy 89af38a83afa22a8a4f0d368a0a4030ad15a0efa --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack --tester-port 47395
CLI: scripts/stack-copy.sh wrapper 89af38a83afa22a8a4f0d368a0a4030ad15a0efa --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
@@ -0,0 +1,16 @@
{
"business": "mosaic-stack",
"revision": "486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
],
"harness": [
"claude-code"
]
}
}
@@ -0,0 +1,13 @@
{
"business": "mosaic-stack",
"revision": "c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
]
}
}
@@ -0,0 +1 @@
{"revision":"c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32","plugins":{"harness":["claude-code"]}}
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# P3 driver: the live-store stat (mos-0878), prep, seed, run, teardown, the stat again, the Docker network
# names before and after, then the outputs copied to $WIN/p3 with SHA256SUMS. Started only behind
# wait-run.sh (busy.sh) on Sage's go. NEW=<sha> TP=1 for the run on the row 176 tool blob.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$R/out" ] || { echo "all.sh: $R/out exists; move it aside first" >&2; exit 1; }
mkdir -p "$R/out"
S=$R/out/p3-live-store-stat.txt
LIVE=(/home/jwoltje/.mosaic-dev/bus/bus.sqlite /home/jwoltje/.mosaic-dev/bus)
{ echo "# before prep, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } > "$S"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-before.txt"
rc=0
"$B/prep.sh" && "$B/seed.sh" && "$B/run.sh" || rc=$?
"$B/teardown.sh"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-after.txt"
{ echo "# after teardown, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } >> "$S"
cat "$S"
if [ "$(sed -n 2,3p "$S")" = "$(sed -n 5,6p "$S")" ]; then echo "live store stat: match"; else echo "live store stat: DIFFER"; rc=1; fi
if cmp -s "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; then echo "docker networks: unchanged"; else echo "docker networks: CHANGED"; diff "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; fi
echo "all.sh: run exit $rc"
W=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/p3/$(git -C "$REPO" rev-parse --short=9 HEAD)-tp$TP
mkdir -p "$W" && cp -p "$R"/out/*.txt "$R"/out/*.json "$R/out/p3-steps.log" "$W"/ 2>/dev/null; cp -pr "$R/out/snap" "$W"/
cp -p "$B"/*.sh "$B"/*.mjs "$B"/*.cjs "$B"/systemctl "$B"/journalctl "$B"/systemd-analyze "$B"/claude "$W"/ 2>/dev/null; mkdir -p "$W/b" && mv "$W"/*.sh "$W"/*.mjs "$W"/*.cjs "$W"/systemctl "$W"/journalctl "$W"/systemd-analyze "$W"/claude "$W/b"/ 2>/dev/null
rm -f "$W/last.txt"
(cd "$W" && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS)
echo "outputs: $W ($(wc -l < "$W/SHA256SUMS") files, SHA256SUMS sha256 $(sha256sum < "$W/SHA256SUMS" | cut -c1-64))"
exit $rc
@@ -0,0 +1,3 @@
#!/bin/sh
# Fake claude for the scratch rehearsal. It never runs a model; the PM launch is emulated.
echo "9.9.9 (Claude Code fixture)"
@@ -0,0 +1,18 @@
// P3: compares two snapshot.mjs outputs table by table, over every table either one lists (rows,
// maxSeq, sha256 where printed, and byRun for usage_records). Across a schema change meta compares
// on rows only, since the migration sets schema_version and schema_digest.
// usage: node cmp.mjs A.json B.json. Prints one line per table and exits 1 if any differ.
import { readFileSync } from 'node:fs';
const [a, b] = process.argv.slice(2).map((p) => JSON.parse(readFileSync(p, 'utf8')));
const short = (h) => (h === undefined ? 'counts-only' : h.slice(0, 12));
let differ = 0;
for (const t of [...new Set([...Object.keys(a.tables), ...Object.keys(b.tables)])].sort()) {
const x = a.tables[t], y = b.tables[t];
if (!x || !y) { console.log(`DIFFER ${t}: only in ${x ? 'A' : 'B'}`); differ = 1; continue; }
const keys = t === 'meta' && a.schema !== b.schema ? ['rows'] : ['rows', 'maxSeq', 'sha256'];
const same = keys.every((k) => x[k] === y[k]) && JSON.stringify(x.byRun ?? null) === JSON.stringify(y.byRun ?? null);
console.log(`${same ? 'EQUAL' : 'DIFFER'} ${t}: rows ${x.rows}/${y.rows}, maxSeq ${x.maxSeq}/${y.maxSeq}, sha256 ${short(x.sha256)}/${short(y.sha256)}${keys.length === 1 ? ' (rows only across the schema change)' : ''}`);
if (!same) differ = 1;
}
console.log(`schema ${a.schema}/${b.schema}`);
process.exit(differ);
@@ -0,0 +1,22 @@
// P3, D3 (plan draft 7, mos-0899 A1): the stop decision from one snapshot.mjs --after --backup output.
// Prints stopTables, every table with priorSame or same false, every nonzero rowsAfter, every
// untimed table whose rows differ from the backup's, and eventsAfter. Counts and table names only.
// usage: node d3report.mjs D3.json (or the document on stdin). Exits 0 when stopTables is empty, 3 when it is not, 1 on a bad document.
import { readFileSync } from 'node:fs';
const s = JSON.parse(readFileSync(process.argv[2] ?? 0, "utf8"));
if (!Array.isArray(s.stopTables) || !s.tables || !Array.isArray(s.untimed)) {
console.log('D3 report: not a --backup snapshot');
process.exit(1);
}
const t = Object.entries(s.tables);
const changed = t.filter(([, x]) => x.vsBackup && (x.vsBackup.priorSame === false || x.vsBackup.same === false)).map(([n]) => n);
const after = t.filter(([, x]) => (x.rowsAfter ?? 0) > 0).map(([n, x]) => `${n} ${x.rowsAfter}`);
const untimed = s.untimed.filter((n) => s.tables[n].rows !== s.tables[n].vsBackup?.backupRows)
.map((n) => `${n} ${s.tables[n].vsBackup?.backupRows ?? 'absent'}->${s.tables[n].rows}`);
console.log(`D3 stopTables ${JSON.stringify(s.stopTables)}${s.onlyInBackup?.length ? `; only in the backup ${JSON.stringify(s.onlyInBackup)}` : ''}`);
console.log(`D3 priorSame or same false: ${changed.join(', ') || 'none'}`);
console.log(`D3 rowsAfter nonzero: ${after.join(', ') || 'none'}`);
console.log(`D3 untimed count differences (backup->now): ${untimed.join(', ') || 'none'}`);
console.log(`D3 eventsAfter ${s.eventsAfter}`);
console.log(s.stopTables.length ? 'D3 STOP (mos-0899 A1): stopTables is not empty; a real window stops here before the restore' : 'D3 stopTables empty: only events can have moved');
process.exit(s.stopTables.length ? 3 : 0);
@@ -0,0 +1,21 @@
# Sourced by every P3 script (merged window B+C, repin-merged-bc.md P3): the scratch root and a clean env for every call.
# NEW and TP come from the caller: NEW defaults to 8e888014d (row 175's push, the dry run); TP=1 adds the
# scratch tester port to W3, W5 and the Console checks once the row 176 tool blob is in NEW.
R=/home/jwoltje/darkwing-scratch/mbc/p3
B=$R/b
RB=$R/root
REPO=$R/repo
COPIES=$R/copies
OLD=5fa9cc8f2c66b52408b652b59c3070f7210b44d0
NEW=${NEW:-8e888014d4f4bbbe7f1e6fa598003c374c169856}
TP=${TP:-0}
PORT=47394
TPORT=47395
SNAP=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs
SNAP_SHA=639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67
LOGF=$R/out/p3-steps.log
# env -i keeps every live MOSAIC_*, XDG_*, credential and pi variable out; HOME is scratch too.
E=(env -i HOME=$RB/home PATH=$B:/usr/local/bin:/usr/bin:/bin TMPDIR=$RB/tmp LANG=C.UTF-8
MOSAIC_CONFIG=$RB/cfg/config.json XDG_CONFIG_HOME=$RB/xcfg XDG_DATA_HOME=$RB/xdata
XDG_STATE_HOME=$RB/xstate XDG_RUNTIME_DIR=$RB/run SD_STATE=$RB/sd SD_DATA=$RB/data)
step() { echo "$(date -u +%FT%TZ) $*" >> "$LOGF"; }
@@ -0,0 +1,7 @@
// The Console stand-in: 200 on /healthz, 404 otherwise, on 127.0.0.1:<port>, and on 127.0.0.1:<tester port>
// too when the unit's ExecStart has --tester-port (merged window P3). Writes healthz-<pid> once every port listens.
const http=require('node:http'),fs=require('node:fs'),path=require('node:path');
const ports=process.argv.slice(2).filter(Boolean).map(Number);let up=0;
for(const p of ports)http.createServer((q,r)=>{r.writeHead(q.url==='/healthz'?200:404);r.end(q.url==='/healthz'?'ok\n':'');})
.listen(p,'127.0.0.1',()=>{if(++up===ports.length)fs.writeFileSync(path.join(process.env.SD_STATE,`healthz-${process.pid}`),'');});
process.on('SIGTERM',()=>process.exit(0));
@@ -0,0 +1,6 @@
// P3: prints one field of a JSON document on stdin, by a dotted path (a.b.c); "" when absent.
// usage: node jget.mjs PATH < doc.json
import { readFileSync } from 'node:fs';
let v = JSON.parse(readFileSync(0, 'utf8'));
for (const k of process.argv[2].split('.')) v = v == null ? undefined : v[k];
process.stdout.write(v === undefined ? '' : typeof v === 'string' ? v : JSON.stringify(v));
@@ -0,0 +1,10 @@
#!/usr/bin/node
// Stand-in `journalctl --user -u UNIT --since @EPOCH -o cat` over $SD_STATE/journal.jsonl (the test's).
const fs=require('node:fs'),path=require('node:path');
const sd=process.env.SD_STATE,a=process.argv.slice(2);let unit='',since='';
for(let i=0;i<a.length;i++){if(a[i]==='-u')unit=a[++i];else if(a[i]==='--since')since=a[++i]}
fs.appendFileSync(path.join(sd,'journal-since.log'),since+'\n');
if(!/^@\d+$/.test(since))process.exit(1);
const from=Number(since.slice(1));
let lines=[];try{lines=fs.readFileSync(path.join(sd,'journal.jsonl'),'utf8').split('\n').filter(Boolean).map((l)=>JSON.parse(l))}catch{}
for(const o of lines)if(o.unit===unit&&o.epoch>=from)console.log(o.text);
@@ -0,0 +1,18 @@
// business-check-style load (repin-de352dfaf/business-check.mjs) of a scratch business file under COPY's own
// loader and roles. usage: node load-check.mjs COPY_DIR CONFIG_DIR. Prints counts, plug-in kinds, HOLDS lines, LOAD_OK or REFUSED.
const [copy, dir] = process.argv.slice(2);
const { loadBusiness } = await import(`${copy}/packages/business/src/business.mjs`);
const { resolveInstance } = await import(`${copy}/packages/business/src/resolve.mjs`);
try {
const b = loadBusiness('mosaic-stack', { dir, rolesDir: `${copy}/roles` });
const count = (o) => Object.keys(o ?? {}).length;
console.log(`copy ${copy.split('/').pop().slice(0, 9)}: roles ${count(b.roles)}, projects ${count(b.projects)}, arbiters ${count(b.arbiters)}, plugins ${JSON.stringify(b.plugins)}`);
for (const instance of ['chief', 'pm']) {
const { limits: { authority: a } } = resolveInstance({ system: {}, business: b, instance });
console.log(`HOLDS ${instance} instance.name ${[...a.withinRole, ...a.crossRole].includes('instance.name') ? 'yes' : 'no'}`);
}
console.log('LOAD_OK');
} catch (e) {
console.log(`REFUSED ${e.message}`);
process.exit(1);
}
@@ -0,0 +1,26 @@
// Scratch business file for P3: the committed example, made loadable, with the given plug-ins (mos-0847).
// Bot ids become distinct positive integers, date placeholders become 2027-01-01, every credential file
// points at a path under NOSECRET that does not exist, and both base URLs go to 127.0.0.1:9 (discard),
// so a scratch bus never reaches the live tracker or Gitea. As the live file (P1): `bus.tester` is true
// and every role's `harness` var is claude-code, the chief's included (row 169 finding 3).
// usage: node mkbiz.mjs EXAMPLE NOSECRET PLUGINS_JSON
import { readFileSync } from 'node:fs';
import { basename } from 'node:path';
const [example, nosecret, plugins] = process.argv.slice(2);
const b = JSON.parse(readFileSync(example, 'utf8'));
let id = 0;
const walk = (o) => {
for (const [k, v] of Object.entries(o)) {
if (k === 'botId') o[k] = ++id;
else if (v === 'YYYY-MM-DD') o[k] = '2027-01-01';
else if (k === 'file' && typeof v === 'string') o[k] = `${nosecret}/${basename(v)}`;
else if (v && typeof v === 'object') walk(v);
}
};
walk(b);
b.vars['tracker.baseUrl'] = 'http://127.0.0.1:9';
b.vars['gitea.baseUrl'] = 'http://127.0.0.1:9';
b.vars['bus.tester'] = true;
for (const role of Object.values(b.roles)) role.vars = { ...(role.vars ?? {}), harness: 'claude-code' };
b.plugins = JSON.parse(plugins);
process.stdout.write(JSON.stringify(b, null, 2) + '\n');
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# P3, prep: the tool clone at NEW, the two copies and the scratch business files. Scratch paths only; the
# canonical checkout is read through git clone --shared. Unlike queue-169, no patch is applied: the tool
# is NEW's own stack-release.sh, the day's tool blob.
set -euo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$REPO" ] && [ ! -e "$COPIES" ] && [ ! -e "$R/bfiles" ] || { echo "prep.sh: $R already has a repo, copies or bfiles" >&2; exit 1; }
mkdir -p "$R/out"
git clone -q --shared --no-checkout /mnt/storage/src/mosaic-stack "$REPO"
git -C "$REPO" checkout -q --detach "$NEW"
git -C "$REPO" branch -f refactor "$NEW"
step "tool clone $REPO at $(git -C "$REPO" rev-parse HEAD), refactor $(git -C "$REPO" rev-parse refactor); scripts/stack-release.sh blob $(git -C "$REPO" rev-parse HEAD:scripts/stack-release.sh); TP=$TP"
mkdir -p "$COPIES"
for c in "$OLD" "$NEW"; do (cd "$REPO" && scripts/stack-copy.sh copy "$c" --copies "$COPIES") >> "$LOGF" 2>&1; step "copy $c: exit 0"; done
mkdir -p "$R/bfiles/B/businesses" "$R/bfiles/H/businesses"
EX="$REPO/packages/business/examples/mosaic-stack.example.json"
step "example blob $(git -C "$REPO" hash-object "$EX")"
node "$B/mkbiz.mjs" "$EX" "$R/bfiles/nosecret" '{"usage-source":["transcript"],"channel":["cli","webui"]}' > "$R/bfiles/B/businesses/mosaic-stack.json"
node "$B/mkbiz.mjs" "$EX" "$R/bfiles/nosecret" '{"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}' > "$R/bfiles/H/businesses/mosaic-stack.json"
step "business B (Window A's plug-ins, no harness) $(sha256sum < "$R/bfiles/B/businesses/mosaic-stack.json" | cut -c1-64); H (harness [\"claude-code\"]) $(sha256sum < "$R/bfiles/H/businesses/mosaic-stack.json" | cut -c1-64)"
@@ -0,0 +1,256 @@
#!/usr/bin/env bash
# Merged window B+C, P3 (repin-merged-bc.md draft 3, sage-1112, sage-1117): the rehearsal on the root
# seed.sh made at OLD 5fa9cc8f2 and 3h. Order: the load checks, W1 and S1, W2, W3, W5 and a snapshot,
# W6 as the tester, W7 (PM launch emulated), S2, a P3-only name write after the backup stamp, then the
# rollback after W6: the refusal before the harness undo, harness null as the tester, OLD's load
# check, D3, rollback --restore --plan, the run without --events, the run with --events N from D3,
# and the end state against S1. Every stack-release call names the scratch --copies and --bin.
# Scratch paths only. TP=1 adds --tester-port $TPORT to W3 and W5 and checks it is dropped on the way back.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
OUT=$R/out/p3.txt
SN=$R/out/snap
[ ! -e "$OUT" ] || { echo "run.sh: $OUT exists" >&2; exit 1; }
[ -f "$RB/data/state/stack-active.json" ] || { echo "run.sh: no seeded root" >&2; exit 1; }
mkdir -p "$SN"
SR=(scripts/stack-release.sh)
CB=(--copies "$COPIES" --bin "$RB/bin")
TPF=(); [ "$TP" = 1 ] && TPF=(--tester-port "$TPORT")
C_OLD=(node "$COPIES/$OLD/packages/cli/src/cli.mjs")
C_NEW=(node "$COPIES/$NEW/packages/cli/src/cli.mjs")
DB=$RB/data/bus/bus.sqlite
part() { # part TITLE CMD... : one labeled part of the transcript, with its command and exit code
local title="$1"; shift
{ echo; echo "## $title"; echo "# command: (cd $REPO && <scratch env> $*)"; } >> "$OUT"
step "run: $*"
local rc=0; (cd "$REPO" && "${E[@]}" "$@") > "$R/out/last.txt" 2>&1 || rc=$?
cat "$R/out/last.txt" >> "$OUT"
echo "# exit $rc" >> "$OUT"; step "exit $rc"; RC=$rc
# mos-0902 (P19 391): a pm-on or rollback in the same second as the activate before it can refuse
# capture-failed. Wait a second and retry once; both attempts stay in the transcript.
if [ "$rc" != 0 ] && [ -z "${RETRIED:-}" ] && grep -qF 'refusing capture-failed' "$R/out/last.txt"; then
note "capture-failed on the first attempt (mos-0902); one retry after 1 s"
sleep 1; RETRIED=1 part "$title (retry after capture-failed)" "$@"
fi
}
note() { echo "# $*" >> "$OUT"; step "$*"; }
stop() { note "STOP: $*"; exit 1; }
expect() { [ "$RC" = "$1" ] || stop "expected exit $1, got $RC"; }
# The last part's output, less a plan's commits: block (its subject lines name refusal codes,
# 2fecddfba names tester-port-target), so has and lacks read only what the tool itself says.
body() { awk '/^commits:/{c=1;next} c && /^ /{next} {c=0;print}' "$R/out/last.txt"; }
has() { grep -qF -- "$1" <(body); } # the last part's output holds this text
lacks() { ! grep -qF -- "$1" <(body); }
lastlog() { tail -1 "$RB/data/state/stack-activation-log.jsonl"; }
pointer() { node "$B/jget.mjs" "$1" < "$RB/data/state/stack-active.json"; }
state() { # the pointer, the unit ExecStarts and the business file's plugins after a part
note "pointer: $(cat "$RB/data/state/stack-active.json")"
note "bus unit ExecStart: $(sed -n 's/^ExecStart=//p' "$RB/xcfg/systemd/user/[email protected]")"
note "Console unit ExecStart: $(sed -n 's/^ExecStart=//p' "$RB/xcfg/systemd/user/mosaic-webui.service")"
note "business file plugins: $(node -e 'console.log(JSON.stringify(require(process.argv[1]).plugins))' "$RB/cfg/businesses/mosaic-stack.json")"
note "activation log, last line: $(lastlog)"
}
snap() { # snap NAME ARGS... : snapshot.mjs on the scratch store, the output kept in out/snap/NAME.json
local name="$1"; shift
# plan draft 7 (mos-0899): sha256sum before every read; any copy but the one Mos approved refuses
local sha; sha="$(sha256sum "$SNAP" | cut -c1-64)"
note "snapshot.mjs sha256 before $name: $sha"
[ "$sha" = "$SNAP_SHA" ] || stop "snapshot.mjs is $sha, not the approved $SNAP_SHA; $name not run"
part "snapshot $name" node "$SNAP" --store "$DB" "$@"
cp "$R/out/last.txt" "$SN/$name.json"
}
same() { # same A B : the two snapshots match on every table
part "compare $1 with $2" node "$B/cmp.mjs" "$SN/$1.json" "$SN/$2.json"
}
plugins_read() { # the NEW copy's own mosaic plugins --tester --json, its output kept in out/NAME.json
part "$2" "${C_NEW[@]}" plugins --business mosaic-stack --tester --json
cp "$R/out/last.txt" "$R/out/$1.json"
}
plugins_set() { # plugins_set NAME VALUE_JSON TITLE: a patch with the revision of out/NAME-read.json, set as the tester
local rev; rev="$(node "$B/jget.mjs" revision < "$R/out/$1-read.json")"
[ -n "$rev" ] || stop "no revision in $1-read.json"
printf '{"revision":%s,"plugins":{"harness":%s}}\n' "$(node -e 'process.stdout.write(JSON.stringify(process.argv[1]))' "$rev")" "$2" > "$R/out/$1.json"
note "patch $1.json: $(cat "$R/out/$1.json")"
part "$3" "${C_NEW[@]}" plugins set --file "$R/out/$1.json" --business mosaic-stack --tester
}
receipt() { # the last organization receipt: transaction, actor, business, state, file sha256 before and after, changes
local f; f="$(find "$RB" -name changes.jsonl -path '*mosaic-stack*' | head -1)"
[ -n "$f" ] || stop "no changes.jsonl for mosaic-stack under $RB"
note "receipt file: ${f#$RB/}, $(wc -l < "$f") line(s)"
note "last receipt: $(tail -1 "$f" | node -e 'const o=JSON.parse(require("fs").readFileSync(0,"utf8"));console.log(JSON.stringify({transaction:o.transaction,actor:o.actor,business:o.business,state:o.state,before:o.before,after:o.after,changes:o.changes}))')"
}
markers() { # names only, never values: run markers in this shell's ancestors (the tester walk refuses them)
local p=$$ n=0
while [ "$p" -gt 1 ]; do
tr '\0' '\n' 2>/dev/null < "/proc/$p/environ" | grep -qE '^(MOSAIC_BUS_CAP|MOSAIC_RUN_ID|MOSAIC_AGENT_RUN)=.' && { echo "pid $p has a run marker"; n=$((n + 1)); }
p=$(awk '{print $4}' "/proc/$p/stat" 2>/dev/null) || break
done
echo "ancestors with a run marker: $n"
}
{
echo "# SCRATCH ROOT, NOT LIVE. Merged window B+C P3, run by darkwing from $(date -u +%FT%TZ) (sage-1112, sage-1117)."
echo "# Plan: agents/sage/work/window-plan/repin-merged-bc.md, sha256 $(sha256sum < /mnt/storage/src/mosaic-stack/agents/sage/work/window-plan/repin-merged-bc.md | cut -c1-64)."
echo "# Tool: $REPO, a git clone --shared of the canonical checkout at $(git -C "$REPO" rev-parse HEAD), nothing applied;"
echo "# scripts/stack-release.sh blob $(git -C "$REPO" rev-parse HEAD:scripts/stack-release.sh). refactor in the clone: $(git -C "$REPO" rev-parse refactor)."
echo "# Copies (stack-copy.sh copy): OLD $OLD, NEW $NEW. TP=$TP: $([ "$TP" = 1 ] && echo "W3 and W5 take --tester-port $TPORT" || echo "no --tester-port (the tool at this NEW predates row 176)")."
echo "# Root: $RB. Config $RB/cfg/config.json, data root $RB/data, units in $RB/xcfg/systemd/user."
echo "# Business file: the committed example (blob $(git -C "$REPO" hash-object packages/business/examples/mosaic-stack.example.json)) made loadable by mkbiz.mjs: plugins"
echo "# {\"usage-source\":[\"transcript\"],\"channel\":[\"cli\",\"webui\"]}, no harness, bus.tester true, every role's harness var claude-code;"
echo "# sha256 $(sha256sum < "$R/bfiles/B/businesses/mosaic-stack.json" | cut -c1-64)."
echo "# Store: seeded at 3h by OLD's Store before the bus first started (store-seed.mjs): 5 usage_records, 2 instance_names, 1 thread."
echo "# The harness set and its undo are the real NEW copy's mosaic plugins set --tester against the scratch bus, no stand-in."
echo "# snapshot.mjs: $SNAP, sha256 $(sha256sum < "$SNAP" | cut -c1-64) (expected $SNAP_SHA)."
echo "# Stand-ins ($B): systemctl runs the copy's real 'scripts/mosaic bus start mosaic-stack'. With pm-mode emulate a --pm"
echo "# start runs the bus WITHOUT --pm and EMULATES the PM launch: no claude runs; a waiting runner, one sessions.json entry"
echo "# and one 'launched chief' journal line stand in for it (no session credential goes to scratch). The Console is a"
echo "# /healthz stand-in on 127.0.0.1:$PORT, and on 127.0.0.1:$TPORT when the unit has --tester-port. journalctl and"
echo "# systemd-analyze are the test's; claude is a fixture that prints a version. Credential files are fake placeholders."
echo "# Environment for every call: env -i with HOME, PATH, TMPDIR, LANG, MOSAIC_CONFIG, XDG_* and SD_* only (names: $(printf '%s\n' "${E[@]:2}" | cut -d= -f1 | paste -sd' ' -))."
} > "$OUT"
step "--- run.sh"
[ "$(sha256sum < "$SNAP" | cut -c1-64)" = "$SNAP_SHA" ] || stop "snapshot.mjs is not the copy Mos read"
state
# --- the load checks (P1 shape, on the scratch file)
part "L1. business-check of OLD on a file that has harness (expect REFUSED unknown kind \"harness\")" node "$B/load-check.mjs" "$COPIES/$OLD" "$R/bfiles/H"
expect 1; has 'unknown kind "harness"' || stop 'no unknown kind "harness" refusal'
part "L2. control: NEW on the same file" node "$B/load-check.mjs" "$COPIES/$NEW" "$R/bfiles/H"; expect 0
part "L3. OLD on the rehearsal file" node "$B/load-check.mjs" "$COPIES/$OLD" "$RB/cfg"; expect 0
part "L4. NEW on the rehearsal file" node "$B/load-check.mjs" "$COPIES/$NEW" "$RB/cfg"; expect 0
part "L5. the P1 values of the rehearsal file" node -e '
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))}))' "$RB/cfg/businesses/mosaic-stack.json"
expect 0; has '"busTester":true' && has '"pluginKinds":["usage-source","channel"]' && has '"launchBy":"chief","chiefHarness":"claude-code","piRoles":[]' || stop "P1 values differ"
{ echo; echo "## L6. run markers in this shell's ancestors (names only; the tester walk refuses one)"; } >> "$OUT"
markers > "$R/out/last.txt"; cat "$R/out/last.txt" >> "$OUT"
has 'ancestors with a run marker: 0' || stop "a run marker above this shell; the tester proof would refuse"
# --- W1, S1, W2
part "W1a. agents as the tester (OLD's CLI; the chief must not be working)" "${C_OLD[@]}" agents --business mosaic-stack --tester --json
expect 0
part "W1b. launches list (OLD's CLI)" "${C_OLD[@]}" launches list --json; expect 0
note "W1 start stamp: $(date -u +%FT%TZ)"
snap S1 --held; expect 0
has '"schema": "3h"' || stop "S1 is not at 3h"
part "W2. status" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$OLD" ] && [ "$(pointer schema)" = 3h ] && [ -z "$(pointer pmPending)" ] || stop "W2: pointer not on OLD at 3h with no pending"
# --- W3, W5
part "W3. activate NEW --pm-after-harness --migrate ${TPF[*]} --plan" "${SR[@]}" activate "$NEW" mosaic-stack --pm-after-harness --migrate "${TPF[@]}" --plan "${CB[@]}"
expect 0
for c in pm-after-harness-target pm-after-harness-set unknown-kind-for-target tester-port-target; do lacks "$c" || stop "W3 names $c"; done
has '3h' && has '3i' && has '--migrate (given)' || stop "W3 plan lacks the 3h to 3i step or --migrate (given)"
[ "$TP" = 1 ] && { has "--tester-port $TPORT" || has "\"--tester-port\",\"$TPORT\"" || stop "W3 plan does not show --tester-port $TPORT in the Console flags"; }
cp "$R/out/last.txt" "$R/out/W3-plan.txt"
part "W5. activate NEW --pm-after-harness --migrate ${TPF[*]} (phase 1, migrates)" "${SR[@]}" activate "$NEW" mosaic-stack --pm-after-harness --migrate "${TPF[@]}" "${CB[@]}"
expect 0
state
ACT="$(lastlog | node "$B/jget.mjs" activation)"; BK="$(lastlog | node "$B/jget.mjs" backup)"
[ "$(lastlog | node "$B/jget.mjs" result)" = ok ] && [ -n "$ACT" ] && [ "$BK" = "$ACT" ] || stop "W5: last log line is not ok with this run's backup"
BDIR="$RB/data/backups/stack/$BK"; STAMP="$(cat "$BDIR/STAMP")"
note "W5 activation $ACT; backup $BDIR; STAMP $STAMP; SCHEMA $(cat "$BDIR/SCHEMA"); files: $(ls "$BDIR" | paste -sd' ' -)"
[ "$(cat "$BDIR/SCHEMA")" = 3h ] || stop "the backup is not at 3h"
# The tool writes the sums from inside bus/ and checks them there (stack-release.sh:337, :357 at blob adcb6847).
(cd "$BDIR/bus" && sha256sum -c --quiet ../SHA256SUMS) >> "$OUT" 2>&1 && note "backup SHA256SUMS: OK" || stop "backup SHA256SUMS does not check"
part "W5b. status (pending)" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$NEW" ] && [ "$(pointer schema)" = 3i ] && [ "$(pointer pm)" = false ] && [ "$(pointer pmPending)" = true ] || stop "W5: pointer not on NEW, 3i, pm false, pmPending true"
if [ "$TP" = 1 ]; then
pointer console | grep -qF "\"--tester-port\",\"$TPORT\"" || stop "W5: the pointer's Console flags lack --tester-port $TPORT"
(exec 3<>/dev/tcp/127.0.0.1/$TPORT) 2>/dev/null && note "tester port $TPORT listens (stand-in)" || stop "tester port $TPORT is closed"
fi
snap W5 --held; expect 0
has '"schema": "3i"' || stop "the store is not at 3i after W5"
same S1 W5; expect 0
# --- W6, W7, S2
plugins_read W6-read "W6a. plugins --tester --json (NEW's CLI), for the revision"; expect 0
plugins_set W6 '["claude-code"]' "W6b. plugins set harness [\"claude-code\"] as the tester"; expect 0
plugins_read W6-after "W6c. plugins read again"; expect 0
has '"harness": [' && has '"claude-code"' || stop "W6: harness is not [\"claude-code\"]"
node -e 'const a=require(process.argv[1]).plugins,b=require(process.argv[2]).plugins;process.exit(JSON.stringify(a["usage-source"])===JSON.stringify(b["usage-source"])&&JSON.stringify(a.channel)===JSON.stringify(b.channel)?0:1)' "$R/out/W6-read.json" "$R/out/W6-after.json" \
&& note "W6: usage-source and channel unchanged" || stop "W6: usage-source or channel changed"
receipt
tail -1 "$OUT" | grep -q '"actor":"tester","business":"mosaic-stack","state":"committed"' || stop "W6: the receipt is not a committed tester write"
part "W6d. business-check under NEW on the patched file" node "$B/load-check.mjs" "$COPIES/$NEW" "$RB/cfg"; expect 0
state
part "W7. pm-on (PM launch emulated)" "${SR[@]}" pm-on mosaic-stack "${CB[@]}"; expect 0
state
[ "$(pointer pm)" = true ] && [ -z "$(pointer pmPending)" ] || stop "W7: pointer is not pm true with no pmPending"
part "W7b. status after pm-on" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
part "W7c. launches list (NEW's CLI)" "${C_NEW[@]}" launches list --json
snap S2 --held; expect 0
same S1 S2; expect 0
# --- P3 only: one tester write after the backup stamp, so D3 has a row to count and the restore one to drop
part "X1. name chief p3-name-3 as the tester (P3 only, after the stamp)" "${C_NEW[@]}" name chief p3-name-3 --business mosaic-stack --tester
X1=$RC
# sage-1122: one write after the stamp that adds an event. At NEW the tester's successful writes
# (name.set, project.create) add none; a refused tester request does (broker.mjs request():
# #refused writes action.refused). name.set refuses the name "tester" with name-is-instance
# before it writes a row.
part "X2. name chief tester as the tester (expect refused name-is-instance, one action.refused event)" "${C_NEW[@]}" name chief tester --business mosaic-stack --tester
[ "$RC" != 0 ] && has name-is-instance || stop "X2 did not refuse name-is-instance"
# --- the rollback after W6
part "R0. rollback --restore $ACT --plan before the harness undo (expect unknown-kind-for-target)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --plan "${CB[@]}"
[ "$RC" != 0 ] && has unknown-kind-for-target || stop "R0 did not refuse unknown-kind-for-target"
plugins_read R1-read "R1a. plugins --tester --json, for the revision"; expect 0
plugins_set R1 'null' "R1b. plugins set harness null as the tester"; expect 0
plugins_read R1-after "R1c. plugins read again"; expect 0
lacks '"harness"' || stop "R1: harness is still set"
receipt
tail -1 "$OUT" | grep -q '"actor":"tester","business":"mosaic-stack","state":"committed"' || stop "R1: the receipt is not a committed tester write"
part "R2. business-check under OLD" node "$B/load-check.mjs" "$COPIES/$OLD" "$RB/cfg"; expect 0
# sage-1123: D3 reads every table against the backup's bus.sqlite. Any table but events in
# stopTables stops a real window before the restore, for Mos's go to name the rows dropped. P3
# notes it and goes on, so R4 and R5 still run.
snap D3 --held --after "$STAMP" --backup "$BDIR/bus/bus.sqlite"; expect 0
N="$(node "$B/jget.mjs" eventsAfter < "$SN/D3.json")"
D3STOP="$(node "$B/jget.mjs" stopTables < "$SN/D3.json")"
note "D3 after $STAMP (X1 exit $X1); untimed tables $(node "$B/jget.mjs" untimed < "$SN/D3.json")"
# plan draft 7: the stop is a non-empty stopTables (mos-0899 A1). The report adds every table with
# priorSame or same false, the nonzero rowsAfter, the untimed count differences and eventsAfter.
part "D3 report (stop on a non-empty stopTables)" node "$B/d3report.mjs" "$SN/D3.json"
[ "$RC" = 0 ] || [ "$RC" = 3 ] || stop "D3 report could not read the snapshot"
grep -qF '"instance_names"' <<< "$D3STOP" || stop "D3 stopTables does not name instance_names, which X1 wrote"
grep -qF '"events"' <<< "$D3STOP" && stop "D3 stopTables names events, which --events covers"
[ -n "$N" ] && [ "$N" -ge 1 ] || stop "D3 counted no events after the stamp; X2 should have added one"
part "R3. rollback --restore $ACT --plan" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --plan "${CB[@]}"; expect 0
[ "$TP" = 1 ] && { has 'tester-port' || stop "R3 plan does not say it drops --tester-port"; }
part "R4. rollback --restore $ACT without --events (expect post-backup-events when D3 counted any)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" "${CB[@]}"
# sage-1122: without --events the real run must refuse post-backup-events, and --events N must pass.
{
[ "$RC" != 0 ] && has post-backup-events || stop "R4 did not refuse post-backup-events"
M="$(sed -n 's/.*refusing post-backup-events: \([0-9][0-9]*\) event.*/\1/p' "$R/out/last.txt" | head -1)"
note "R4 refused with $M event(s); D3 counted $N"
[ "$M" = "$N" ] || note "FINDING: R4 counted $M event(s), D3 counted $N"
[ "$(pointer copy)" = "$NEW" ] && [ "$(pointer pm)" = true ] || stop "R4's refusal changed the pointer"
part "R5. rollback --restore $ACT --events $N (N from D3)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --events "$N" "${CB[@]}"
if [ "$RC" != 0 ] && has post-backup-events; then
M2="$(sed -n 's/.*refusing post-backup-events: \([0-9][0-9]*\) event.*/\1/p' "$R/out/last.txt" | head -1)"
note "FINDING: the event count moved between D3 ($N) and R5 ($M2); one rerun with --events $M2"
part "R5b. rollback --restore $ACT --events $M2" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --events "$M2" "${CB[@]}"
fi
expect 0
}
POST="$(sed -n 's/^restore: .*moves to \(.*\) and is kept;.*/\1/p' "$R/out/last.txt" | head -1)"
note "post-attempt store: ${POST:-(none named)}$([ -n "$POST" ] && [ -e "$POST" ] && echo ', present')"
state
# --- the end state
part "F1. status at the end" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$OLD" ] && [ "$(pointer schema)" = 3h ] && [ "$(pointer pm)" = true ] && [ -z "$(pointer pmPending)" ] || stop "F1: pointer not on OLD, 3h, pm true"
pointer console | grep -qF -- '--tester-port' && stop "F1: the pointer's Console flags still have --tester-port"
grep -qF -- '--tester-port' "$RB/xcfg/systemd/user/mosaic-webui.service" && stop "F1: the Console unit still has --tester-port"
(exec 3<>/dev/tcp/127.0.0.1/$TPORT) 2>/dev/null && stop "F1: tester port $TPORT still listens"
note "F1: pointer on OLD at 3h, pm true, no --tester-port in the pointer or the Console unit, port $TPORT closed"
snap F --held; expect 0
has '"schema": "3h"' || stop "the store is not back at 3h"
same S1 F; expect 0
part "F2. agents as the tester (OLD's CLI)" "${C_OLD[@]}" agents --business mosaic-stack --tester --json; expect 0
part "F3. launches list (OLD's CLI)" "${C_OLD[@]}" launches list --json; expect 0
note "P3: PASS"
echo "done: $OUT"
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# P3, seed: a scratch root at OLD 5fa9cc8f2 and 3h on stand-in units, with synthetic store rows written by
# OLD's Store before the bus first starts, then adopt. Real OLD bus host (PM launch emulated), healthz
# stand-in for the Console. Scratch paths only.
set -euo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$RB" ] || { echo "seed.sh: $RB exists; remove it first" >&2; exit 1; }
for p in $PORT $TPORT; do ! (exec 3<>/dev/tcp/127.0.0.1/$p) 2>/dev/null || { echo "seed.sh: port $p is in use" >&2; exit 1; }; done
mkdir -p "$RB"/{home,cfg/businesses,xcfg,xdata,xstate,run,sd,bin,tmp,data/notify/mosaic-stack}
chmod 700 "$RB/run"
echo emulate > "$RB/sd/pm-mode"
cat > "$RB/cfg/config.json" <<EOC
{"configVersion":1,"environment":"development","dataRoot":"$RB/data","execution":{"backend":"docker","provider":"zai","model":"glm-5.3-flash","adapter":"mock"}}
EOC
cp "$R/bfiles/B/businesses/mosaic-stack.json" "$RB/cfg/businesses/mosaic-stack.json"
printf '{"notifyVersion":1,"binding":null}' > "$RB/data/notify/mosaic-stack/notify.json"; chmod 600 "$RB/data/notify/mosaic-stack/notify.json"
step "root: $RB; business file $(sha256sum < "$RB/cfg/businesses/mosaic-stack.json" | cut -c1-64) (the example with usage-source transcript and channel cli,webui, no harness, bus.tester true, every role's harness var claude-code)"
# The broker refuses to boot unless every credential file in the business file exists, mode 0600. These are
# FAKE placeholder strings, not tokens; both base URLs in the file are 127.0.0.1:9.
NS="$R/bfiles/nosecret"; [ ! -e "$NS" ] || { echo "seed.sh: $NS exists; remove it first" >&2; exit 1; }
mkdir -m 700 "$NS"
for f in $(node -e 'const b=require(process.argv[1]);const o=[];(function w(x){if(x&&typeof x==="object")for(const[k,v]of Object.entries(x)){if(k==="file"&&typeof v==="string")o.push(v);w(v)}})(b);console.log(o.join(" "))' "$RB/cfg/businesses/mosaic-stack.json"); do
case "$f" in "$NS"/*) ;; *) echo "seed.sh: credential path outside $NS: $f" >&2; exit 1;; esac
printf 'scratch-fake-placeholder-%s\n' "$(basename "$f" .token)" > "$f"; chmod 600 "$f"
done
step "fake credential files: $(ls "$NS" | wc -l) under $NS, each 'scratch-fake-placeholder-<name>', mode 0600"
step "store seed: $(node "$B/store-seed.mjs" "$COPIES/$OLD" "$RB/data" 2>&1)"
printf '#!/usr/bin/env bash\n# mosaic-cli wrapper (Q81, agents/sage/work/q81/mosaic-cli.sh)\n[ "${1:-}" = __lease-capability ] && exec "%s/mosaic-old" "$@"\nexit 1\n' "$RB/bin" > "$RB/bin/mosaic"; chmod 755 "$RB/bin/mosaic"
run() { step "run: $*"; local rc=0; (cd "$REPO" && "${E[@]}" "$@") >> "$LOGF" 2>&1 || rc=$?; step "exit $rc"; return $rc; }
run scripts/bus-service.sh install --copy $OLD --copies "$COPIES" --pm --claude "$B/claude"
run systemctl --user start [email protected]
run scripts/webui-service.sh install --copy $OLD --copies "$COPIES" --port $PORT --business mosaic-stack
run systemctl --user start mosaic-webui.service
run scripts/stack-copy.sh wrapper $OLD --copies "$COPIES" --bin "$RB/bin"
run "$COPIES/$OLD/scripts/mosaic" bus status --json
run "$COPIES/$OLD/scripts/mosaic" launches list --json
run scripts/stack-release.sh adopt mosaic-stack --copies "$COPIES" --bin "$RB/bin"
run scripts/stack-release.sh status mosaic-stack --copies "$COPIES" --bin "$RB/bin" || true
step "pointer: $(cat "$RB/data/state/stack-active.json")"
@@ -0,0 +1,24 @@
// P3: synthetic rows in the scratch store before the OLD bus first starts, so S1, the migration, D3 and the
// restore have something to hash: usage records (a known end, a begin only, an unknown end), two instance
// names and a thread with a project. OLD's own Store writes them at 3h. Synthetic values only.
// usage: node store-seed.mjs OLD_COPY DATA_ROOT
import { pathToFileURL } from 'node:url';
const [old, root] = process.argv.slice(2);
const { Store, SCHEMA_VERSION } = await import(pathToFileURL(`${old}/packages/bus/src/store.mjs`).href);
if (SCHEMA_VERSION !== '3h') throw Error(`OLD is ${SCHEMA_VERSION}, not 3h`);
const s = new Store(root);
const u = (at, run, turn, phase, status, n, cursor) =>
s.run(`INSERT INTO usage_records(at,business,run,instance,provider,model,account,turn,source,phase,status,code,cursor,input,output,cache_write,cache_read)
VALUES (?,?,?,?,?,?,NULL,?,?,?,?,?,?,?,?,?,?)`, at, 'mosaic-stack', run, 'chief', 'anthropic', 'scratch-model', turn, 'transcript', phase, status,
status === 'unknown' ? 'no-new-usage' : null, cursor, ...(status === 'known' ? [n, n * 2, 0, n * 3] : [null, null, null, null]));
u('2026-10-19T10:00:00.000Z', 'p3-run-a', 't1', 'begin', 'known', 0, '{"offset":1}');
u('2026-10-19T10:00:05.000Z', 'p3-run-a', 't1', 'end', 'known', 1200, null);
u('2026-10-19T10:01:00.000Z', 'p3-run-a', 't2', 'begin', 'known', 0, '{"offset":2}');
u('2026-10-19T13:00:00.000Z', 'p3-run-b', 't1', 'begin', 'known', 0, '{"offset":3}');
u('2026-10-19T13:00:09.000Z', 'p3-run-b', 't1', 'end', 'unknown', 0, null);
s.run(`INSERT INTO instance_names(at,business,instance,name,by) VALUES (?,?,?,?,?)`, '2026-10-19T09:00:00.000Z', 'mosaic-stack', 'chief', 'p3-name-1', 'tester');
s.run(`INSERT INTO instance_names(at,business,instance,name,by) VALUES (?,?,?,?,?)`, '2026-10-19T14:00:00.000Z', 'mosaic-stack', 'chief', 'p3-name-2', 'tester');
s.run(`INSERT INTO projects(id,at,business,name,repo,created_by) VALUES (?,?,?,?,?,?)`, 'p3-proj', '2026-10-19T09:00:00.000Z', 'mosaic-stack', 'p3-project', null, 'tester');
s.run(`INSERT INTO threads(id,at,business,project,instance,owner,name) VALUES (?,?,?,?,?,?,?)`, 'p3-th1', '2026-10-19T09:30:00.000Z', 'mosaic-stack', 'p3-proj', 'chief', 'tester', 'p3-thread');
s.close();
console.log('seeded 5 usage_records, 2 instance_names, 1 project, 1 thread at 3h');
@@ -0,0 +1,136 @@
#!/usr/bin/node
// sage-1004/1006 Window B rehearsal: a stand-in `systemctl --user`, based on the one in
// packages/cli/tests/stack-release.test.mjs. Unit state lives in $SD_STATE/units.json and every call
// goes to calls.log. Unlike the test's holder, a bus start runs the copy's real
// `scripts/mosaic bus start <business>` from the unit's WorkingDirectory, without --pm and under this
// scratch environment. Its output becomes journal lines. With --pm in ExecStart, the PM launch is
// EMULATED: no claude runs. A scratch runner process stands in for the session, with one
// sessions.json entry and one `launched` journal line. A Console start runs a scratch /healthz
// server on the unit's --port. Nothing here reads or writes a live unit, store or journal.
// Row 169 rehearsal: when $SD_STATE/pm-mode holds "real", a bus start with --pm runs the unit's argv as
// it is, --pm included, so the copy's own launchPm runs (step 5). The start then waits up to 30 s more
// for the `launched` line or the bus exiting, and journals all of it. A bus that exited is "failed",
// as systemd shows a Type=simple unit whose main process exited 3 (RestartPreventExitStatus=2 3 4,
// so no restart). A `launched` line in real mode writes REAL-LAUNCH to pids.log; run.sh stops on it.
const fs = require('node:fs'), path = require('node:path'), cp = require('node:child_process');
const sd = process.env.SD_STATE, data = process.env.SD_DATA, unitDir = path.join(process.env.XDG_CONFIG_HOME, 'systemd', 'user');
const args = process.argv.slice(2).filter((a) => a !== '--user'), [verb, ...rest] = args;
fs.appendFileSync(path.join(sd, 'calls.log'), `${new Date().toISOString()} ${args.join(' ')}\n`);
const stFile = path.join(sd, 'units.json');
const load = () => { try { return JSON.parse(fs.readFileSync(stFile, 'utf8')); } catch { return {}; } };
const save = (s) => { fs.writeFileSync(stFile + '.tmp', JSON.stringify(s)); fs.renameSync(stFile + '.tmp', stFile); };
const sleep = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
const alive = (pid) => { try { const s = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); return s[s.lastIndexOf(')') + 2] !== 'Z'; } catch { return false; } };
const startTime = (pid) => { const s = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); return s.slice(s.lastIndexOf(')') + 2).split(' ')[19]; };
const isBus = (u) => /^mosaic-bus@[a-z0-9-]+\.service$/.test(u), inst = (u) => u.slice('mosaic-bus@'.length, -'.service'.length);
const journal = (unit, text) => fs.appendFileSync(path.join(sd, 'journal.jsonl'), JSON.stringify({ epoch: Math.floor(Date.now() / 1000), unit, text }) + '\n');
const unitFile = (u) => {
const main = isBus(u) ? '[email protected]' : u, file = path.join(unitDir, main);
if (!fs.existsSync(file)) return null;
const drops = [];
for (const d of isBus(u) ? [main + '.d', u + '.d'] : [u + '.d']) { const dir = path.join(unitDir, d); if (fs.existsSync(dir)) for (const f of fs.readdirSync(dir).sort()) if (f.endsWith('.conf')) drops.push(path.join(dir, f)); }
const r = { wd: '', exec: '', env: [], drops };
for (const f of [file, ...drops]) for (let line of fs.readFileSync(f, 'utf8').split('\n')) {
line = line.replace(/%i/g, isBus(u) ? inst(u) : '').replace(/%h/g, process.env.HOME);
const m = /^(WorkingDirectory|ExecStart|Environment)=(.*)$/.exec(line); if (!m) continue;
if (m[1] === 'WorkingDirectory') r.wd = m[2]; else if (m[1] === 'ExecStart') { if (m[2]) r.exec = m[2]; } else r.env.push(m[2]);
}
return r;
};
// Every fd above 2 is closed first, so no child holds stack-release.sh's lock (fd 9).
const CLOSE = 'for fd in /proc/self/fd/*; do n=${fd##*/}; [ "$n" -gt 2 ] && eval "exec $n>&-" 2>/dev/null; done; exec "$@"';
const spawnDetached = (argv, opts) => { const ch = cp.spawn('bash', ['-c', CLOSE, 'standin', ...argv], { detached: true, ...opts }); ch.unref(); return ch; };
const sessionsFile = path.join(data, 'bus-host', 'sessions.json');
const readSessions = () => { try { return JSON.parse(fs.readFileSync(sessionsFile, 'utf8')); } catch { return { sessionsVersion: 1, sessions: [] }; } };
const writeSessions = (doc) => { fs.mkdirSync(path.dirname(sessionsFile), { recursive: true, mode: 0o700 }); fs.writeFileSync(sessionsFile + '.tmp', JSON.stringify(doc, null, 2) + '\n', { mode: 0o600 }); fs.renameSync(sessionsFile + '.tmp', sessionsFile); };
if (verb === 'show') {
const u = rest[0], props = []; for (let i = 1; i < rest.length; i++) if (rest[i] === '-p') props.push(rest[++i]);
const f = unitFile(u), st = load()[u] || {};
for (const p of props) {
if (p === 'LoadState') console.log(`LoadState=${f ? 'loaded' : 'not-found'}`);
else if (p === 'WorkingDirectory') console.log(`WorkingDirectory=${f ? f.wd : ''}`);
else if (p === 'ExecStart') console.log(f && f.exec ? `ExecStart={ path=${f.exec.split(' ')[0]} ; argv[]=${f.exec} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }` : 'ExecStart=');
else if (p === 'Environment') console.log(`Environment=${f ? f.env.join(' ') : ''}`);
else if (p === 'MainPID') console.log(`MainPID=${st.state === 'active' && st.pid ? st.pid : 0}`);
else if (p === 'DropInPaths') console.log(`DropInPaths=${f ? f.drops.join(' ') : ''}`);
}
process.exit(0);
}
if (verb === 'is-active') { const q = rest[0] === '--quiet', u = q ? rest[1] : rest[0], st = load()[u] || {}; let s = st.state || 'inactive'; if (s === 'active' && st.pid && !alive(st.pid)) s = 'failed'; if (!q) console.log(s); process.exit(s === 'active' ? 0 : 3); }
if (verb === 'is-enabled') { console.log('disabled'); process.exit(1); }
if (verb === 'daemon-reload') process.exit(0);
if (verb === 'list-units') {
const pats = rest.filter((a) => !a.startsWith('--')).map((p) => new RegExp('^' + p.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$'));
for (const [u, s] of Object.entries(load())) if (pats.some((re) => re.test(u))) console.log(`${u} loaded ${s.state} ${s.state === 'active' ? 'running' : 'dead'} standin`);
process.exit(0);
}
if (verb === 'start') {
const u = rest[0], f = unitFile(u); if (!f) { console.error(`Unit ${u} not found.`); process.exit(5); }
const s = load();
if (!isBus(u)) {
const argv = f.exec.split(' '), i = argv.indexOf('--port'), port = i > 0 ? argv[i + 1] : '7332';
const t = argv.indexOf('--tester-port'), tport = t > 0 ? argv[t + 1] : '';
const ch = spawnDetached([process.execPath, path.join(__dirname, 'healthz.cjs'), port, tport], { stdio: 'ignore', cwd: sd });
fs.appendFileSync(path.join(sd, 'pids.log'), `healthz ${ch.pid}\n`);
const end = Date.now() + 10000;
while (!fs.existsSync(path.join(sd, `healthz-${ch.pid}`))) { if (Date.now() > end) { console.error('healthz stand-in did not start'); process.exit(1); } sleep(20); }
s[u] = { state: 'active', pid: ch.pid, wd: f.wd }; save(s); process.exit(0);
}
const argv = f.exec.split(' '), pm = argv.slice(1).includes('--pm');
let mode = 'emulate'; try { mode = fs.readFileSync(path.join(sd, 'pm-mode'), 'utf8').trim(); } catch {}
const realPm = pm && mode === 'real', real = realPm ? argv : argv.filter((a) => a !== '--pm');
const env = { ...process.env }; for (const e of f.env) { const k = e.slice(0, e.indexOf('=')); if (k === 'PATH' || k === 'MOSAIC_CLAUDE_BIN') env[k] = e.slice(k.length + 1); }
const out = path.join(sd, `bus-${Date.now()}.out`), fd = fs.openSync(out, 'a');
const ch = spawnDetached(real, { stdio: ['ignore', fd, fd], cwd: f.wd, env });
fs.closeSync(fd);
fs.appendFileSync(path.join(sd, 'pids.log'), `bus ${ch.pid} ${real.join(' ')} > ${out}\n`);
const end = Date.now() + 60000; let text = '';
while (!/^bus host up/m.test(text)) {
if (!alive(ch.pid) && realPm) { text = fs.readFileSync(out, 'utf8'); if (/^bus host up/m.test(text)) break; }
if (!alive(ch.pid)) { for (const l of text.split('\n').filter(Boolean)) journal(u, l); s[u] = { state: 'failed', pid: null, wd: f.wd }; save(s); console.error(`bus exited before host up; see ${out}`); process.exit(1); }
if (Date.now() > end) { console.error(`bus host up not seen in 60 s; see ${out}`); process.exit(1); }
sleep(100); text = fs.readFileSync(out, 'utf8');
}
if (realPm) {
const end3 = Date.now() + 30000;
while (!/^launched /m.test(text) && alive(ch.pid) && Date.now() < end3) { sleep(100); text = fs.readFileSync(out, 'utf8'); }
sleep(200); text = fs.readFileSync(out, 'utf8');
if (/^launched /m.test(text)) fs.appendFileSync(path.join(sd, 'pids.log'), `REAL-LAUNCH ${ch.pid}\n`);
}
for (const l of text.split('\n').filter(Boolean)) journal(u, l);
if (realPm) {
const up = alive(ch.pid);
fs.appendFileSync(path.join(sd, 'pids.log'), `real-pm ${ch.pid} ${up ? 'running' : 'exited'}\n`);
s[u] = up ? { state: 'active', pid: ch.pid, wd: f.wd, out, journaled: text.length } : { state: 'failed', pid: null, wd: f.wd };
save(s); process.exit(0);
}
s[u] = { state: 'active', pid: ch.pid, wd: f.wd, out, journaled: text.length };
if (pm) {
// The emulated PM launch: a runner that only waits, one sessions.json entry, one journal line.
const runner = spawnDetached([process.execPath, '-e', 'setInterval(()=>{},1<<30)'], { stdio: 'ignore', cwd: sd });
const end2 = Date.now() + 5000; while (!fs.existsSync(`/proc/${runner.pid}/stat`) && Date.now() < end2) sleep(10);
const run = `remul${runner.pid}`, b = inst(u);
const doc = readSessions(); doc.sessions.push({ run, business: b, instance: 'chief', harness: 'claude-code', model: 'emulated', launchedBy: 'standin-pm-emulation', runnerPid: runner.pid, runnerStartTime: startTime(runner.pid), startedAt: new Date().toISOString() }); writeSessions(doc);
journal(u, `launched chief: run ${run}, claude-code emulated`);
fs.appendFileSync(path.join(sd, 'pids.log'), `runner ${runner.pid} ${run}\n`);
s[u].runner = runner.pid; s[u].run = run;
}
save(s); process.exit(0);
}
if (verb === 'stop') {
const u = rest[0], s = load(), st = s[u];
if (st && st.pid) {
try { process.kill(st.pid, 'SIGTERM'); } catch {}
const end = Date.now() + 20000; while (alive(st.pid) && Date.now() < end) sleep(50);
if (alive(st.pid)) { fs.appendFileSync(path.join(sd, 'pids.log'), `SIGKILL ${st.pid}\n`); try { process.kill(st.pid, 'SIGKILL'); } catch {} }
if (st.out) { const text = fs.readFileSync(st.out, 'utf8'); for (const l of text.slice(st.journaled || 0).split('\n').filter(Boolean)) journal(u, l); }
}
if (st && st.runner) {
try { process.kill(st.runner, 'SIGTERM'); } catch {}
const doc = readSessions(); doc.sessions = doc.sessions.filter((x) => x.run !== st.run); writeSessions(doc);
}
if (st) { s[u] = { wd: st.wd, state: 'inactive', pid: null }; save(s); }
process.exit(0);
}
console.error(`stand-in systemctl: unsupported: ${args.join(' ')}`); process.exit(1);
@@ -0,0 +1,4 @@
#!/usr/bin/node
// Stand-in `systemd-analyze --user unit-paths` (the test's): only the scratch unit dir.
if(process.argv[2]!=='--user'||process.argv[3]!=='unit-paths')process.exit(1);
console.log(require('node:path').join(process.env.XDG_CONFIG_HOME,'systemd','user'));
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# P3: stops the scratch units through the stand-in, then confirms every PID it started is gone and the port is closed.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
T=$R/out/p3-teardown.txt
{
echo "# teardown $(date -u +%FT%TZ)"
for u in mosaic-webui.service [email protected]; do
(cd "$REPO" && "${E[@]}" systemctl --user stop "$u"); echo "stop $u exit $?"
done
left=0
while read -r kind pid _; do
if [ -e "/proc/$pid" ] && grep -q "$R" "/proc/$pid/cmdline" 2>/dev/null; then echo "ALIVE $kind $pid"; left=1; fi
done < <(grep -v "^REAL-LAUNCH\|^SIGKILL\|^real-pm" "$RB/sd/pids.log")
for p in /proc/[0-9]*; do c=$(readlink "$p/cwd" 2>/dev/null) || continue; case $c in "$R"*) case "$(tr "\0" " " < "$p/cmdline" 2>/dev/null)" in *b/all.sh*|*b/teardown.sh*) continue;; esac; echo "cwd-in-root ${p#/proc/} $c"; left=1;; esac; done
for p in $PORT $TPORT; do if (exec 3<>/dev/tcp/127.0.0.1/$p) 2>/dev/null; then echo "port $p open"; left=1; else echo "port $p closed"; fi; done
echo "left: $left"
} 2>&1 | tee "$T"
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Waits until busy.sh passes twice, 60 s apart, then runs all.sh, teed. Gives up after 90 minutes.
set -uo pipefail
end=$((SECONDS + 5400))
while :; do
if ~/darkwing-scratch/busy.sh > /dev/null; then
sleep 60
if ~/darkwing-scratch/busy.sh; then break; fi
fi
[ "$SECONDS" -lt "$end" ] || { echo "wait-run: still busy after 90 min"; exit 9; }
sleep 30
done
echo "wait-run: clear at $(date -u +%FT%TZ)"
/home/jwoltje/darkwing-scratch/mbc/p3/b/all.sh 2>&1 | tee /home/jwoltje/darkwing-scratch/mbc/p3/all-$(date -u +%Y%m%dT%H%M%SZ).log
exit "${PIPESTATUS[0]}"
@@ -0,0 +1,15 @@
addy-gen_default
bridge
compose-audit_default
host
jarvis-crypto_default
mage-ai_mage-network
mosaic-dev_default
mosaic-internal
mosaic-mono-v1_default
mosaic-public
neni-content-engine-dashboard_default
none
sage-phr-ng_sage-network
t205-directus_dd-internal
t205-payload_pl-internal
@@ -0,0 +1,15 @@
addy-gen_default
bridge
compose-audit_default
host
jarvis-crypto_default
mage-ai_mage-network
mosaic-dev_default
mosaic-internal
mosaic-mono-v1_default
mosaic-public
neni-content-engine-dashboard_default
none
sage-phr-ng_sage-network
t205-directus_dd-internal
t205-payload_pl-internal
@@ -0,0 +1,6 @@
# before prep, 2026-10-20T01:27:49Z
/home/jwoltje/.mosaic-dev/bus/bus.sqlite 1792446324
/home/jwoltje/.mosaic-dev/bus 1792446325
# after teardown, 2026-10-20T01:28:05Z
/home/jwoltje/.mosaic-dev/bus/bus.sqlite 1792446324
/home/jwoltje/.mosaic-dev/bus 1792446325
@@ -0,0 +1,257 @@
2026-10-20T01:27:50Z tool clone /home/jwoltje/darkwing-scratch/mbc/p3/repo at 89af38a83afa22a8a4f0d368a0a4030ad15a0efa, refactor 89af38a83afa22a8a4f0d368a0a4030ad15a0efa; scripts/stack-release.sh blob adcb68477c25822968ec9856add55a6a5f674355; TP=1
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 127 packages in 1s
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts @google/[email protected] (preinstall: echo 'preinstall: no-op')
npm warn install-scripts [email protected] (postinstall: node install.js)
npm warn install-scripts [email protected] (postinstall: node scripts/postinstall)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
copied: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
2026-10-20T01:27:51Z copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0: exit 0
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 127 packages in 1s
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts @google/[email protected] (preinstall: echo 'preinstall: no-op')
npm warn install-scripts [email protected] (postinstall: node install.js)
npm warn install-scripts [email protected] (postinstall: node scripts/postinstall)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
copied: /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa
2026-10-20T01:27:53Z copy 89af38a83afa22a8a4f0d368a0a4030ad15a0efa: exit 0
2026-10-20T01:27:53Z example blob 3a81ca0faea6d3dc3b29ae513c799497ed53f9d7
2026-10-20T01:27:53Z business B (Window A's plug-ins, no harness) c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32; H (harness ["claude-code"]) 486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a
2026-10-20T01:27:53Z root: /home/jwoltje/darkwing-scratch/mbc/p3/root; business file c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32 (the example with usage-source transcript and channel cli,webui, no harness, bus.tester true, every role's harness var claude-code)
2026-10-20T01:27:53Z fake credential files: 9 under /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/nosecret, each 'scratch-fake-placeholder-<name>', mode 0600
2026-10-20T01:27:53Z store seed: seeded 5 usage_records, 2 instance_names, 1 project, 1 thread at 3h
2026-10-20T01:27:53Z run: scripts/bus-service.sh install --copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --pm --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
written: /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user/[email protected]
claude: /home/jwoltje/darkwing-scratch/mbc/p3/b/claude (9.9.9 (Claude Code fixture))
daemon-reload done
next, for one business (one per data root):
mkdir -m 0700 -p <dataRoot>/notify/<business> the notifier refuses a looser directory
write <dataRoot>/notify/<business>/notify.json, mode 0600:
{"notifyVersion": 1, "binding": "<discord binding>"} or "binding": null for no DMs
systemctl --user enable --now mosaic-bus@<business> start now and at login
systemctl --user status mosaic-bus@<business>
journalctl --user -u mosaic-bus@<business> -f the host's log
systemctl --user stop mosaic-bus@<business> SIGTERM; restartable
survive logout and reboot only with lingering on: loginctl enable-linger jwoltje
2026-10-20T01:27:53Z exit 0
2026-10-20T01:27:53Z run: systemctl --user start [email protected]
2026-10-20T01:27:53Z exit 0
2026-10-20T01:27:53Z run: scripts/webui-service.sh install --copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
written: /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user/mosaic-webui.service
serve: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
daemon-reload done
this script starts nothing: the Console holds the human's capability. Jason
starts and restarts it, or Mos under lead decision 102 (sends then enter the
trail as Jason); no other agent does:
systemctl --user enable --now mosaic-webui start now and at login
systemctl --user status mosaic-webui
journalctl --user -u mosaic-webui -f the Console's log
systemctl --user stop mosaic-webui SIGTERM; restartable
scripts/webui-service.sh status unit state and /healthz
survive logout and reboot only with lingering on: loginctl enable-linger jwoltje
2026-10-20T01:27:53Z exit 0
2026-10-20T01:27:53Z run: systemctl --user start mosaic-webui.service
2026-10-20T01:27:53Z exit 0
2026-10-20T01:27:53Z run: scripts/stack-copy.sh wrapper 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
wrapper: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
2026-10-20T01:27:53Z exit 0
2026-10-20T01:27:53Z run: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus status --json
{
"host": {
"business": "mosaic-stack",
"pid": 1350318,
"startedAt": "2026-10-20T01:27:53.729Z",
"notifier": null,
"live": true
},
"socket": true,
"writerLock": {
"pid": 1350347,
"at": "2026-10-20T01:27:53.795Z",
"live": true
},
"boot": {
"ok": true,
"at": "2026-10-20T01:27:53.728Z",
"business": "mosaic-stack",
"file": "/home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json",
"reason": null,
"lastGood": "2026-10-20T01:27:53.728Z"
}
}
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic launches list --json
[
{
"run": "remul1350398",
"business": "mosaic-stack",
"instance": "chief",
"harness": "claude-code",
"model": "emulated",
"launchedBy": "standin-pm-emulation",
"runnerPid": 1350398,
"runnerStartTime": "56086405",
"startedAt": "2026-10-20T01:27:53.832Z",
"live": true
}
]
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: scripts/stack-release.sh adopt mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
adopted 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 for mosaic-stack (pm 1, schema 3h)
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
pointer: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/state/stack-active.json
{"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T012754Z-5fa9cc8f2c66","at":"2026-10-20T01:27:54Z"}
log (last five lines):
{"at":"2026-10-20T01:27:54Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T012754Z-5fa9cc8f2c66","result":"ok"}
check:
bus: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
Console: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
CLI: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
result: pass
bus status:
host: mosaic-stack, pid 1350318, running, since 2026-10-20T01:27:53.729Z, notifier off
socket: present
writer.lock: pid 1350347
boot: organization file loaded at 2026-10-20T01:27:53.728Z
unit flags: match the pointer
drift: 143 commit(s) on refactor since the pointer's copy
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T012754Z-5fa9cc8f2c66","at":"2026-10-20T01:27:54Z"}
2026-10-20T01:27:54Z --- run.sh
2026-10-20T01:27:54Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T012754Z-5fa9cc8f2c66","at":"2026-10-20T01:27:54Z"}
2026-10-20T01:27:54Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus start %i --pm
2026-10-20T01:27:54Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
2026-10-20T01:27:54Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
2026-10-20T01:27:54Z activation log, last line: {"at":"2026-10-20T01:27:54Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T012754Z-5fa9cc8f2c66","result":"ok"}
2026-10-20T01:27:54Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H
2026-10-20T01:27:54Z exit 1
2026-10-20T01:27:54Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: node -e
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))})) /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json
2026-10-20T01:27:54Z exit 0
2026-10-20T01:27:54Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs agents --business mosaic-stack --tester --json
2026-10-20T01:27:55Z exit 0
2026-10-20T01:27:55Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs launches list --json
2026-10-20T01:27:55Z exit 0
2026-10-20T01:27:55Z W1 start stamp: 2026-10-20T01:27:55Z
2026-10-20T01:27:55Z snapshot.mjs sha256 before S1: 639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67
2026-10-20T01:27:55Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held
2026-10-20T01:27:55Z exit 0
2026-10-20T01:27:55Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:27:55Z exit 0
2026-10-20T01:27:55Z run: scripts/stack-release.sh activate 89af38a83afa22a8a4f0d368a0a4030ad15a0efa mosaic-stack --pm-after-harness --migrate --tester-port 47395 --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:27:55Z exit 0
2026-10-20T01:27:55Z run: scripts/stack-release.sh activate 89af38a83afa22a8a4f0d368a0a4030ad15a0efa mosaic-stack --pm-after-harness --migrate --tester-port 47395 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:27:57Z exit 0
2026-10-20T01:27:57Z pointer: {"copy":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","business":"mosaic-stack","pm":false,"pmPending":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack","--tester-port","47395"],"schema":"3i","activation":"20261020T012756Z-89af38a83afa","at":"2026-10-20T01:27:57Z"}
2026-10-20T01:27:57Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/scripts/mosaic bus start %i
2026-10-20T01:27:57Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack --tester-port 47395
2026-10-20T01:27:57Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
2026-10-20T01:27:57Z activation log, last line: {"at":"2026-10-20T01:27:57Z","op":"activate","from":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","to":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","backup":"20261020T012756Z-89af38a83afa","activation":"20261020T012756Z-89af38a83afa","result":"ok","pm":"pending"}
2026-10-20T01:27:57Z W5 activation 20261020T012756Z-89af38a83afa; backup /home/jwoltje/darkwing-scratch/mbc/p3/root/data/backups/stack/20261020T012756Z-89af38a83afa; STAMP 2026-10-20T01:27:56.427Z; SCHEMA 3h; files: bus DATA_ROOT LISTING.txt MODES.txt ROLLBACK_SET SCHEMA SHA256SUMS SOURCE.sha256 STAMP
2026-10-20T01:27:57Z backup SHA256SUMS: OK
2026-10-20T01:27:57Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:27:57Z exit 0
2026-10-20T01:27:57Z tester port 47395 listens (stand-in)
2026-10-20T01:27:57Z snapshot.mjs sha256 before W5: 639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67
2026-10-20T01:27:57Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held
2026-10-20T01:27:57Z exit 0
2026-10-20T01:27:57Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/cmp.mjs /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/S1.json /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/W5.json
2026-10-20T01:27:57Z exit 0
2026-10-20T01:27:57Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs plugins --business mosaic-stack --tester --json
2026-10-20T01:27:58Z exit 0
2026-10-20T01:27:58Z patch W6.json: {"revision":"c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32","plugins":{"harness":["claude-code"]}}
2026-10-20T01:27:58Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs plugins set --file /home/jwoltje/darkwing-scratch/mbc/p3/out/W6.json --business mosaic-stack --tester
2026-10-20T01:27:58Z exit 0
2026-10-20T01:27:58Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs plugins --business mosaic-stack --tester --json
2026-10-20T01:27:58Z exit 0
2026-10-20T01:27:58Z W6: usage-source and channel unchanged
2026-10-20T01:27:58Z receipt file: cfg/businesses/.history/mosaic-stack/changes.jsonl, 2 line(s)
2026-10-20T01:27:58Z last receipt: {"transaction":"0850365f-8a4d-4ef0-b709-13b5956bf799","actor":"tester","business":"mosaic-stack","state":"committed","before":"c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32","after":"486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a","changes":[{"path":"plugins.harness","old":null,"new":["claude-code"],"oldPresent":false,"newPresent":true}]}
2026-10-20T01:27:58Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T01:27:58Z exit 0
2026-10-20T01:27:58Z pointer: {"copy":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","business":"mosaic-stack","pm":false,"pmPending":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack","--tester-port","47395"],"schema":"3i","activation":"20261020T012756Z-89af38a83afa","at":"2026-10-20T01:27:57Z"}
2026-10-20T01:27:58Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/scripts/mosaic bus start %i
2026-10-20T01:27:58Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack --tester-port 47395
2026-10-20T01:27:58Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}
2026-10-20T01:27:58Z activation log, last line: {"at":"2026-10-20T01:27:57Z","op":"activate","from":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","to":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","backup":"20261020T012756Z-89af38a83afa","activation":"20261020T012756Z-89af38a83afa","result":"ok","pm":"pending"}
2026-10-20T01:27:58Z run: scripts/stack-release.sh pm-on mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:27:59Z exit 0
2026-10-20T01:27:59Z pointer: {"copy":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack","--tester-port","47395"],"schema":"3i","activation":"20261020T012758Z-89af38a83afa","at":"2026-10-20T01:27:59Z"}
2026-10-20T01:27:59Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/scripts/mosaic bus start %i --pm
2026-10-20T01:27:59Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack --tester-port 47395
2026-10-20T01:27:59Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}
2026-10-20T01:27:59Z activation log, last line: {"at":"2026-10-20T01:27:59Z","op":"pm-on","from":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","to":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","backup":null,"activation":"20261020T012758Z-89af38a83afa","result":"ok","pm":"on"}
2026-10-20T01:27:59Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:28:00Z exit 0
2026-10-20T01:28:00Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs launches list --json
2026-10-20T01:28:00Z exit 0
2026-10-20T01:28:00Z snapshot.mjs sha256 before S2: 639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67
2026-10-20T01:28:00Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held
2026-10-20T01:28:00Z exit 0
2026-10-20T01:28:00Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/cmp.mjs /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/S1.json /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/S2.json
2026-10-20T01:28:00Z exit 0
2026-10-20T01:28:00Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs name chief p3-name-3 --business mosaic-stack --tester
2026-10-20T01:28:00Z exit 0
2026-10-20T01:28:00Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs name chief tester --business mosaic-stack --tester
2026-10-20T01:28:00Z exit 2
2026-10-20T01:28:00Z run: scripts/stack-release.sh rollback mosaic-stack --restore 20261020T012756Z-89af38a83afa --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:28:00Z exit 3
2026-10-20T01:28:00Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs plugins --business mosaic-stack --tester --json
2026-10-20T01:28:01Z exit 0
2026-10-20T01:28:01Z patch R1.json: {"revision":"486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a","plugins":{"harness":null}}
2026-10-20T01:28:01Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs plugins set --file /home/jwoltje/darkwing-scratch/mbc/p3/out/R1.json --business mosaic-stack --tester
2026-10-20T01:28:01Z exit 0
2026-10-20T01:28:01Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/89af38a83afa22a8a4f0d368a0a4030ad15a0efa/packages/cli/src/cli.mjs plugins --business mosaic-stack --tester --json
2026-10-20T01:28:01Z exit 0
2026-10-20T01:28:01Z receipt file: cfg/businesses/.history/mosaic-stack/changes.jsonl, 4 line(s)
2026-10-20T01:28:01Z last receipt: {"transaction":"737b2ac6-b029-4072-bc3d-e149cab48e0a","actor":"tester","business":"mosaic-stack","state":"committed","before":"486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a","after":"c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32","changes":[{"path":"plugins.harness","old":["claude-code"],"new":null,"oldPresent":true,"newPresent":false}]}
2026-10-20T01:28:01Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T01:28:01Z exit 0
2026-10-20T01:28:01Z snapshot.mjs sha256 before D3: 639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67
2026-10-20T01:28:01Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held --after 2026-10-20T01:27:56.427Z --backup /home/jwoltje/darkwing-scratch/mbc/p3/root/data/backups/stack/20261020T012756Z-89af38a83afa/bus/bus.sqlite
2026-10-20T01:28:01Z exit 0
2026-10-20T01:28:01Z D3 after 2026-10-20T01:27:56.427Z (X1 exit 0); untimed tables ["message_threads","meta","task_comment_cursors"]
2026-10-20T01:28:01Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/d3report.mjs /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/D3.json
2026-10-20T01:28:01Z exit 3
2026-10-20T01:28:01Z run: scripts/stack-release.sh rollback mosaic-stack --restore 20261020T012756Z-89af38a83afa --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:28:02Z exit 0
2026-10-20T01:28:02Z run: scripts/stack-release.sh rollback mosaic-stack --restore 20261020T012756Z-89af38a83afa --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:28:02Z exit 3
2026-10-20T01:28:02Z R4 refused with 1 event(s); D3 counted 1
2026-10-20T01:28:02Z run: scripts/stack-release.sh rollback mosaic-stack --restore 20261020T012756Z-89af38a83afa --events 1 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:28:04Z exit 0
2026-10-20T01:28:04Z post-attempt store: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus.post-attempt-20261020T012802Z, present
2026-10-20T01:28:04Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T012802Z-5fa9cc8f2c66","at":"2026-10-20T01:28:04Z"}
2026-10-20T01:28:04Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus start %i --pm
2026-10-20T01:28:04Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
2026-10-20T01:28:04Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
2026-10-20T01:28:04Z activation log, last line: {"at":"2026-10-20T01:28:04Z","op":"rollback","from":"89af38a83afa22a8a4f0d368a0a4030ad15a0efa","to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":"20261020T012756Z-89af38a83afa","activation":"20261020T012802Z-5fa9cc8f2c66","result":"ok"}
2026-10-20T01:28:04Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T01:28:04Z exit 0
2026-10-20T01:28:04Z F1: pointer on OLD at 3h, pm true, no --tester-port in the pointer or the Console unit, port 47395 closed
2026-10-20T01:28:04Z snapshot.mjs sha256 before F: 639fd28a2674aaa03ce824e3394b4052f21cdef7d6fa49bae61a9927ed341e67
2026-10-20T01:28:04Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held
2026-10-20T01:28:04Z exit 0
2026-10-20T01:28:04Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/cmp.mjs /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/S1.json /home/jwoltje/darkwing-scratch/mbc/p3/out/snap/F.json
2026-10-20T01:28:04Z exit 0
2026-10-20T01:28:04Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs agents --business mosaic-stack --tester --json
2026-10-20T01:28:05Z exit 0
2026-10-20T01:28:05Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs launches list --json
2026-10-20T01:28:05Z exit 0
2026-10-20T01:28:05Z P3: PASS
@@ -0,0 +1,7 @@
# teardown 2026-10-20T01:28:05Z
stop mosaic-webui.service exit 0
stop [email protected] exit 0
cwd-in-root 1358116 /home/jwoltje/darkwing-scratch/mbc/p3
port 47394 closed
port 47395 closed
left: 1
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,219 @@
{
"schema": "3i",
"backupSchema": "3h",
"tables": {
"decision_events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"decisions": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"deliveries": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"events": {
"rows": 1,
"maxSeq": 1,
"sha256": "15eff14f9f26864e391ae2bfa5961314513e0e5280efb0b847c0e49b1f1d788b",
"rowsAfter": 1,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 1,
"priorSame": true
}
},
"instance_names": {
"rows": 3,
"maxSeq": 3,
"sha256": "1cc8f63b7f9d88e92192b5c3f252bcc906aba1d6f15b933b9d36e8cc799e67a7",
"rowsAfter": 1,
"vsBackup": {
"backupRows": 2,
"backupMaxSeq": 2,
"newRows": 1,
"priorSame": true
}
},
"message_threads": {
"rows": 0,
"maxSeq": null,
"vsBackup": {
"backupRows": 0,
"same": true
}
},
"messages": {
"rows": 0,
"maxSeq": null,
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"meta": {
"rows": 3,
"maxSeq": null,
"sha256": "614990a87c5e4222e36e5b73025c22e337a6090dfa8c2444f3c1e39832843086",
"vsBackup": {
"backupRows": 3,
"keysChanged": [
"schema_digest",
"schema_version"
]
}
},
"projects": {
"rows": 1,
"maxSeq": 1,
"sha256": "39bc340a4b5a88f52f7c927e19c16887dbbe79bfd69b88eec1a0f07ab726af3f",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 1,
"backupMaxSeq": 1,
"newRows": 0,
"priorSame": true
}
},
"role_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"task_comment_cursors": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"task_snapshots": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"thread_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"thread_opens": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 0,
"backupMaxSeq": null,
"newRows": 0,
"priorSame": true
}
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "79cc060fc8127eb8ae899e6951608a69af3e8cd5ff4fab4503d3a4481c6eb348",
"rowsAfter": 0,
"vsBackup": {
"backupRows": 1,
"backupMaxSeq": 1,
"newRows": 0,
"priorSame": true
}
},
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"rowsAfter": 0,
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
],
"vsBackup": {
"backupRows": 5,
"backupMaxSeq": 5,
"newRows": 0,
"priorSame": true
}
}
},
"untimed": [
"message_threads",
"meta",
"task_comment_cursors"
],
"onlyInBackup": [],
"stopTables": [
"instance_names"
],
"after": "2026-10-20T01:27:56.427Z",
"eventsAfter": 1
}
@@ -0,0 +1,104 @@
{
"schema": "3h",
"tables": {
"decision_events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"decisions": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"deliveries": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "c460ba76e52eeb4c5870eef177bdab666db7b6ed76a53729b08025ce9cae6459"
},
"message_threads": {
"rows": 0,
"maxSeq": null
},
"messages": {
"rows": 0,
"maxSeq": null
},
"meta": {
"rows": 3,
"maxSeq": null,
"sha256": "ca899a3308cb5912c30ecf4160c8a1a0da41ed72c8f8ef2f10c1b6748205c9b3"
},
"projects": {
"rows": 1,
"maxSeq": 1,
"sha256": "39bc340a4b5a88f52f7c927e19c16887dbbe79bfd69b88eec1a0f07ab726af3f"
},
"role_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_comment_cursors": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_snapshots": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_opens": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "79cc060fc8127eb8ae899e6951608a69af3e8cd5ff4fab4503d3a4481c6eb348"
},
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
}
},
"untimed": [
"message_threads",
"meta",
"task_comment_cursors"
]
}
@@ -0,0 +1,104 @@
{
"schema": "3h",
"tables": {
"decision_events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"decisions": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"deliveries": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "c460ba76e52eeb4c5870eef177bdab666db7b6ed76a53729b08025ce9cae6459"
},
"message_threads": {
"rows": 0,
"maxSeq": null
},
"messages": {
"rows": 0,
"maxSeq": null
},
"meta": {
"rows": 3,
"maxSeq": null,
"sha256": "ca899a3308cb5912c30ecf4160c8a1a0da41ed72c8f8ef2f10c1b6748205c9b3"
},
"projects": {
"rows": 1,
"maxSeq": 1,
"sha256": "39bc340a4b5a88f52f7c927e19c16887dbbe79bfd69b88eec1a0f07ab726af3f"
},
"role_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_comment_cursors": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_snapshots": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_opens": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "79cc060fc8127eb8ae899e6951608a69af3e8cd5ff4fab4503d3a4481c6eb348"
},
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
}
},
"untimed": [
"message_threads",
"meta",
"task_comment_cursors"
]
}
@@ -0,0 +1,104 @@
{
"schema": "3i",
"tables": {
"decision_events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"decisions": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"deliveries": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "c460ba76e52eeb4c5870eef177bdab666db7b6ed76a53729b08025ce9cae6459"
},
"message_threads": {
"rows": 0,
"maxSeq": null
},
"messages": {
"rows": 0,
"maxSeq": null
},
"meta": {
"rows": 3,
"maxSeq": null,
"sha256": "614990a87c5e4222e36e5b73025c22e337a6090dfa8c2444f3c1e39832843086"
},
"projects": {
"rows": 1,
"maxSeq": 1,
"sha256": "39bc340a4b5a88f52f7c927e19c16887dbbe79bfd69b88eec1a0f07ab726af3f"
},
"role_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_comment_cursors": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_snapshots": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_opens": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "79cc060fc8127eb8ae899e6951608a69af3e8cd5ff4fab4503d3a4481c6eb348"
},
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
}
},
"untimed": [
"message_threads",
"meta",
"task_comment_cursors"
]
}
@@ -0,0 +1,104 @@
{
"schema": "3i",
"tables": {
"decision_events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"decisions": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"deliveries": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"events": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "c460ba76e52eeb4c5870eef177bdab666db7b6ed76a53729b08025ce9cae6459"
},
"message_threads": {
"rows": 0,
"maxSeq": null
},
"messages": {
"rows": 0,
"maxSeq": null
},
"meta": {
"rows": 3,
"maxSeq": null,
"sha256": "614990a87c5e4222e36e5b73025c22e337a6090dfa8c2444f3c1e39832843086"
},
"projects": {
"rows": 1,
"maxSeq": 1,
"sha256": "39bc340a4b5a88f52f7c927e19c16887dbbe79bfd69b88eec1a0f07ab726af3f"
},
"role_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_comment_cursors": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"task_snapshots": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_claims": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"thread_opens": {
"rows": 0,
"maxSeq": null,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "79cc060fc8127eb8ae899e6951608a69af3e8cd5ff4fab4503d3a4481c6eb348"
},
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
}
},
"untimed": [
"message_threads",
"meta",
"task_comment_cursors"
]
}
@@ -0,0 +1,24 @@
9cbf9a23e41e546a6b92a3403ee800e6e325ca5c9065e9580fd3678c304dd979 ./b/all.sh
6b25b038e3d7f4d12d169613a6f7e214d2c4f69e34fb98d446f4adad3876e44d ./b/claude
4f9dffbf3d6e75e14b19f8d4ef45b390e4997cccc61caa9323cf822ffed4c58c ./b/cmp.mjs
0b9147124dbef220a2a17c647b2f9582155ff25c5ee3712378ef2d07c978ba66 ./b/env.sh
89c201e59d7bb6427041734757d170df7c9b39d96d8cb680a57fbb9eff5ab5aa ./b/healthz.cjs
fb1f19bb5a464d575ffdeb133a9a2df7fdf507218e683fddaaa170280d5c9fed ./b/jget.mjs
e1dcabdd3e43cae6f885a44fc1fe357406c00d896c03fff889f8b61dd4e15683 ./b/journalctl
2aed6b4762c6f48cd338f15134822118dddac9ce6246ef5c4fc9faff6f80178e ./b/load-check.mjs
dc9ebad483d55f8016b73d6fb36a7b6e6d7921bc052a605aeabec8a650136ed0 ./b/mkbiz.mjs
7a0821f59d23d318d7d2d5a24b24f774548acc25c31da15d92566e9d6c614f42 ./b/prep.sh
735021443468aba9d89c6a63c8d643982713d90b7bc9e386d0b659cad5de776d ./b/run.sh
073f1952e35f464fe26fa9c86161b322c3f10f20814128b000b9c368e5c9de2a ./b/seed.sh
98d10dc85c7ea32e032529935d2cf39b4d63196e5e7ab05bd4332b43833e88fb ./b/store-seed.mjs
e3669292be33f8b8298d9d1a00ba19e5ca42e3b50fc995007c9fc4587d0df6cd ./b/systemctl
30908331d33adead6e32b9da5b77ca29283f42446636527946541618331dc8a2 ./b/systemd-analyze
6e9494e2b4f306ca2320f0cc274d9d4aeb925c73cc94a9c678f607a2b14667ed ./b/teardown.sh
0a4884269bd5914075294e803262078bd7aa12c8b8e119b1aa7b8d58fb8c5f72 ./b/wait-run.sh
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-after.txt
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-before.txt
f90d3862e96f8f9eed3d32f9deccf3604bcbeeb422a22ee3648095885e93e1af ./p3-live-store-stat.txt
02e7f9ec7ae54b9c5871f81f38091e9e22095f947433457a29bd8e294a85b35c ./p3-steps.log
09c833966c5b2a07e0b8dc7a96000008e9c5aa64c671ba59e1b31446f913be1d ./p3-teardown.txt
dedca266a18176e870c56faec2e3a62547124de079d71ec2131ef87c1eaa2583 ./p3.txt
9e3ee240b117169fe3f252fc6b4f6834c7bf5629015a5f00764a18f44aa7bd60 ./snap/S1.json
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# P3 driver: the live-store stat (mos-0878), prep, seed, run, teardown, the stat again, the Docker network
# names before and after, then the outputs copied to $WIN/p3 with SHA256SUMS. Started only behind
# wait-run.sh (busy.sh) on Sage's go. NEW=<sha> TP=1 for the run on the row 176 tool blob.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$R/out" ] || { echo "all.sh: $R/out exists; move it aside first" >&2; exit 1; }
mkdir -p "$R/out"
S=$R/out/p3-live-store-stat.txt
LIVE=(/home/jwoltje/.mosaic-dev/bus/bus.sqlite /home/jwoltje/.mosaic-dev/bus)
{ echo "# before prep, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } > "$S"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-before.txt"
rc=0
"$B/prep.sh" && "$B/seed.sh" && "$B/run.sh" || rc=$?
"$B/teardown.sh"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-after.txt"
{ echo "# after teardown, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } >> "$S"
cat "$S"
if [ "$(sed -n 2,3p "$S")" = "$(sed -n 5,6p "$S")" ]; then echo "live store stat: match"; else echo "live store stat: DIFFER"; rc=1; fi
if cmp -s "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; then echo "docker networks: unchanged"; else echo "docker networks: CHANGED"; diff "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; fi
echo "all.sh: run exit $rc"
W=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/p3/$(git -C "$REPO" rev-parse --short=9 HEAD)-tp$TP
mkdir -p "$W" && cp -p "$R"/out/*.txt "$R"/out/*.json "$R/out/p3-steps.log" "$W"/ 2>/dev/null; cp -pr "$R/out/snap" "$W"/
cp -p "$B"/*.sh "$B"/*.mjs "$B"/*.cjs "$B"/systemctl "$B"/journalctl "$B"/systemd-analyze "$B"/claude "$W"/ 2>/dev/null; mkdir -p "$W/b" && mv "$W"/*.sh "$W"/*.mjs "$W"/*.cjs "$W"/systemctl "$W"/journalctl "$W"/systemd-analyze "$W"/claude "$W/b"/ 2>/dev/null
rm -f "$W/last.txt"
(cd "$W" && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS)
echo "outputs: $W ($(wc -l < "$W/SHA256SUMS") files, SHA256SUMS sha256 $(sha256sum < "$W/SHA256SUMS" | cut -c1-64))"
exit $rc
@@ -0,0 +1,3 @@
#!/bin/sh
# Fake claude for the scratch rehearsal. It never runs a model; the PM launch is emulated.
echo "9.9.9 (Claude Code fixture)"
@@ -0,0 +1,13 @@
// P3: compares two snapshot.mjs outputs table by table (rows, maxSeq, sha256, and byRun for usage_records).
// usage: node cmp.mjs A.json B.json. Prints one line per table and exits 1 if any differ.
import { readFileSync } from 'node:fs';
const [a, b] = process.argv.slice(2).map((p) => JSON.parse(readFileSync(p, 'utf8')));
let differ = 0;
for (const t of ['usage_records', 'instance_names', 'threads']) {
const x = a.tables[t], y = b.tables[t];
const same = ['rows', 'maxSeq', 'sha256'].every((k) => x[k] === y[k]) && JSON.stringify(x.byRun ?? null) === JSON.stringify(y.byRun ?? null);
console.log(`${same ? 'EQUAL' : 'DIFFER'} ${t}: rows ${x.rows}/${y.rows}, maxSeq ${x.maxSeq}/${y.maxSeq}, sha256 ${x.sha256.slice(0, 12)}/${y.sha256.slice(0, 12)}`);
if (!same) differ = 1;
}
console.log(`schema ${a.schema}/${b.schema}`);
process.exit(differ);
@@ -0,0 +1,21 @@
# Sourced by every P3 script (merged window B+C, repin-merged-bc.md P3): the scratch root and a clean env for every call.
# NEW and TP come from the caller: NEW defaults to 8e888014d (row 175's push, the dry run); TP=1 adds the
# scratch tester port to W3, W5 and the Console checks once the row 176 tool blob is in NEW.
R=/home/jwoltje/darkwing-scratch/mbc/p3
B=$R/b
RB=$R/root
REPO=$R/repo
COPIES=$R/copies
OLD=5fa9cc8f2c66b52408b652b59c3070f7210b44d0
NEW=${NEW:-8e888014d4f4bbbe7f1e6fa598003c374c169856}
TP=${TP:-0}
PORT=47394
TPORT=47395
SNAP=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs
SNAP_SHA=909a11f65c42de1dec6776a55585ad01ed960d25ff827c6b298b3293fbe46406
LOGF=$R/out/p3-steps.log
# env -i keeps every live MOSAIC_*, XDG_*, credential and pi variable out; HOME is scratch too.
E=(env -i HOME=$RB/home PATH=$B:/usr/local/bin:/usr/bin:/bin TMPDIR=$RB/tmp LANG=C.UTF-8
MOSAIC_CONFIG=$RB/cfg/config.json XDG_CONFIG_HOME=$RB/xcfg XDG_DATA_HOME=$RB/xdata
XDG_STATE_HOME=$RB/xstate XDG_RUNTIME_DIR=$RB/run SD_STATE=$RB/sd SD_DATA=$RB/data)
step() { echo "$(date -u +%FT%TZ) $*" >> "$LOGF"; }
@@ -0,0 +1,7 @@
// The Console stand-in: 200 on /healthz, 404 otherwise, on 127.0.0.1:<port>, and on 127.0.0.1:<tester port>
// too when the unit's ExecStart has --tester-port (merged window P3). Writes healthz-<pid> once every port listens.
const http=require('node:http'),fs=require('node:fs'),path=require('node:path');
const ports=process.argv.slice(2).filter(Boolean).map(Number);let up=0;
for(const p of ports)http.createServer((q,r)=>{r.writeHead(q.url==='/healthz'?200:404);r.end(q.url==='/healthz'?'ok\n':'');})
.listen(p,'127.0.0.1',()=>{if(++up===ports.length)fs.writeFileSync(path.join(process.env.SD_STATE,`healthz-${process.pid}`),'');});
process.on('SIGTERM',()=>process.exit(0));
@@ -0,0 +1,6 @@
// P3: prints one field of a JSON document on stdin, by a dotted path (a.b.c); "" when absent.
// usage: node jget.mjs PATH < doc.json
import { readFileSync } from 'node:fs';
let v = JSON.parse(readFileSync(0, 'utf8'));
for (const k of process.argv[2].split('.')) v = v == null ? undefined : v[k];
process.stdout.write(v === undefined ? '' : typeof v === 'string' ? v : JSON.stringify(v));
@@ -0,0 +1,10 @@
#!/usr/bin/node
// Stand-in `journalctl --user -u UNIT --since @EPOCH -o cat` over $SD_STATE/journal.jsonl (the test's).
const fs=require('node:fs'),path=require('node:path');
const sd=process.env.SD_STATE,a=process.argv.slice(2);let unit='',since='';
for(let i=0;i<a.length;i++){if(a[i]==='-u')unit=a[++i];else if(a[i]==='--since')since=a[++i]}
fs.appendFileSync(path.join(sd,'journal-since.log'),since+'\n');
if(!/^@\d+$/.test(since))process.exit(1);
const from=Number(since.slice(1));
let lines=[];try{lines=fs.readFileSync(path.join(sd,'journal.jsonl'),'utf8').split('\n').filter(Boolean).map((l)=>JSON.parse(l))}catch{}
for(const o of lines)if(o.unit===unit&&o.epoch>=from)console.log(o.text);
@@ -0,0 +1,18 @@
// business-check-style load (repin-de352dfaf/business-check.mjs) of a scratch business file under COPY's own
// loader and roles. usage: node load-check.mjs COPY_DIR CONFIG_DIR. Prints counts, plug-in kinds, HOLDS lines, LOAD_OK or REFUSED.
const [copy, dir] = process.argv.slice(2);
const { loadBusiness } = await import(`${copy}/packages/business/src/business.mjs`);
const { resolveInstance } = await import(`${copy}/packages/business/src/resolve.mjs`);
try {
const b = loadBusiness('mosaic-stack', { dir, rolesDir: `${copy}/roles` });
const count = (o) => Object.keys(o ?? {}).length;
console.log(`copy ${copy.split('/').pop().slice(0, 9)}: roles ${count(b.roles)}, projects ${count(b.projects)}, arbiters ${count(b.arbiters)}, plugins ${JSON.stringify(b.plugins)}`);
for (const instance of ['chief', 'pm']) {
const { limits: { authority: a } } = resolveInstance({ system: {}, business: b, instance });
console.log(`HOLDS ${instance} instance.name ${[...a.withinRole, ...a.crossRole].includes('instance.name') ? 'yes' : 'no'}`);
}
console.log('LOAD_OK');
} catch (e) {
console.log(`REFUSED ${e.message}`);
process.exit(1);
}
@@ -0,0 +1,26 @@
// Scratch business file for P3: the committed example, made loadable, with the given plug-ins (mos-0847).
// Bot ids become distinct positive integers, date placeholders become 2027-01-01, every credential file
// points at a path under NOSECRET that does not exist, and both base URLs go to 127.0.0.1:9 (discard),
// so a scratch bus never reaches the live tracker or Gitea. As the live file (P1): `bus.tester` is true
// and every role's `harness` var is claude-code, the chief's included (row 169 finding 3).
// usage: node mkbiz.mjs EXAMPLE NOSECRET PLUGINS_JSON
import { readFileSync } from 'node:fs';
import { basename } from 'node:path';
const [example, nosecret, plugins] = process.argv.slice(2);
const b = JSON.parse(readFileSync(example, 'utf8'));
let id = 0;
const walk = (o) => {
for (const [k, v] of Object.entries(o)) {
if (k === 'botId') o[k] = ++id;
else if (v === 'YYYY-MM-DD') o[k] = '2027-01-01';
else if (k === 'file' && typeof v === 'string') o[k] = `${nosecret}/${basename(v)}`;
else if (v && typeof v === 'object') walk(v);
}
};
walk(b);
b.vars['tracker.baseUrl'] = 'http://127.0.0.1:9';
b.vars['gitea.baseUrl'] = 'http://127.0.0.1:9';
b.vars['bus.tester'] = true;
for (const role of Object.values(b.roles)) role.vars = { ...(role.vars ?? {}), harness: 'claude-code' };
b.plugins = JSON.parse(plugins);
process.stdout.write(JSON.stringify(b, null, 2) + '\n');
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# P3, prep: the tool clone at NEW, the two copies and the scratch business files. Scratch paths only; the
# canonical checkout is read through git clone --shared. Unlike queue-169, no patch is applied: the tool
# is NEW's own stack-release.sh, the day's tool blob.
set -euo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$REPO" ] && [ ! -e "$COPIES" ] && [ ! -e "$R/bfiles" ] || { echo "prep.sh: $R already has a repo, copies or bfiles" >&2; exit 1; }
mkdir -p "$R/out"
git clone -q --shared --no-checkout /mnt/storage/src/mosaic-stack "$REPO"
git -C "$REPO" checkout -q --detach "$NEW"
git -C "$REPO" branch -f refactor "$NEW"
step "tool clone $REPO at $(git -C "$REPO" rev-parse HEAD), refactor $(git -C "$REPO" rev-parse refactor); scripts/stack-release.sh blob $(git -C "$REPO" rev-parse HEAD:scripts/stack-release.sh); TP=$TP"
mkdir -p "$COPIES"
for c in "$OLD" "$NEW"; do (cd "$REPO" && scripts/stack-copy.sh copy "$c" --copies "$COPIES") >> "$LOGF" 2>&1; step "copy $c: exit 0"; done
mkdir -p "$R/bfiles/B/businesses" "$R/bfiles/H/businesses"
EX="$REPO/packages/business/examples/mosaic-stack.example.json"
step "example blob $(git -C "$REPO" hash-object "$EX")"
node "$B/mkbiz.mjs" "$EX" "$R/bfiles/nosecret" '{"usage-source":["transcript"],"channel":["cli","webui"]}' > "$R/bfiles/B/businesses/mosaic-stack.json"
node "$B/mkbiz.mjs" "$EX" "$R/bfiles/nosecret" '{"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}' > "$R/bfiles/H/businesses/mosaic-stack.json"
step "business B (Window A's plug-ins, no harness) $(sha256sum < "$R/bfiles/B/businesses/mosaic-stack.json" | cut -c1-64); H (harness [\"claude-code\"]) $(sha256sum < "$R/bfiles/H/businesses/mosaic-stack.json" | cut -c1-64)"
@@ -0,0 +1,226 @@
#!/usr/bin/env bash
# Merged window B+C, P3 (repin-merged-bc.md draft 3, sage-1112, sage-1117): the rehearsal on the root
# seed.sh made at OLD 5fa9cc8f2 and 3h. Order: the load checks, W1 and S1, W2, W3, W5 and a snapshot,
# W6 as the tester, W7 (PM launch emulated), S2, a P3-only name write after the backup stamp, then the
# rollback after W6: the refusal before the harness undo, harness null as the tester, OLD's load
# check, D3, rollback --restore --plan, the run without --events, the run with --events N from D3,
# and the end state against S1. Every stack-release call names the scratch --copies and --bin.
# Scratch paths only. TP=1 adds --tester-port $TPORT to W3 and W5 and checks it is dropped on the way back.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
OUT=$R/out/p3.txt
SN=$R/out/snap
[ ! -e "$OUT" ] || { echo "run.sh: $OUT exists" >&2; exit 1; }
[ -f "$RB/data/state/stack-active.json" ] || { echo "run.sh: no seeded root" >&2; exit 1; }
mkdir -p "$SN"
SR=(scripts/stack-release.sh)
CB=(--copies "$COPIES" --bin "$RB/bin")
TPF=(); [ "$TP" = 1 ] && TPF=(--tester-port "$TPORT")
C_OLD=(node "$COPIES/$OLD/packages/cli/src/cli.mjs")
C_NEW=(node "$COPIES/$NEW/packages/cli/src/cli.mjs")
DB=$RB/data/bus/bus.sqlite
part() { # part TITLE CMD... : one labeled part of the transcript, with its command and exit code
local title="$1"; shift
{ echo; echo "## $title"; echo "# command: (cd $REPO && <scratch env> $*)"; } >> "$OUT"
step "run: $*"
local rc=0; (cd "$REPO" && "${E[@]}" "$@") > "$R/out/last.txt" 2>&1 || rc=$?
cat "$R/out/last.txt" >> "$OUT"
echo "# exit $rc" >> "$OUT"; step "exit $rc"; RC=$rc
}
note() { echo "# $*" >> "$OUT"; step "$*"; }
stop() { note "STOP: $*"; exit 1; }
expect() { [ "$RC" = "$1" ] || stop "expected exit $1, got $RC"; }
has() { grep -qF -- "$1" "$R/out/last.txt"; } # the last part's output holds this text
lacks() { ! grep -qF -- "$1" "$R/out/last.txt"; }
lastlog() { tail -1 "$RB/data/state/stack-activation-log.jsonl"; }
pointer() { node "$B/jget.mjs" "$1" < "$RB/data/state/stack-active.json"; }
state() { # the pointer, the unit ExecStarts and the business file's plugins after a part
note "pointer: $(cat "$RB/data/state/stack-active.json")"
note "bus unit ExecStart: $(sed -n 's/^ExecStart=//p' "$RB/xcfg/systemd/user/[email protected]")"
note "Console unit ExecStart: $(sed -n 's/^ExecStart=//p' "$RB/xcfg/systemd/user/mosaic-webui.service")"
note "business file plugins: $(node -e 'console.log(JSON.stringify(require(process.argv[1]).plugins))' "$RB/cfg/businesses/mosaic-stack.json")"
note "activation log, last line: $(lastlog)"
}
snap() { # snap NAME ARGS... : snapshot.mjs on the scratch store, the output kept in out/snap/NAME.json
local name="$1"; shift
part "snapshot $name" node "$SNAP" --store "$DB" "$@"
cp "$R/out/last.txt" "$SN/$name.json"
}
same() { # same A B : the two snapshots match on every table
part "compare $1 with $2" node "$B/cmp.mjs" "$SN/$1.json" "$SN/$2.json"
}
plugins_read() { # the NEW copy's own mosaic plugins --tester --json, its output kept in out/NAME.json
part "$2" "${C_NEW[@]}" plugins --business mosaic-stack --tester --json
cp "$R/out/last.txt" "$R/out/$1.json"
}
plugins_set() { # plugins_set NAME VALUE_JSON TITLE: a patch with the revision of out/NAME-read.json, set as the tester
local rev; rev="$(node "$B/jget.mjs" revision < "$R/out/$1-read.json")"
[ -n "$rev" ] || stop "no revision in $1-read.json"
printf '{"revision":%s,"plugins":{"harness":%s}}\n' "$(node -e 'process.stdout.write(JSON.stringify(process.argv[1]))' "$rev")" "$2" > "$R/out/$1.json"
note "patch $1.json: $(cat "$R/out/$1.json")"
part "$3" "${C_NEW[@]}" plugins set --file "$R/out/$1.json" --business mosaic-stack --tester
}
receipt() { # the last organization receipt: transaction, actor, business and the plug-ins before and after
local f; f="$(find "$RB" -name changes.jsonl -path '*mosaic-stack*' | head -1)"
[ -n "$f" ] || stop "no changes.jsonl for mosaic-stack under $RB"
note "receipt file: ${f#$RB/}, $(wc -l < "$f") line(s)"
note "last receipt: $(tail -1 "$f" | node -e 'const o=JSON.parse(require("fs").readFileSync(0,"utf8"));console.log(JSON.stringify({transaction:o.transaction,actor:o.actor,business:o.business,before:o.before?.plugins,after:o.after?.plugins}))')"
}
markers() { # names only, never values: run markers in this shell's ancestors (the tester walk refuses them)
local p=$$ n=0
while [ "$p" -gt 1 ]; do
tr '\0' '\n' 2>/dev/null < "/proc/$p/environ" | grep -qE '^(MOSAIC_BUS_CAP|MOSAIC_RUN_ID|MOSAIC_AGENT_RUN)=.' && { echo "pid $p has a run marker"; n=$((n + 1)); }
p=$(awk '{print $4}' "/proc/$p/stat" 2>/dev/null) || break
done
echo "ancestors with a run marker: $n"
}
{
echo "# SCRATCH ROOT, NOT LIVE. Merged window B+C P3, run by darkwing from $(date -u +%FT%TZ) (sage-1112, sage-1117)."
echo "# Plan: agents/sage/work/window-plan/repin-merged-bc.md, sha256 $(sha256sum < /mnt/storage/src/mosaic-stack/agents/sage/work/window-plan/repin-merged-bc.md | cut -c1-64)."
echo "# Tool: $REPO, a git clone --shared of the canonical checkout at $(git -C "$REPO" rev-parse HEAD), nothing applied;"
echo "# scripts/stack-release.sh blob $(git -C "$REPO" rev-parse HEAD:scripts/stack-release.sh). refactor in the clone: $(git -C "$REPO" rev-parse refactor)."
echo "# Copies (stack-copy.sh copy): OLD $OLD, NEW $NEW. TP=$TP: $([ "$TP" = 1 ] && echo "W3 and W5 take --tester-port $TPORT" || echo "no --tester-port (the tool at this NEW predates row 176)")."
echo "# Root: $RB. Config $RB/cfg/config.json, data root $RB/data, units in $RB/xcfg/systemd/user."
echo "# Business file: the committed example (blob $(git -C "$REPO" hash-object packages/business/examples/mosaic-stack.example.json)) made loadable by mkbiz.mjs: plugins"
echo "# {\"usage-source\":[\"transcript\"],\"channel\":[\"cli\",\"webui\"]}, no harness, bus.tester true, every role's harness var claude-code;"
echo "# sha256 $(sha256sum < "$R/bfiles/B/businesses/mosaic-stack.json" | cut -c1-64)."
echo "# Store: seeded at 3h by OLD's Store before the bus first started (store-seed.mjs): 5 usage_records, 2 instance_names, 1 thread."
echo "# The harness set and its undo are the real NEW copy's mosaic plugins set --tester against the scratch bus, no stand-in."
echo "# snapshot.mjs: $SNAP, sha256 $(sha256sum < "$SNAP" | cut -c1-64) (expected $SNAP_SHA)."
echo "# Stand-ins ($B): systemctl runs the copy's real 'scripts/mosaic bus start mosaic-stack'. With pm-mode emulate a --pm"
echo "# start runs the bus WITHOUT --pm and EMULATES the PM launch: no claude runs; a waiting runner, one sessions.json entry"
echo "# and one 'launched chief' journal line stand in for it (no session credential goes to scratch). The Console is a"
echo "# /healthz stand-in on 127.0.0.1:$PORT, and on 127.0.0.1:$TPORT when the unit has --tester-port. journalctl and"
echo "# systemd-analyze are the test's; claude is a fixture that prints a version. Credential files are fake placeholders."
echo "# Environment for every call: env -i with HOME, PATH, TMPDIR, LANG, MOSAIC_CONFIG, XDG_* and SD_* only (names: $(printf '%s\n' "${E[@]:2}" | cut -d= -f1 | paste -sd' ' -))."
} > "$OUT"
step "--- run.sh"
[ "$(sha256sum < "$SNAP" | cut -c1-64)" = "$SNAP_SHA" ] || stop "snapshot.mjs is not the copy Mos read"
state
# --- the load checks (P1 shape, on the scratch file)
part "L1. business-check of OLD on a file that has harness (expect REFUSED unknown kind \"harness\")" node "$B/load-check.mjs" "$COPIES/$OLD" "$R/bfiles/H"
expect 1; has 'unknown kind "harness"' || stop 'no unknown kind "harness" refusal'
part "L2. control: NEW on the same file" node "$B/load-check.mjs" "$COPIES/$NEW" "$R/bfiles/H"; expect 0
part "L3. OLD on the rehearsal file" node "$B/load-check.mjs" "$COPIES/$OLD" "$RB/cfg"; expect 0
part "L4. NEW on the rehearsal file" node "$B/load-check.mjs" "$COPIES/$NEW" "$RB/cfg"; expect 0
part "L5. the P1 values of the rehearsal file" node -e '
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))}))' "$RB/cfg/businesses/mosaic-stack.json"
expect 0; has '"busTester":true' && has '"pluginKinds":["usage-source","channel"]' && has '"launchBy":"chief","chiefHarness":"claude-code","piRoles":[]' || stop "P1 values differ"
{ echo; echo "## L6. run markers in this shell's ancestors (names only; the tester walk refuses one)"; } >> "$OUT"
markers > "$R/out/last.txt"; cat "$R/out/last.txt" >> "$OUT"
has 'ancestors with a run marker: 0' || stop "a run marker above this shell; the tester proof would refuse"
# --- W1, S1, W2
part "W1a. agents as the tester (OLD's CLI; the chief must not be working)" "${C_OLD[@]}" agents --business mosaic-stack --tester --json
expect 0
part "W1b. launches list (OLD's CLI)" "${C_OLD[@]}" launches list --json; expect 0
note "W1 start stamp: $(date -u +%FT%TZ)"
snap S1 --held; expect 0
has '"schema": "3h"' || stop "S1 is not at 3h"
part "W2. status" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$OLD" ] && [ "$(pointer schema)" = 3h ] && [ -z "$(pointer pmPending)" ] || stop "W2: pointer not on OLD at 3h with no pending"
# --- W3, W5
part "W3. activate NEW --pm-after-harness --migrate ${TPF[*]} --plan" "${SR[@]}" activate "$NEW" mosaic-stack --pm-after-harness --migrate "${TPF[@]}" --plan "${CB[@]}"
expect 0
for c in pm-after-harness-target pm-after-harness-set unknown-kind-for-target tester-port-target; do lacks "$c" || stop "W3 names $c"; done
has '3h' && has '3i' && has '--migrate (given)' || stop "W3 plan lacks the 3h to 3i step or --migrate (given)"
[ "$TP" = 1 ] && { has "--tester-port $TPORT" || has "\"--tester-port\",\"$TPORT\"" || stop "W3 plan does not show --tester-port $TPORT in the Console flags"; }
cp "$R/out/last.txt" "$R/out/W3-plan.txt"
part "W5. activate NEW --pm-after-harness --migrate ${TPF[*]} (phase 1, migrates)" "${SR[@]}" activate "$NEW" mosaic-stack --pm-after-harness --migrate "${TPF[@]}" "${CB[@]}"
expect 0
state
ACT="$(lastlog | node "$B/jget.mjs" activation)"; BK="$(lastlog | node "$B/jget.mjs" backup)"
[ "$(lastlog | node "$B/jget.mjs" result)" = ok ] && [ -n "$ACT" ] && [ "$BK" = "$ACT" ] || stop "W5: last log line is not ok with this run's backup"
BDIR="$RB/data/backups/stack/$BK"; STAMP="$(cat "$BDIR/STAMP")"
note "W5 activation $ACT; backup $BDIR; STAMP $STAMP; SCHEMA $(cat "$BDIR/SCHEMA"); files: $(ls "$BDIR" | paste -sd' ' -)"
[ "$(cat "$BDIR/SCHEMA")" = 3h ] || stop "the backup is not at 3h"
(cd "$BDIR" && sha256sum -c --quiet SHA256SUMS) >> "$OUT" 2>&1 && note "backup SHA256SUMS: OK" || stop "backup SHA256SUMS does not check"
part "W5b. status (pending)" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$NEW" ] && [ "$(pointer schema)" = 3i ] && [ "$(pointer pm)" = false ] && [ "$(pointer pmPending)" = true ] || stop "W5: pointer not on NEW, 3i, pm false, pmPending true"
if [ "$TP" = 1 ]; then
pointer console | grep -qF "\"--tester-port\",\"$TPORT\"" || stop "W5: the pointer's Console flags lack --tester-port $TPORT"
(exec 3<>/dev/tcp/127.0.0.1/$TPORT) 2>/dev/null && note "tester port $TPORT listens (stand-in)" || stop "tester port $TPORT is closed"
fi
snap W5 --held; expect 0
has '"schema": "3i"' || stop "the store is not at 3i after W5"
same S1 W5; expect 0
# --- W6, W7, S2
plugins_read W6-read "W6a. plugins --tester --json (NEW's CLI), for the revision"; expect 0
plugins_set W6 '["claude-code"]' "W6b. plugins set harness [\"claude-code\"] as the tester"; expect 0
plugins_read W6-after "W6c. plugins read again"; expect 0
has '"harness": [' && has '"claude-code"' || stop "W6: harness is not [\"claude-code\"]"
node -e 'const a=require(process.argv[1]).plugins,b=require(process.argv[2]).plugins;process.exit(JSON.stringify(a["usage-source"])===JSON.stringify(b["usage-source"])&&JSON.stringify(a.channel)===JSON.stringify(b.channel)?0:1)' "$R/out/W6-read.json" "$R/out/W6-after.json" \
&& note "W6: usage-source and channel unchanged" || stop "W6: usage-source or channel changed"
receipt
tail -1 "$OUT" | grep -q '"actor":"tester"' || stop "W6: the receipt's actor is not tester"
part "W6d. business-check under NEW on the patched file" node "$B/load-check.mjs" "$COPIES/$NEW" "$RB/cfg"; expect 0
state
part "W7. pm-on (PM launch emulated)" "${SR[@]}" pm-on mosaic-stack "${CB[@]}"; expect 0
state
[ "$(pointer pm)" = true ] && [ -z "$(pointer pmPending)" ] || stop "W7: pointer is not pm true with no pmPending"
part "W7b. status after pm-on" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
part "W7c. launches list (NEW's CLI)" "${C_NEW[@]}" launches list --json
snap S2 --held; expect 0
same S1 S2; expect 0
# --- P3 only: one tester write after the backup stamp, so D3 has a row to count and the restore one to drop
part "X1. name chief p3-name-3 as the tester (P3 only, after the stamp)" "${C_NEW[@]}" name chief p3-name-3 --business mosaic-stack --tester
X1=$RC
# --- the rollback after W6
part "R0. rollback --restore $ACT --plan before the harness undo (expect unknown-kind-for-target)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --plan "${CB[@]}"
[ "$RC" != 0 ] && has unknown-kind-for-target || stop "R0 did not refuse unknown-kind-for-target"
plugins_read R1-read "R1a. plugins --tester --json, for the revision"; expect 0
plugins_set R1 'null' "R1b. plugins set harness null as the tester"; expect 0
plugins_read R1-after "R1c. plugins read again"; expect 0
lacks '"harness"' || stop "R1: harness is still set"
receipt
tail -1 "$OUT" | grep -q '"actor":"tester"' || stop "R1: the receipt's actor is not tester"
part "R2. business-check under OLD" node "$B/load-check.mjs" "$COPIES/$OLD" "$RB/cfg"; expect 0
snap D3 --held --after "$STAMP"; expect 0
N="$(node "$B/jget.mjs" eventsAfter < "$SN/D3.json")"
note "D3 after $STAMP: events $N, usage_records $(node "$B/jget.mjs" tables.usage_records.rowsAfter < "$SN/D3.json"), instance_names $(node "$B/jget.mjs" tables.instance_names.rowsAfter < "$SN/D3.json"), threads $(node "$B/jget.mjs" tables.threads.rowsAfter < "$SN/D3.json") (X1 exit $X1)"
[ -n "$N" ] || stop "D3 has no eventsAfter"
part "R3. rollback --restore $ACT --plan" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --plan "${CB[@]}"; expect 0
[ "$TP" = 1 ] && { has 'tester-port' || stop "R3 plan does not say it drops --tester-port"; }
part "R4. rollback --restore $ACT without --events (expect post-backup-events when D3 counted any)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" "${CB[@]}"
if [ "$N" = 0 ]; then
expect 0
else
[ "$RC" != 0 ] && has post-backup-events || stop "R4 did not refuse post-backup-events"
M="$(sed -n 's/.*refusing post-backup-events: \([0-9][0-9]*\) event.*/\1/p' "$R/out/last.txt" | head -1)"
note "R4 refused with $M event(s); D3 counted $N"
[ "$(pointer copy)" = "$NEW" ] && [ "$(pointer pm)" = true ] || stop "R4's refusal changed the pointer"
part "R5. rollback --restore $ACT --events $N (N from D3)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --events "$N" "${CB[@]}"
if [ "$RC" != 0 ] && has post-backup-events; then
M2="$(sed -n 's/.*refusing post-backup-events: \([0-9][0-9]*\) event.*/\1/p' "$R/out/last.txt" | head -1)"
note "FINDING: the event count moved between D3 ($N) and R5 ($M2); one rerun with --events $M2"
part "R5b. rollback --restore $ACT --events $M2" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --events "$M2" "${CB[@]}"
fi
expect 0
fi
POST="$(sed -n 's/^restore: .*moves to \(.*\) and is kept;.*/\1/p' "$R/out/last.txt" | head -1)"
note "post-attempt store: ${POST:-(none named)}$([ -n "$POST" ] && [ -e "$POST" ] && echo ', present')"
state
# --- the end state
part "F1. status at the end" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$OLD" ] && [ "$(pointer schema)" = 3h ] && [ "$(pointer pm)" = true ] && [ -z "$(pointer pmPending)" ] || stop "F1: pointer not on OLD, 3h, pm true"
pointer console | grep -qF -- '--tester-port' && stop "F1: the pointer's Console flags still have --tester-port"
grep -qF -- '--tester-port' "$RB/xcfg/systemd/user/mosaic-webui.service" && stop "F1: the Console unit still has --tester-port"
(exec 3<>/dev/tcp/127.0.0.1/$TPORT) 2>/dev/null && stop "F1: tester port $TPORT still listens"
note "F1: pointer on OLD at 3h, pm true, no --tester-port in the pointer or the Console unit, port $TPORT closed"
snap F --held; expect 0
has '"schema": "3h"' || stop "the store is not back at 3h"
same S1 F; expect 0
part "F2. agents as the tester (OLD's CLI)" "${C_OLD[@]}" agents --business mosaic-stack --tester --json; expect 0
part "F3. launches list (OLD's CLI)" "${C_OLD[@]}" launches list --json; expect 0
note "P3: PASS"
echo "done: $OUT"
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# P3, seed: a scratch root at OLD 5fa9cc8f2 and 3h on stand-in units, with synthetic store rows written by
# OLD's Store before the bus first starts, then adopt. Real OLD bus host (PM launch emulated), healthz
# stand-in for the Console. Scratch paths only.
set -euo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$RB" ] || { echo "seed.sh: $RB exists; remove it first" >&2; exit 1; }
for p in $PORT $TPORT; do ! (exec 3<>/dev/tcp/127.0.0.1/$p) 2>/dev/null || { echo "seed.sh: port $p is in use" >&2; exit 1; }; done
mkdir -p "$RB"/{home,cfg/businesses,xcfg,xdata,xstate,run,sd,bin,tmp,data/notify/mosaic-stack}
chmod 700 "$RB/run"
echo emulate > "$RB/sd/pm-mode"
cat > "$RB/cfg/config.json" <<EOC
{"configVersion":1,"environment":"development","dataRoot":"$RB/data","execution":{"backend":"docker","provider":"zai","model":"glm-5.3-flash","adapter":"mock"}}
EOC
cp "$R/bfiles/B/businesses/mosaic-stack.json" "$RB/cfg/businesses/mosaic-stack.json"
printf '{"notifyVersion":1,"binding":null}' > "$RB/data/notify/mosaic-stack/notify.json"; chmod 600 "$RB/data/notify/mosaic-stack/notify.json"
step "root: $RB; business file $(sha256sum < "$RB/cfg/businesses/mosaic-stack.json" | cut -c1-64) (the example with usage-source transcript and channel cli,webui, no harness, bus.tester true, every role's harness var claude-code)"
# The broker refuses to boot unless every credential file in the business file exists, mode 0600. These are
# FAKE placeholder strings, not tokens; both base URLs in the file are 127.0.0.1:9.
NS="$R/bfiles/nosecret"; [ ! -e "$NS" ] || { echo "seed.sh: $NS exists; remove it first" >&2; exit 1; }
mkdir -m 700 "$NS"
for f in $(node -e 'const b=require(process.argv[1]);const o=[];(function w(x){if(x&&typeof x==="object")for(const[k,v]of Object.entries(x)){if(k==="file"&&typeof v==="string")o.push(v);w(v)}})(b);console.log(o.join(" "))' "$RB/cfg/businesses/mosaic-stack.json"); do
case "$f" in "$NS"/*) ;; *) echo "seed.sh: credential path outside $NS: $f" >&2; exit 1;; esac
printf 'scratch-fake-placeholder-%s\n' "$(basename "$f" .token)" > "$f"; chmod 600 "$f"
done
step "fake credential files: $(ls "$NS" | wc -l) under $NS, each 'scratch-fake-placeholder-<name>', mode 0600"
step "store seed: $(node "$B/store-seed.mjs" "$COPIES/$OLD" "$RB/data" 2>&1)"
printf '#!/usr/bin/env bash\n# mosaic-cli wrapper (Q81, agents/sage/work/q81/mosaic-cli.sh)\n[ "${1:-}" = __lease-capability ] && exec "%s/mosaic-old" "$@"\nexit 1\n' "$RB/bin" > "$RB/bin/mosaic"; chmod 755 "$RB/bin/mosaic"
run() { step "run: $*"; local rc=0; (cd "$REPO" && "${E[@]}" "$@") >> "$LOGF" 2>&1 || rc=$?; step "exit $rc"; return $rc; }
run scripts/bus-service.sh install --copy $OLD --copies "$COPIES" --pm --claude "$B/claude"
run systemctl --user start [email protected]
run scripts/webui-service.sh install --copy $OLD --copies "$COPIES" --port $PORT --business mosaic-stack
run systemctl --user start mosaic-webui.service
run scripts/stack-copy.sh wrapper $OLD --copies "$COPIES" --bin "$RB/bin"
run "$COPIES/$OLD/scripts/mosaic" bus status --json
run "$COPIES/$OLD/scripts/mosaic" launches list --json
run scripts/stack-release.sh adopt mosaic-stack --copies "$COPIES" --bin "$RB/bin"
run scripts/stack-release.sh status mosaic-stack --copies "$COPIES" --bin "$RB/bin" || true
step "pointer: $(cat "$RB/data/state/stack-active.json")"
@@ -0,0 +1,24 @@
// P3: synthetic rows in the scratch store before the OLD bus first starts, so S1, the migration, D3 and the
// restore have something to hash: usage records (a known end, a begin only, an unknown end), two instance
// names and a thread with a project. OLD's own Store writes them at 3h. Synthetic values only.
// usage: node store-seed.mjs OLD_COPY DATA_ROOT
import { pathToFileURL } from 'node:url';
const [old, root] = process.argv.slice(2);
const { Store, SCHEMA_VERSION } = await import(pathToFileURL(`${old}/packages/bus/src/store.mjs`).href);
if (SCHEMA_VERSION !== '3h') throw Error(`OLD is ${SCHEMA_VERSION}, not 3h`);
const s = new Store(root);
const u = (at, run, turn, phase, status, n, cursor) =>
s.run(`INSERT INTO usage_records(at,business,run,instance,provider,model,account,turn,source,phase,status,code,cursor,input,output,cache_write,cache_read)
VALUES (?,?,?,?,?,?,NULL,?,?,?,?,?,?,?,?,?,?)`, at, 'mosaic-stack', run, 'chief', 'anthropic', 'scratch-model', turn, 'transcript', phase, status,
status === 'unknown' ? 'no-new-usage' : null, cursor, ...(status === 'known' ? [n, n * 2, 0, n * 3] : [null, null, null, null]));
u('2026-10-19T10:00:00.000Z', 'p3-run-a', 't1', 'begin', 'known', 0, '{"offset":1}');
u('2026-10-19T10:00:05.000Z', 'p3-run-a', 't1', 'end', 'known', 1200, null);
u('2026-10-19T10:01:00.000Z', 'p3-run-a', 't2', 'begin', 'known', 0, '{"offset":2}');
u('2026-10-19T13:00:00.000Z', 'p3-run-b', 't1', 'begin', 'known', 0, '{"offset":3}');
u('2026-10-19T13:00:09.000Z', 'p3-run-b', 't1', 'end', 'unknown', 0, null);
s.run(`INSERT INTO instance_names(at,business,instance,name,by) VALUES (?,?,?,?,?)`, '2026-10-19T09:00:00.000Z', 'mosaic-stack', 'chief', 'p3-name-1', 'tester');
s.run(`INSERT INTO instance_names(at,business,instance,name,by) VALUES (?,?,?,?,?)`, '2026-10-19T14:00:00.000Z', 'mosaic-stack', 'chief', 'p3-name-2', 'tester');
s.run(`INSERT INTO projects(id,at,business,name,repo,created_by) VALUES (?,?,?,?,?,?)`, 'p3-proj', '2026-10-19T09:00:00.000Z', 'mosaic-stack', 'p3-project', null, 'tester');
s.run(`INSERT INTO threads(id,at,business,project,instance,owner,name) VALUES (?,?,?,?,?,?,?)`, 'p3-th1', '2026-10-19T09:30:00.000Z', 'mosaic-stack', 'p3-proj', 'chief', 'tester', 'p3-thread');
s.close();
console.log('seeded 5 usage_records, 2 instance_names, 1 project, 1 thread at 3h');
@@ -0,0 +1,136 @@
#!/usr/bin/node
// sage-1004/1006 Window B rehearsal: a stand-in `systemctl --user`, based on the one in
// packages/cli/tests/stack-release.test.mjs. Unit state lives in $SD_STATE/units.json and every call
// goes to calls.log. Unlike the test's holder, a bus start runs the copy's real
// `scripts/mosaic bus start <business>` from the unit's WorkingDirectory, without --pm and under this
// scratch environment. Its output becomes journal lines. With --pm in ExecStart, the PM launch is
// EMULATED: no claude runs. A scratch runner process stands in for the session, with one
// sessions.json entry and one `launched` journal line. A Console start runs a scratch /healthz
// server on the unit's --port. Nothing here reads or writes a live unit, store or journal.
// Row 169 rehearsal: when $SD_STATE/pm-mode holds "real", a bus start with --pm runs the unit's argv as
// it is, --pm included, so the copy's own launchPm runs (step 5). The start then waits up to 30 s more
// for the `launched` line or the bus exiting, and journals all of it. A bus that exited is "failed",
// as systemd shows a Type=simple unit whose main process exited 3 (RestartPreventExitStatus=2 3 4,
// so no restart). A `launched` line in real mode writes REAL-LAUNCH to pids.log; run.sh stops on it.
const fs = require('node:fs'), path = require('node:path'), cp = require('node:child_process');
const sd = process.env.SD_STATE, data = process.env.SD_DATA, unitDir = path.join(process.env.XDG_CONFIG_HOME, 'systemd', 'user');
const args = process.argv.slice(2).filter((a) => a !== '--user'), [verb, ...rest] = args;
fs.appendFileSync(path.join(sd, 'calls.log'), `${new Date().toISOString()} ${args.join(' ')}\n`);
const stFile = path.join(sd, 'units.json');
const load = () => { try { return JSON.parse(fs.readFileSync(stFile, 'utf8')); } catch { return {}; } };
const save = (s) => { fs.writeFileSync(stFile + '.tmp', JSON.stringify(s)); fs.renameSync(stFile + '.tmp', stFile); };
const sleep = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
const alive = (pid) => { try { const s = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); return s[s.lastIndexOf(')') + 2] !== 'Z'; } catch { return false; } };
const startTime = (pid) => { const s = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); return s.slice(s.lastIndexOf(')') + 2).split(' ')[19]; };
const isBus = (u) => /^mosaic-bus@[a-z0-9-]+\.service$/.test(u), inst = (u) => u.slice('mosaic-bus@'.length, -'.service'.length);
const journal = (unit, text) => fs.appendFileSync(path.join(sd, 'journal.jsonl'), JSON.stringify({ epoch: Math.floor(Date.now() / 1000), unit, text }) + '\n');
const unitFile = (u) => {
const main = isBus(u) ? '[email protected]' : u, file = path.join(unitDir, main);
if (!fs.existsSync(file)) return null;
const drops = [];
for (const d of isBus(u) ? [main + '.d', u + '.d'] : [u + '.d']) { const dir = path.join(unitDir, d); if (fs.existsSync(dir)) for (const f of fs.readdirSync(dir).sort()) if (f.endsWith('.conf')) drops.push(path.join(dir, f)); }
const r = { wd: '', exec: '', env: [], drops };
for (const f of [file, ...drops]) for (let line of fs.readFileSync(f, 'utf8').split('\n')) {
line = line.replace(/%i/g, isBus(u) ? inst(u) : '').replace(/%h/g, process.env.HOME);
const m = /^(WorkingDirectory|ExecStart|Environment)=(.*)$/.exec(line); if (!m) continue;
if (m[1] === 'WorkingDirectory') r.wd = m[2]; else if (m[1] === 'ExecStart') { if (m[2]) r.exec = m[2]; } else r.env.push(m[2]);
}
return r;
};
// Every fd above 2 is closed first, so no child holds stack-release.sh's lock (fd 9).
const CLOSE = 'for fd in /proc/self/fd/*; do n=${fd##*/}; [ "$n" -gt 2 ] && eval "exec $n>&-" 2>/dev/null; done; exec "$@"';
const spawnDetached = (argv, opts) => { const ch = cp.spawn('bash', ['-c', CLOSE, 'standin', ...argv], { detached: true, ...opts }); ch.unref(); return ch; };
const sessionsFile = path.join(data, 'bus-host', 'sessions.json');
const readSessions = () => { try { return JSON.parse(fs.readFileSync(sessionsFile, 'utf8')); } catch { return { sessionsVersion: 1, sessions: [] }; } };
const writeSessions = (doc) => { fs.mkdirSync(path.dirname(sessionsFile), { recursive: true, mode: 0o700 }); fs.writeFileSync(sessionsFile + '.tmp', JSON.stringify(doc, null, 2) + '\n', { mode: 0o600 }); fs.renameSync(sessionsFile + '.tmp', sessionsFile); };
if (verb === 'show') {
const u = rest[0], props = []; for (let i = 1; i < rest.length; i++) if (rest[i] === '-p') props.push(rest[++i]);
const f = unitFile(u), st = load()[u] || {};
for (const p of props) {
if (p === 'LoadState') console.log(`LoadState=${f ? 'loaded' : 'not-found'}`);
else if (p === 'WorkingDirectory') console.log(`WorkingDirectory=${f ? f.wd : ''}`);
else if (p === 'ExecStart') console.log(f && f.exec ? `ExecStart={ path=${f.exec.split(' ')[0]} ; argv[]=${f.exec} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }` : 'ExecStart=');
else if (p === 'Environment') console.log(`Environment=${f ? f.env.join(' ') : ''}`);
else if (p === 'MainPID') console.log(`MainPID=${st.state === 'active' && st.pid ? st.pid : 0}`);
else if (p === 'DropInPaths') console.log(`DropInPaths=${f ? f.drops.join(' ') : ''}`);
}
process.exit(0);
}
if (verb === 'is-active') { const q = rest[0] === '--quiet', u = q ? rest[1] : rest[0], st = load()[u] || {}; let s = st.state || 'inactive'; if (s === 'active' && st.pid && !alive(st.pid)) s = 'failed'; if (!q) console.log(s); process.exit(s === 'active' ? 0 : 3); }
if (verb === 'is-enabled') { console.log('disabled'); process.exit(1); }
if (verb === 'daemon-reload') process.exit(0);
if (verb === 'list-units') {
const pats = rest.filter((a) => !a.startsWith('--')).map((p) => new RegExp('^' + p.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$'));
for (const [u, s] of Object.entries(load())) if (pats.some((re) => re.test(u))) console.log(`${u} loaded ${s.state} ${s.state === 'active' ? 'running' : 'dead'} standin`);
process.exit(0);
}
if (verb === 'start') {
const u = rest[0], f = unitFile(u); if (!f) { console.error(`Unit ${u} not found.`); process.exit(5); }
const s = load();
if (!isBus(u)) {
const argv = f.exec.split(' '), i = argv.indexOf('--port'), port = i > 0 ? argv[i + 1] : '7332';
const t = argv.indexOf('--tester-port'), tport = t > 0 ? argv[t + 1] : '';
const ch = spawnDetached([process.execPath, path.join(__dirname, 'healthz.cjs'), port, tport], { stdio: 'ignore', cwd: sd });
fs.appendFileSync(path.join(sd, 'pids.log'), `healthz ${ch.pid}\n`);
const end = Date.now() + 10000;
while (!fs.existsSync(path.join(sd, `healthz-${ch.pid}`))) { if (Date.now() > end) { console.error('healthz stand-in did not start'); process.exit(1); } sleep(20); }
s[u] = { state: 'active', pid: ch.pid, wd: f.wd }; save(s); process.exit(0);
}
const argv = f.exec.split(' '), pm = argv.slice(1).includes('--pm');
let mode = 'emulate'; try { mode = fs.readFileSync(path.join(sd, 'pm-mode'), 'utf8').trim(); } catch {}
const realPm = pm && mode === 'real', real = realPm ? argv : argv.filter((a) => a !== '--pm');
const env = { ...process.env }; for (const e of f.env) { const k = e.slice(0, e.indexOf('=')); if (k === 'PATH' || k === 'MOSAIC_CLAUDE_BIN') env[k] = e.slice(k.length + 1); }
const out = path.join(sd, `bus-${Date.now()}.out`), fd = fs.openSync(out, 'a');
const ch = spawnDetached(real, { stdio: ['ignore', fd, fd], cwd: f.wd, env });
fs.closeSync(fd);
fs.appendFileSync(path.join(sd, 'pids.log'), `bus ${ch.pid} ${real.join(' ')} > ${out}\n`);
const end = Date.now() + 60000; let text = '';
while (!/^bus host up/m.test(text)) {
if (!alive(ch.pid) && realPm) { text = fs.readFileSync(out, 'utf8'); if (/^bus host up/m.test(text)) break; }
if (!alive(ch.pid)) { for (const l of text.split('\n').filter(Boolean)) journal(u, l); s[u] = { state: 'failed', pid: null, wd: f.wd }; save(s); console.error(`bus exited before host up; see ${out}`); process.exit(1); }
if (Date.now() > end) { console.error(`bus host up not seen in 60 s; see ${out}`); process.exit(1); }
sleep(100); text = fs.readFileSync(out, 'utf8');
}
if (realPm) {
const end3 = Date.now() + 30000;
while (!/^launched /m.test(text) && alive(ch.pid) && Date.now() < end3) { sleep(100); text = fs.readFileSync(out, 'utf8'); }
sleep(200); text = fs.readFileSync(out, 'utf8');
if (/^launched /m.test(text)) fs.appendFileSync(path.join(sd, 'pids.log'), `REAL-LAUNCH ${ch.pid}\n`);
}
for (const l of text.split('\n').filter(Boolean)) journal(u, l);
if (realPm) {
const up = alive(ch.pid);
fs.appendFileSync(path.join(sd, 'pids.log'), `real-pm ${ch.pid} ${up ? 'running' : 'exited'}\n`);
s[u] = up ? { state: 'active', pid: ch.pid, wd: f.wd, out, journaled: text.length } : { state: 'failed', pid: null, wd: f.wd };
save(s); process.exit(0);
}
s[u] = { state: 'active', pid: ch.pid, wd: f.wd, out, journaled: text.length };
if (pm) {
// The emulated PM launch: a runner that only waits, one sessions.json entry, one journal line.
const runner = spawnDetached([process.execPath, '-e', 'setInterval(()=>{},1<<30)'], { stdio: 'ignore', cwd: sd });
const end2 = Date.now() + 5000; while (!fs.existsSync(`/proc/${runner.pid}/stat`) && Date.now() < end2) sleep(10);
const run = `remul${runner.pid}`, b = inst(u);
const doc = readSessions(); doc.sessions.push({ run, business: b, instance: 'chief', harness: 'claude-code', model: 'emulated', launchedBy: 'standin-pm-emulation', runnerPid: runner.pid, runnerStartTime: startTime(runner.pid), startedAt: new Date().toISOString() }); writeSessions(doc);
journal(u, `launched chief: run ${run}, claude-code emulated`);
fs.appendFileSync(path.join(sd, 'pids.log'), `runner ${runner.pid} ${run}\n`);
s[u].runner = runner.pid; s[u].run = run;
}
save(s); process.exit(0);
}
if (verb === 'stop') {
const u = rest[0], s = load(), st = s[u];
if (st && st.pid) {
try { process.kill(st.pid, 'SIGTERM'); } catch {}
const end = Date.now() + 20000; while (alive(st.pid) && Date.now() < end) sleep(50);
if (alive(st.pid)) { fs.appendFileSync(path.join(sd, 'pids.log'), `SIGKILL ${st.pid}\n`); try { process.kill(st.pid, 'SIGKILL'); } catch {} }
if (st.out) { const text = fs.readFileSync(st.out, 'utf8'); for (const l of text.slice(st.journaled || 0).split('\n').filter(Boolean)) journal(u, l); }
}
if (st && st.runner) {
try { process.kill(st.runner, 'SIGTERM'); } catch {}
const doc = readSessions(); doc.sessions = doc.sessions.filter((x) => x.run !== st.run); writeSessions(doc);
}
if (st) { s[u] = { wd: st.wd, state: 'inactive', pid: null }; save(s); }
process.exit(0);
}
console.error(`stand-in systemctl: unsupported: ${args.join(' ')}`); process.exit(1);
@@ -0,0 +1,4 @@
#!/usr/bin/node
// Stand-in `systemd-analyze --user unit-paths` (the test's): only the scratch unit dir.
if(process.argv[2]!=='--user'||process.argv[3]!=='unit-paths')process.exit(1);
console.log(require('node:path').join(process.env.XDG_CONFIG_HOME,'systemd','user'));
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# P3: stops the scratch units through the stand-in, then confirms every PID it started is gone and the port is closed.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
T=$R/out/p3-teardown.txt
{
echo "# teardown $(date -u +%FT%TZ)"
for u in mosaic-webui.service [email protected]; do
(cd "$REPO" && "${E[@]}" systemctl --user stop "$u"); echo "stop $u exit $?"
done
left=0
while read -r kind pid _; do
if [ -e "/proc/$pid" ] && grep -q "$R" "/proc/$pid/cmdline" 2>/dev/null; then echo "ALIVE $kind $pid"; left=1; fi
done < <(grep -v "^REAL-LAUNCH\|^SIGKILL\|^real-pm" "$RB/sd/pids.log")
for p in /proc/[0-9]*; do c=$(readlink "$p/cwd" 2>/dev/null) || continue; case $c in "$R"*) case "$(tr "\0" " " < "$p/cmdline" 2>/dev/null)" in *b/all.sh*|*b/teardown.sh*) continue;; esac; echo "cwd-in-root ${p#/proc/} $c"; left=1;; esac; done
for p in $PORT $TPORT; do if (exec 3<>/dev/tcp/127.0.0.1/$p) 2>/dev/null; then echo "port $p open"; left=1; else echo "port $p closed"; fi; done
echo "left: $left"
} 2>&1 | tee "$T"
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Waits until busy.sh passes twice, 60 s apart, then runs all.sh, teed. Gives up after 90 minutes.
set -uo pipefail
end=$((SECONDS + 5400))
while :; do
if ~/darkwing-scratch/busy.sh > /dev/null; then
sleep 60
if ~/darkwing-scratch/busy.sh; then break; fi
fi
[ "$SECONDS" -lt "$end" ] || { echo "wait-run: still busy after 90 min"; exit 9; }
sleep 30
done
echo "wait-run: clear at $(date -u +%FT%TZ)"
/home/jwoltje/darkwing-scratch/mbc/p3/b/all.sh 2>&1 | tee /home/jwoltje/darkwing-scratch/mbc/p3/all-$(date -u +%Y%m%dT%H%M%SZ).log
exit "${PIPESTATUS[0]}"
@@ -0,0 +1,15 @@
addy-gen_default
bridge
compose-audit_default
host
jarvis-crypto_default
mage-ai_mage-network
mosaic-dev_default
mosaic-internal
mosaic-mono-v1_default
mosaic-public
neni-content-engine-dashboard_default
none
sage-phr-ng_sage-network
t205-directus_dd-internal
t205-payload_pl-internal
@@ -0,0 +1,15 @@
addy-gen_default
bridge
compose-audit_default
host
jarvis-crypto_default
mage-ai_mage-network
mosaic-dev_default
mosaic-internal
mosaic-mono-v1_default
mosaic-public
neni-content-engine-dashboard_default
none
sage-phr-ng_sage-network
t205-directus_dd-internal
t205-payload_pl-internal
@@ -0,0 +1,6 @@
# before prep, 2026-10-20T00:28:47Z
/home/jwoltje/.mosaic-dev/bus/bus.sqlite 1792446324
/home/jwoltje/.mosaic-dev/bus 1792446325
# after teardown, 2026-10-20T00:28:54Z
/home/jwoltje/.mosaic-dev/bus/bus.sqlite 1792446324
/home/jwoltje/.mosaic-dev/bus 1792446325
@@ -0,0 +1,158 @@
2026-10-20T00:28:47Z tool clone /home/jwoltje/darkwing-scratch/mbc/p3/repo at 8e888014d4f4bbbe7f1e6fa598003c374c169856, refactor 8e888014d4f4bbbe7f1e6fa598003c374c169856; scripts/stack-release.sh blob 0b501ffbc24735468ca7e91845b86badfb2dd0b3; TP=0
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 127 packages in 1s
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts @google/[email protected] (preinstall: echo 'preinstall: no-op')
npm warn install-scripts [email protected] (postinstall: node install.js)
npm warn install-scripts [email protected] (postinstall: node scripts/postinstall)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
copied: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
2026-10-20T00:28:49Z copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0: exit 0
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 127 packages in 1s
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts @google/[email protected] (preinstall: echo 'preinstall: no-op')
npm warn install-scripts [email protected] (postinstall: node install.js)
npm warn install-scripts [email protected] (postinstall: node scripts/postinstall)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
copied: /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856
2026-10-20T00:28:51Z copy 8e888014d4f4bbbe7f1e6fa598003c374c169856: exit 0
2026-10-20T00:28:51Z example blob 3a81ca0faea6d3dc3b29ae513c799497ed53f9d7
2026-10-20T00:28:51Z business B (Window A's plug-ins, no harness) c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32; H (harness ["claude-code"]) 486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a
2026-10-20T00:28:51Z root: /home/jwoltje/darkwing-scratch/mbc/p3/root; business file c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32 (the example with usage-source transcript and channel cli,webui, no harness, bus.tester true, every role's harness var claude-code)
2026-10-20T00:28:51Z fake credential files: 9 under /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/nosecret, each 'scratch-fake-placeholder-<name>', mode 0600
2026-10-20T00:28:51Z store seed: seeded 5 usage_records, 2 instance_names, 1 project, 1 thread at 3h
2026-10-20T00:28:51Z run: scripts/bus-service.sh install --copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --pm --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
written: /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user/[email protected]
claude: /home/jwoltje/darkwing-scratch/mbc/p3/b/claude (9.9.9 (Claude Code fixture))
daemon-reload done
next, for one business (one per data root):
mkdir -m 0700 -p <dataRoot>/notify/<business> the notifier refuses a looser directory
write <dataRoot>/notify/<business>/notify.json, mode 0600:
{"notifyVersion": 1, "binding": "<discord binding>"} or "binding": null for no DMs
systemctl --user enable --now mosaic-bus@<business> start now and at login
systemctl --user status mosaic-bus@<business>
journalctl --user -u mosaic-bus@<business> -f the host's log
systemctl --user stop mosaic-bus@<business> SIGTERM; restartable
survive logout and reboot only with lingering on: loginctl enable-linger jwoltje
2026-10-20T00:28:51Z exit 0
2026-10-20T00:28:51Z run: systemctl --user start [email protected]
2026-10-20T00:28:51Z exit 0
2026-10-20T00:28:51Z run: scripts/webui-service.sh install --copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
written: /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user/mosaic-webui.service
serve: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
daemon-reload done
this script starts nothing: the Console holds the human's capability. Jason
starts and restarts it, or Mos under lead decision 102 (sends then enter the
trail as Jason); no other agent does:
systemctl --user enable --now mosaic-webui start now and at login
systemctl --user status mosaic-webui
journalctl --user -u mosaic-webui -f the Console's log
systemctl --user stop mosaic-webui SIGTERM; restartable
scripts/webui-service.sh status unit state and /healthz
survive logout and reboot only with lingering on: loginctl enable-linger jwoltje
2026-10-20T00:28:51Z exit 0
2026-10-20T00:28:51Z run: systemctl --user start mosaic-webui.service
2026-10-20T00:28:51Z exit 0
2026-10-20T00:28:51Z run: scripts/stack-copy.sh wrapper 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
wrapper: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
2026-10-20T00:28:51Z exit 0
2026-10-20T00:28:51Z run: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus status --json
{
"host": {
"business": "mosaic-stack",
"pid": 241212,
"startedAt": "2026-10-20T00:28:51.709Z",
"notifier": null,
"live": true
},
"socket": true,
"writerLock": {
"pid": 241229,
"at": "2026-10-20T00:28:51.774Z",
"live": true
},
"boot": {
"ok": true,
"at": "2026-10-20T00:28:51.708Z",
"business": "mosaic-stack",
"file": "/home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json",
"reason": null,
"lastGood": "2026-10-20T00:28:51.708Z"
}
}
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic launches list --json
[
{
"run": "remul241237",
"business": "mosaic-stack",
"instance": "chief",
"harness": "claude-code",
"model": "emulated",
"launchedBy": "standin-pm-emulation",
"runnerPid": 241237,
"runnerStartTime": "55732203",
"startedAt": "2026-10-20T00:28:51.811Z",
"live": true
}
]
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: scripts/stack-release.sh adopt mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
adopted 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 for mosaic-stack (pm 1, schema 3h)
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
pointer: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/state/stack-active.json
{"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T002852Z-5fa9cc8f2c66","at":"2026-10-20T00:28:52Z"}
log (last five lines):
{"at":"2026-10-20T00:28:52Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T002852Z-5fa9cc8f2c66","result":"ok"}
check:
bus: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
Console: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
CLI: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
result: pass
bus status:
host: mosaic-stack, pid 241212, running, since 2026-10-20T00:28:51.709Z, notifier off
socket: present
writer.lock: pid 241229
boot: organization file loaded at 2026-10-20T00:28:51.708Z
unit flags: match the pointer
drift: 138 commit(s) on refactor since the pointer's copy
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T002852Z-5fa9cc8f2c66","at":"2026-10-20T00:28:52Z"}
2026-10-20T00:28:52Z --- run.sh
2026-10-20T00:28:52Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T002852Z-5fa9cc8f2c66","at":"2026-10-20T00:28:52Z"}
2026-10-20T00:28:52Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus start %i --pm
2026-10-20T00:28:52Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
2026-10-20T00:28:52Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
2026-10-20T00:28:52Z activation log, last line: {"at":"2026-10-20T00:28:52Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T002852Z-5fa9cc8f2c66","result":"ok"}
2026-10-20T00:28:52Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H
2026-10-20T00:28:52Z exit 1
2026-10-20T00:28:52Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: node -e
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))})) /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json
2026-10-20T00:28:52Z exit 0
2026-10-20T00:28:52Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs agents --business mosaic-stack --tester --json
2026-10-20T00:28:53Z exit 0
2026-10-20T00:28:53Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs launches list --json
2026-10-20T00:28:53Z exit 0
2026-10-20T00:28:53Z W1 start stamp: 2026-10-20T00:28:53Z
2026-10-20T00:28:53Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held
2026-10-20T00:28:53Z exit 0
2026-10-20T00:28:53Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T00:28:53Z exit 0
2026-10-20T00:28:53Z run: scripts/stack-release.sh activate 8e888014d4f4bbbe7f1e6fa598003c374c169856 mosaic-stack --pm-after-harness --migrate --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T00:28:53Z exit 0
2026-10-20T00:28:53Z STOP: W3 names tester-port-target
@@ -0,0 +1,6 @@
# teardown 2026-10-20T00:28:53Z
stop mosaic-webui.service exit 0
stop [email protected] exit 0
port 47394 closed
port 47395 closed
left: 0
@@ -0,0 +1,305 @@
# SCRATCH ROOT, NOT LIVE. Merged window B+C P3, run by darkwing from 2026-10-20T00:28:52Z (sage-1112, sage-1117).
# Plan: agents/sage/work/window-plan/repin-merged-bc.md, sha256 696f0adb7a02c62b26ebb9f760c4c6b4f8805ec2acc62c388677b644c98b63ea.
# Tool: /home/jwoltje/darkwing-scratch/mbc/p3/repo, a git clone --shared of the canonical checkout at 8e888014d4f4bbbe7f1e6fa598003c374c169856, nothing applied;
# scripts/stack-release.sh blob 0b501ffbc24735468ca7e91845b86badfb2dd0b3. refactor in the clone: 8e888014d4f4bbbe7f1e6fa598003c374c169856.
# Copies (stack-copy.sh copy): OLD 5fa9cc8f2c66b52408b652b59c3070f7210b44d0, NEW 8e888014d4f4bbbe7f1e6fa598003c374c169856. TP=0: no --tester-port (the tool at this NEW predates row 176).
# Root: /home/jwoltje/darkwing-scratch/mbc/p3/root. Config /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/config.json, data root /home/jwoltje/darkwing-scratch/mbc/p3/root/data, units in /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user.
# Business file: the committed example (blob 3a81ca0faea6d3dc3b29ae513c799497ed53f9d7) made loadable by mkbiz.mjs: plugins
# {"usage-source":["transcript"],"channel":["cli","webui"]}, no harness, bus.tester true, every role's harness var claude-code;
# sha256 c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32.
# Store: seeded at 3h by OLD's Store before the bus first started (store-seed.mjs): 5 usage_records, 2 instance_names, 1 thread.
# The harness set and its undo are the real NEW copy's mosaic plugins set --tester against the scratch bus, no stand-in.
# snapshot.mjs: /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs, sha256 909a11f65c42de1dec6776a55585ad01ed960d25ff827c6b298b3293fbe46406 (expected 909a11f65c42de1dec6776a55585ad01ed960d25ff827c6b298b3293fbe46406).
# Stand-ins (/home/jwoltje/darkwing-scratch/mbc/p3/b): systemctl runs the copy's real 'scripts/mosaic bus start mosaic-stack'. With pm-mode emulate a --pm
# start runs the bus WITHOUT --pm and EMULATES the PM launch: no claude runs; a waiting runner, one sessions.json entry
# and one 'launched chief' journal line stand in for it (no session credential goes to scratch). The Console is a
# /healthz stand-in on 127.0.0.1:47394, and on 127.0.0.1:47395 when the unit has --tester-port. journalctl and
# systemd-analyze are the test's; claude is a fixture that prints a version. Credential files are fake placeholders.
# Environment for every call: env -i with HOME, PATH, TMPDIR, LANG, MOSAIC_CONFIG, XDG_* and SD_* only (names: HOME PATH TMPDIR LANG MOSAIC_CONFIG XDG_CONFIG_HOME XDG_DATA_HOME XDG_STATE_HOME XDG_RUNTIME_DIR SD_STATE SD_DATA).
# pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T002852Z-5fa9cc8f2c66","at":"2026-10-20T00:28:52Z"}
# bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus start %i --pm
# Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
# business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
# activation log, last line: {"at":"2026-10-20T00:28:52Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T002852Z-5fa9cc8f2c66","result":"ok"}
## L1. business-check of OLD on a file that has harness (expect REFUSED unknown kind "harness")
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H)
REFUSED /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H/businesses/mosaic-stack.json plugins names unknown kind "harness"; adding a kind is a core change
# exit 1
## L2. control: NEW on the same file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H)
copy 8e888014d: roles 6, projects 1, arbiters 2, plugins {"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}
HOLDS chief instance.name yes
HOLDS pm instance.name no
LOAD_OK
# exit 0
## L3. OLD on the rehearsal file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg)
copy 5fa9cc8f2: roles 6, projects 1, arbiters 2, plugins {"usage-source":["transcript"],"channel":["cli","webui"]}
HOLDS chief instance.name yes
HOLDS pm instance.name no
LOAD_OK
# exit 0
## L4. NEW on the rehearsal file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg)
copy 8e888014d: roles 6, projects 1, arbiters 2, plugins {"usage-source":["transcript"],"channel":["cli","webui"]}
HOLDS chief instance.name yes
HOLDS pm instance.name no
LOAD_OK
# exit 0
## L5. the P1 values of the rehearsal file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node -e
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))})) /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json)
{"busTester":true,"pluginKinds":["usage-source","channel"],"launchBy":"chief","chiefHarness":"claude-code","piRoles":[],"harnessByRole":{"pm":"claude-code","cto":"claude-code","coder":"claude-code","reviewer":"claude-code","chief":"claude-code","assistant":"claude-code"}}
# exit 0
## L6. run markers in this shell's ancestors (names only; the tester walk refuses one)
ancestors with a run marker: 0
## W1a. agents as the tester (OLD's CLI; the chief must not be working)
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs agents --business mosaic-stack --tester --json)
[]
# exit 0
## W1b. launches list (OLD's CLI)
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs launches list --json)
[
{
"run": "remul241237",
"business": "mosaic-stack",
"instance": "chief",
"harness": "claude-code",
"model": "emulated",
"launchedBy": "standin-pm-emulation",
"runnerPid": 241237,
"runnerStartTime": "55732203",
"startedAt": "2026-10-20T00:28:51.811Z",
"live": true
}
]
# exit 0
# W1 start stamp: 2026-10-20T00:28:53Z
## snapshot S1
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held)
{
"schema": "3h",
"tables": {
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "04f8f0d94725145f7204a37d232fbf19c5c4f1e2930fda37482dff5b5cd484e4"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "15169aaf4e94d892f2202d0fd7d5af79b75ba017d23375ae389bae25dcc16edb"
}
}
}
# exit 0
## W2. status
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin)
pointer: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/state/stack-active.json
{"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T002852Z-5fa9cc8f2c66","at":"2026-10-20T00:28:52Z"}
log (last five lines):
{"at":"2026-10-20T00:28:52Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T002852Z-5fa9cc8f2c66","result":"ok"}
check:
bus: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
Console: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
CLI: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
result: pass
bus status:
host: mosaic-stack, pid 241212, running, since 2026-10-20T00:28:51.709Z, notifier off
socket: present
writer.lock: pid 241229
boot: organization file loaded at 2026-10-20T00:28:51.708Z
unit flags: match the pointer
drift: 138 commit(s) on refactor since the pointer's copy
# exit 0
## W3. activate NEW --pm-after-harness --migrate --plan
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> scripts/stack-release.sh activate 8e888014d4f4bbbe7f1e6fa598003c374c169856 mosaic-stack --pm-after-harness --migrate --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin)
plan: activate for mosaic-stack
from: 5fa9cc8f2c66b52408b652b59c3070f7210b44d0
to: 8e888014d4f4bbbe7f1e6fa598003c374c169856
store schema: 3h (read from the store the running bus holds)
target schema: 3i
migration: 3h to 3i, after a backup of the stopped store
migration steps: 3h to 3i
needs: --migrate (given)
needs: Jason present for this run (decision 96 condition 2)
commits: the run adds 138 (newest first, at most 200):
8e888014d log: row 175 landed (98d29769e), row 176 brief amended and launched, merged window drafted; sessions: Sage
473258a51 queue: revs 2072-2076: row 175 round 3 approve on 2e30f2a1 (Filbert 2072, comment 29279), landing note and done after 98d29769e (Sage 2073, 2074); row 176 brief re-pinned to 0f7119af9566 for the stack-release --tester-port pointer change and row 175 F1 (Sage 2075), queued to briefed (Sage 2076)
2fecddfba sage: row 176 brief: activate --tester-port N writes the flag into the pointer's Console flags, a rollback or an activate to a copy whose Console lacks it drops it, tester-port-target refuses before anything stops; tests and three mutants; row 175 F1 (TOOLS.md step 2) rides along
98d29769e bus, cli: tester reads and the W1-W7 tester writes, recorded as tester; scripts/mosaic sends plugins, name and names to the CLI (row 175, #1673)
1d81c54ff sessions: Filbert row 175 r3 review, approve
716ddcf1e queue: revs 2058-2071: row 179 start, in-review and request (Darkwing 2058, 2060, 2061), issue #1677 (Sage 2059), r1 approve (Dewey 2062, comment 29271), landing note and done after 9e74925c2 (Sage 2063, 2064); row 175 r2 request on f9e41b918 (Dewey 2065-2067, comment 29275), back to in-progress to rebase onto 9e74925c2 (Sage 2068, 2069), round 3 request on the rebased candidate 2e30f2a1 (Dewey 2070, 2071, comment 29276)
0f45a3e6e sessions: Dewey row 175 round 2 to in-review on 989699f7c, row 179 approved
9e74925c2 docs: TOOLS.md follow-ups F1-F3 from the row 169 review (row 179, #1677)
ce5807989 log: row 169 landed (264756a30), row 179 briefed, row 175 to round 2 (1bfc9833b)
1bfc9833b queue: revs 2052-2057: row 179 added and briefed (Sage 2052, 2057), row 169 landing notes and done after 264756a30 (Sage 2053, 2054, 2056), row 175 r1 approve recorded (Filbert 2055, comment 29264)
c98a5d17a sessions: Dewey row 175 round 1 approved
8f2ac5236 sessions: Filbert row 175 r1 review, approve
264756a30 stack-release: activate --pm-after-harness, pm-on and the pending pointer, so a re-pin past c216f47db starts the PM after the harness kind is set (row 169, #1666)
b2a75f318 sage: brief for the row 169 TOOLS.md follow-ups F1-F3 (Filbert, #1666 comment 29263), owner Darkwing, reviewer Dewey, after row 169
e7d47c346 log: rows 169 and 175 in-review, row 169 r1 approve, queue revs 2046-2051 (cb4a8bf1f)
cb4a8bf1f queue: revs 2046-2051: row 169 in-review round 1 (Darkwing 2046-2047), row 175 brief re-pin for the wrapper fix (Sage 2048), row 175 in-review round 1 on 7b27ab3f9 (Dewey 2049-2050), row 169 r1 approve recorded (Filbert 2051, comment 29263)
c7939a568 sessions: Filbert row 169 r1 review, approve
423ff5c86 sessions: Dewey row 175 round 1 in-review
3dfaea286 sage: row 175 brief carries the scripts/mosaic dispatch fix (plugins, name, names, follow, threads, thread go to packages/cli), test 12 and a mutant; found in Darkwing's row 169 rehearsal
d63cfca22 log: row 178 brief for mos-0881 (30622a229, c6ef51ee1)
c6ef51ee1 queue: row 178 re-pinned to the mos-0881 brief (rev 2045, Sage)
30622a229 sage: row 178 brief, the turn-on doesn't wait for Jason (mos-0881), with roll-back-at-once on a failed signed-in check; bc310ee pod-label part recorded
47a351add log: rows 176 and 178 briefs revised for mos-0878 (80cabd935, c4e049319)
c4e049319 queue: rows 176 and 178 re-pinned to the mos-0878 briefs, row 178 piece updated and after set to 169, 175, 176 (revs 2041-2044, Sage, mos-0878)
80cabd935 sage: row 176 brief adds the credentials-body and project-root tests (mos-0878 Q1); row 178 brief rewritten for mos-0878 Q2: partial fix after the window rows, console-proof.token slot, ops-01 SealedSecret and middleware under R27, console-allowed-uid recorded as decision 101's uid and left alone
0750b6a49 log: rows 176-178 filed (#1674-#1676, mos-0872, mos-0874), row 175 briefed and claimed
58e173535 queue: rows 176 (#1674), 177 (#1675) and 178 (#1676) added (revs 2038-2040, Sage, mos-0872, mos-0874)
6ee7285c0 sage: briefs for rows 176 (#1674, Console tester listener on 127.0.0.1, 7332 refuses x-mosaic-tester, mos-0872/0874), 177 (#1675, tester threads, scoping) and 178 (#1676, Traefik proof for signed-in requests, Vikunja #385, mos-0874)
835941b7c queue: row 175 widened to tester writes and briefed with no after (revs 2032-2036, Sage, mos-0870 N2, mos-0872); also Dewey's rev 2037 (dewey-175-claim, row 175 in-progress)
1c90c68c5 sage: row 175 brief widened to tester reads and writes (#1673, Q173, mos-0870 N2, mos-0872 Q1-Q3): seven writes recorded as tester, nine human-only items, prefix lifted, project init --tester inside the data root's project area only
d195d171c log: row 166 landed (4b738e2da, #1663 closed), row 175 filed (#1673, mos-0868)
6b8f94524 queue: row 166 done with landing note (revs 2029-2030), row 175 added after 169 (#1673, mos-0868, rev 2031); Sage revs only
f8ac674cc sage: brief for row 175 (#1673, --tester on the window reads, mos-0868); Window B doc after mos-0866 F1-F3 and mos-0868: W4 from the unit template, agents to Mos with --tester, Jason's reads in J1 and J2
4b738e2da stack-release: refuse unreadable drop-ins and quoted units, recheck the bus after a held read, gate on the target copy (row 166, #1663)
64922106d sage: carry-past-row64 names Vikunja P19 #383, no pi window before the pi credential is settled (mos-0865 D2)
c7424db50 log: row 64 closed, D2 coder sessions on both harnesses, #1557 closed (mos-0863, mos-0864)
5cabf919e queue: row 64 done, landing note with D2 #1557 comment 29228 (mos-0864; Sage revs 2027-2028)
c87865ee0 sage: row 64 D2 evidence, scratch-root builder, driver, check and both coder manifests (mos-0863 D2, #1557 comment 29228)
3510c3cbf queue: row 174 for #1672, skill read BOM and fs errors after row 173, not started (mos-0863 D4; Sage rev 2026)
9c80ba7f1 plans: brief for #1672, skill reads keep a leading BOM and report fs errors as skill-refused (row 64 N2/N3, mos-0863 D4)
46de60893 sage: window carry step for any pin past row 64, install and activate the seven role skills from the pinned copy (mos-0863 D3, #1557)
ebfc23c43 sage: row 64 packet, build notes, both gates, mutants and the landing manifest; BUILD.md item 5 corrected for Darkwing N1 (mos-0863 D5, #1557)
6b6567b8b harness: README names bundle-refused for the skill content refusals, skill-refused at the launcher (row 64 F1, #1557 comment 29218)
9f0039711 roles, harness, cli: a managed session gets its role's skills as prompt text on both harnesses (row 64, #1557)
1a01f63ea queue: row 64 round 1 approvals, Filbert rev 2024 and Darkwing rev 2025 on manifest 7689cd9b (#1557)
7c81d5e9c sessions: Filbert row 64 r1 review, approve
12ac2c428 sessions: Sage line for row 64 candidate, gate and in-review round 1
e76c73f72 queue: row 64 started and in-review round 1 on c6d7d538f, reviewers darkwing and filbert (#1557, Sage revs 2022-2023 and the start rev)
087d202bc queue: row 173 for the Seen click intent gap after row 172 (#1671, mos-0861 A1; Sage rev 2021)
a0da43dab plans: brief for the Seen click intent gap after row 172 (#1671, mos-0861 A1)
b5d4d0f22 sessions: Sage line for the row 172 landing and close-out
c24fe5d0f build-log: row 172 landing, the dropped Seen click and the row 165 reload race (#1670)
83db85aa3 queue: row 172 round 1 Darkwing approve (darkwing rev 2018), landing note and done (Sage revs 2019-2020)
be10e0c83 webui: a Seen click during a Board read waits for the read and posts, and the row 165 test loads the page instead of reloading from an evaluate (row 172, #1670)
7f38a2f54 sage: row 172 packet, base control and trace lines corrected (Darkwing D1, D2 on #1670)
0ed9412fc sessions: Sage line for the 170/171/134 build-log and row 172 round 1
9d6e47dd5 queue: row 172 brief re-pin, briefed, start and round 1 in-review on 15c3d8ca1 (Sage revs 2013-2017)
17d566305 sage: row 172 packet, candidate 15c3d8ca1 (cause trace, mutants, 10-run loop, gate)
164e1f97f row 172 brief: the cause is a Seen click dropped during a Board read, and the reload race in the row 165 test (P19 366, #1670)
bab069b3c build-log: rows 170, 171 and 134 landings, with the row 134 range-diff evidence (mos-0859/0860)
b42934b85 queue: row 134 done on 3a600cf5b (Sage revs 2011-2012: note, done)
a85e573d4 cli README: the chief of staff reads the organization revision with organization_revision, not from the human (row 134 follow-up, Filbert #1669 29193)
3a600cf5b bus, harness: a role holding organization.change reads the organization revision itself with organization.revision and the organization_revision tool (row 134, #1669)
04155deff queue: row 171 done on 078518e4e, plus revs 1996-2010 (Sage: 171 reopen/request/note/done, 172 add, 134 review request; Rocko 1997-1998 row 171 round 2 in-review; Researcher 2002-2004 row 134 start and round 1 in-review; Dewey 2007 row 171 approve; Filbert 2008 row 134 approve)
078518e4e bus, cli, webui: a thread project named like a business-file repo refuses project-name-is-repo unless --repo matches, with a clearer CLI refusal (row 171, #1668)
b2d3b6c47 sessions: Filbert row 134 r1 review, approve
ed045ac84 dewey: SESSIONS line for the row 171 round 2 review (#1668)
4d9114ab4 sage: row 172 brief, the board-held sign-out wait under gate load (P19 366, #1670, mos-0858); cause section open until traced
d58c9c5cd queue: row 170 done on cb43dcb45, plus revs 1970-1994 (Sage: 171 scope/re-pin/request/note, 134 re-pins/assign/issue/briefed, 64 and 66 re-pins, 64 start, 170 note and range-diff; Rocko 1970, 1973-1974 row 171 start and round 1; Dewey 1971, 1981-1982 row 170 claim and in-review, 1990 row 171 approve; Filbert 1986 row 170 approve)
cb43dcb45 bus, cli: a tester message to a role nobody holds refuses tester-target-not-running, and talk --tester exits 3 (row 170, #1667)
228aeb503 sage: rows 64/66 brief, skills reach both harnesses as prompt text (pi read is workspace-confined, Claude Code Skill tool offers its own skills; probe in agents/sage/work/queue-64/probe.md)
c9f6e214f dewey: SESSIONS line for the row 171 round 1 review (#1668)
2cef8cd35 sage: row 134 brief owns the three stale revision-from-the-human sentences (Researcher build report)
9b11b8731 sessions: Filbert row 170 r1 review, approve
2e9fe381f docs: register Sage's rows 171, 134, 64 and 66 brief work and the b0721a0b0 push correction
e0bf9960d sage: rows 64 and 66 brief refreshed to 7319bd867 after row 65 (harness module files owned, plugins suite in the gates), row 64 candidate names Sage as author and gate owner (mos-0855)
b0721a0b0 dewey: SESSIONS line for the row 170 build and in-review (#1667)
7319bd867 sage: row 171 brief names cli.mjs (sage-1021, mos-0855), row 134 brief refreshed to 000730949 with owner Researcher, row 42 run log takes mos-0855's triggers (#1668)
000730949 queue: rows 170 and 171 briefed on Mos's approval, row 171 re-pinned to the mos-0854 brief (mos-0854, #1667, #1668) (revs 1964-1969)
fcfa577f2 sage: row 171 brief cites mos-0854 (D1 withdrawn, option B approved) in place of its open decision section (#1668)
92160cb30 queue: rows 170 (P19 380, #1667) and 171 (P19 379, #1668) added queued, briefs 97cc7f0a3 await Mos; Darkwing's row 169 claim (revs 1961-1963)
97cc7f0a3 sage: briefs for P19 380 (tester refusal, #1667, row 170) and P19 379 (project names vs repos, option B, #1668, row 171), for Mos's approval
42817065e queue: row 169 after cleared, in-review waits on 166's landing by note (mos-0852 point 5, #1666) (revs 1959-1960)
56534526b sage: Window B last section rewritten for the approved two-phase path, row 169 (mos-0848 (b), mos-0852, #1558, #1666)
cbdcf1967 queue: row 169 briefed on Mos's brief approval (mos-0852, #1666) (rev 1958)
3ff2360dc sage: Window B P3 recorded done from Darkwing's rehearsal, with what it didn't exercise (#1558)
c5b74bef2 darkwing: Window B P3 scratch rehearsal, activate --pm --migrate 3h to 3i and rollback --restore on blob 4b16e848 (sage-1004, mos-0838 D2, #1558)
3b5c964eb queue: row 169, the stack-release.sh two-phase PM start (P19 382, #1666), brief pinned at bfc5fa7ba36e (revs 1956-1957)
b201760c5 sage: W6 business instances from $C_NEW and the project list channel note in plan A, verb routes checked in A and B (mos-0851), row 169 in the 382 brief (#1558, #1666)
bd8416bc2 plans: brief for P19 382, activate past c216f47db with the PM launched after the harness kind is set (mos-0848, #1666)
421217411 sage: Window A P2 CONSOLE_PASS and the post-W5b channel undo before rollback (mos-0849, #1558)
6e7c23d7d sage: Darkwing's Window A and B scratch --plan and load checks, cited in both plans (#1558)
855c9eb01 sage: Window A and B plans with mos-0846 U1, the 382 bus-exit finding, mos-0845 P19 comments (#1558)
6dbc67302 sage: Window A and B plans with mos-0845 rulings, P19 378-382 filing scripts (#1558)
894ce3f37 sage: file row 65 follow-ups as P19 376 and 377 (mos-0842 item 4, #1558)
73bbbee81 sessions: Sage row 65 landing, c216f47db with gate g3 green (#1558)
a5810fc84 build-log: row 65 landed as c216f47db, gate g3 green, mos-0841 conditions met, not live (#1558)
71fd9b922 queue: row 65 done, landed as c216f47db on #1558 (sage rev 1955)
aed9062b4 sage: row 65 landing notes, c216f47db with gate g3 green, the mos-0840 Routing view, the plugins set patch for Jason, follow-up 5 (#1558)
c216f47db plugins, cli, bus, business, webui: harness, model and thinking from the instance vars, a fallback route, and a harness plug-in kind (row 65, #1558)
866f3c5a8 queue: row 65 round 2 in review on #1558 with candidate 8d7c9e2f1, request 29143 (sage revs 1951-1952); darkwing approve (rev 1953, comment 29144) and dewey approve (rev 1954, comment 29145), both on manifest 8df15e39
24320f80c sessions: Dewey row 65 round 2 review, approve (comment 29145, rev 1954)
b4c9cb359 sage: row 65 round 2 packet, candidate 8d7c9e2f1 on 89ddb0225, manifest, diff, public/ diff (digest a91cf866 unchanged), build notes, gate and 18 mutants (#1558)
89ddb0225 queue: row 65 round 1 verdicts, dewey changes (rev 1947, comment 29136) and darkwing changes (rev 1948, comment 29137); sage moves row 65 back to in-progress (rev 1949) and re-pins the brief to blob 0cdff8739051 (rev 1950) for round 2 (#1558)
0235fa9fd brief: row 65 routing table names the chief of staff's Q169 assistant exception and its tests (round 2 ruling, sage-1006, #1558)
ff9edc778 sessions: Dewey row 65 round 1 review, changes (comment 29136, rev 1947)
9014f9f72 sessions: Sage row 65 build, Mos decision 123 go (mos-0841) and in-review
4c6649454 queue: row 65 in review, round 1 on #1558 with candidate ccdbc2232, request 29133 (sage revs 1945-1946)
1d5897024 sage: row 65 packet, candidate ccdbc2232 manifest, diff, public/ diff, build notes, gate and mutants (#1558)
d8336daef queue: row 65 brief re-pinned for the human-only routes.set verb (sage rev 1944)
841e0b0a2 brief: row 65 routing table saves through a human-only routes.set verb, outside ORGANIZATION_KEYS
4d856a0cd queue: row 65 brief re-pinned to 54cbf1a2 for the Console routing table, and its gate names Mos's decision 123 check (sage revs 1942-1943)
d3af6db97 brief: row 65 adds a Console routing table for harness, model, thinking and fallback (mos-0840), and refuses thinking a harness can't apply
b65e6d5fe sessions: Sage row 168 landing, row 65 brief amendment (decision 151), row 7 posts
e1bfc2cd4 queue: row 65 in progress and brief re-pinned to 802e046c with its gate, row 168 approved by Dewey and done (sage revs 1937, 1939-1941; dewey rev 1938)
8e2cbb555 brief: row 65 keeps the instance vars as its one source, adds fallback vars and the full harness list (decision 151, #1558)
efb51169d ledger: count only stack issue numbers, a tracker-name skip and a --first-issue floor (#1665)
54786df03 sessions: Dewey row 168 review round 1, approve (29121)
c34deedf9 sessions: Sage row 168 build and review request, P19 371 rulings
3bf16114a queue: row 168 in review round 1, manifest candidate, request 29120 (sage, revs 1935-1936)
6da8fdaa9 sage: row 168 packet, candidate f3a966ea4 manifest, diff, build notes and gate (#1665)
e2ad3aa10 queue: row 168 in progress, brief re-pinned to 52ac1975 and piece updated (sage, revs 1932-1934)
03586947a docs: row 168 brief amended before build, floor moves to a --first-issue option (#1665); window-plan: mos-0838 rulings in the 3i draft
e69e646b4 window-plan: P19 371 3i window draft for Mos, one or two windows and the restore caveat
c16ba2f0c queue: row 168 ledger stack refs added and briefed, #1665 (sage)
a1572a8f7 docs: brief for the ledger counting only stack issue numbers (#1665, P19 372, row 7 follow-up)
15357b4ba sessions: Sage AM standup and row 7 week 10-11 ledger rerun record
b90d944c8 queue: row 7 note, 10-11..10-17 ledger rerun 29089 (sage)
296972652 queue: row 126 Filbert r2 approve and done (sage)
a267a64b1 sessions: Sage row 126 landing, P19 371 and 372, row 7 week ledger; Dewey queue-126 packet
ca15d73e9 limits: a daily token quota for the account the stack uses, and bus schema 3h to 3i (row 126, #1620)
54319f552 sessions: Filbert row 126 r2 review, approve
4c385db45 sessions: Dewey row 126 round 4 build and review rounds 1-2
2124cfa76 queue: row 126 Filbert r1 approve, brief re-pin for 3h to 3i, row 7 week note, round 2 in-review (sage)
e264db51b plans: row 126 brief names the 3h to 3i step and the account guard (#1620)
1df04f52f sessions: Filbert row 126 r1 review, approve
9e2b26866 queue: row 167 Filbert approve and done, row 126 round 1 in-review (sage)
640a1ee97 sessions: Sage row 167 landing and row 126 3i ruling
pm: the bus starts without --pm and the PM stays pending; next: Jason's plugins set of harness, then pm-on
bus: scripts/bus-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
Console: scripts/webui-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
CLI: scripts/stack-copy.sh wrapper 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
# exit 0
# STOP: W3 names tester-port-target
@@ -0,0 +1,36 @@
{
"schema": "3h",
"tables": {
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "04f8f0d94725145f7204a37d232fbf19c5c4f1e2930fda37482dff5b5cd484e4"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "15169aaf4e94d892f2202d0fd7d5af79b75ba017d23375ae389bae25dcc16edb"
}
}
}
@@ -0,0 +1,25 @@
9cbf9a23e41e546a6b92a3403ee800e6e325ca5c9065e9580fd3678c304dd979 ./b/all.sh
6b25b038e3d7f4d12d169613a6f7e214d2c4f69e34fb98d446f4adad3876e44d ./b/claude
4f9dffbf3d6e75e14b19f8d4ef45b390e4997cccc61caa9323cf822ffed4c58c ./b/cmp.mjs
0b9147124dbef220a2a17c647b2f9582155ff25c5ee3712378ef2d07c978ba66 ./b/env.sh
89c201e59d7bb6427041734757d170df7c9b39d96d8cb680a57fbb9eff5ab5aa ./b/healthz.cjs
fb1f19bb5a464d575ffdeb133a9a2df7fdf507218e683fddaaa170280d5c9fed ./b/jget.mjs
e1dcabdd3e43cae6f885a44fc1fe357406c00d896c03fff889f8b61dd4e15683 ./b/journalctl
2aed6b4762c6f48cd338f15134822118dddac9ce6246ef5c4fc9faff6f80178e ./b/load-check.mjs
dc9ebad483d55f8016b73d6fb36a7b6e6d7921bc052a605aeabec8a650136ed0 ./b/mkbiz.mjs
7a0821f59d23d318d7d2d5a24b24f774548acc25c31da15d92566e9d6c614f42 ./b/prep.sh
907fc0f09e8295ed27ed192027c3b8b1b4cb65dc61f2b5147f7dc85f0c403656 ./b/run.sh
073f1952e35f464fe26fa9c86161b322c3f10f20814128b000b9c368e5c9de2a ./b/seed.sh
98d10dc85c7ea32e032529935d2cf39b4d63196e5e7ab05bd4332b43833e88fb ./b/store-seed.mjs
e3669292be33f8b8298d9d1a00ba19e5ca42e3b50fc995007c9fc4587d0df6cd ./b/systemctl
30908331d33adead6e32b9da5b77ca29283f42446636527946541618331dc8a2 ./b/systemd-analyze
6e9494e2b4f306ca2320f0cc274d9d4aeb925c73cc94a9c678f607a2b14667ed ./b/teardown.sh
0a4884269bd5914075294e803262078bd7aa12c8b8e119b1aa7b8d58fb8c5f72 ./b/wait-run.sh
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-after.txt
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-before.txt
b11af385614d04a034fa122bd1c7c99c6b6b89516a1e3475cb379829f3103122 ./p3-live-store-stat.txt
dd52bd729f6c5e12e48c0136f85df424868248358d5faeb2910d090b3af5cdb1 ./p3-steps.log
fc9d1a2284c4d69836144314d48afc430822e35e3acdf9b52b5d0969556227b6 ./p3-teardown.txt
8ce043eb37f4bbf8d2bc45a3b55d6bdc5717e4913e1ef26b5c7eabf8f7cc58d8 ./p3.txt
9e3ee240b117169fe3f252fc6b4f6834c7bf5629015a5f00764a18f44aa7bd60 ./snap/S1.json
d4202b7bee78b0b8e4e2738c63f22d3e898d310948b2e06d0b7bb17b9bd1558c ./W3-plan.txt
@@ -0,0 +1,152 @@
plan: activate for mosaic-stack
from: 5fa9cc8f2c66b52408b652b59c3070f7210b44d0
to: 8e888014d4f4bbbe7f1e6fa598003c374c169856
store schema: 3h (read from the store the running bus holds)
target schema: 3i
migration: 3h to 3i, after a backup of the stopped store
migration steps: 3h to 3i
needs: --migrate (given)
needs: Jason present for this run (decision 96 condition 2)
commits: the run adds 138 (newest first, at most 200):
8e888014d log: row 175 landed (98d29769e), row 176 brief amended and launched, merged window drafted; sessions: Sage
473258a51 queue: revs 2072-2076: row 175 round 3 approve on 2e30f2a1 (Filbert 2072, comment 29279), landing note and done after 98d29769e (Sage 2073, 2074); row 176 brief re-pinned to 0f7119af9566 for the stack-release --tester-port pointer change and row 175 F1 (Sage 2075), queued to briefed (Sage 2076)
2fecddfba sage: row 176 brief: activate --tester-port N writes the flag into the pointer's Console flags, a rollback or an activate to a copy whose Console lacks it drops it, tester-port-target refuses before anything stops; tests and three mutants; row 175 F1 (TOOLS.md step 2) rides along
98d29769e bus, cli: tester reads and the W1-W7 tester writes, recorded as tester; scripts/mosaic sends plugins, name and names to the CLI (row 175, #1673)
1d81c54ff sessions: Filbert row 175 r3 review, approve
716ddcf1e queue: revs 2058-2071: row 179 start, in-review and request (Darkwing 2058, 2060, 2061), issue #1677 (Sage 2059), r1 approve (Dewey 2062, comment 29271), landing note and done after 9e74925c2 (Sage 2063, 2064); row 175 r2 request on f9e41b918 (Dewey 2065-2067, comment 29275), back to in-progress to rebase onto 9e74925c2 (Sage 2068, 2069), round 3 request on the rebased candidate 2e30f2a1 (Dewey 2070, 2071, comment 29276)
0f45a3e6e sessions: Dewey row 175 round 2 to in-review on 989699f7c, row 179 approved
9e74925c2 docs: TOOLS.md follow-ups F1-F3 from the row 169 review (row 179, #1677)
ce5807989 log: row 169 landed (264756a30), row 179 briefed, row 175 to round 2 (1bfc9833b)
1bfc9833b queue: revs 2052-2057: row 179 added and briefed (Sage 2052, 2057), row 169 landing notes and done after 264756a30 (Sage 2053, 2054, 2056), row 175 r1 approve recorded (Filbert 2055, comment 29264)
c98a5d17a sessions: Dewey row 175 round 1 approved
8f2ac5236 sessions: Filbert row 175 r1 review, approve
264756a30 stack-release: activate --pm-after-harness, pm-on and the pending pointer, so a re-pin past c216f47db starts the PM after the harness kind is set (row 169, #1666)
b2a75f318 sage: brief for the row 169 TOOLS.md follow-ups F1-F3 (Filbert, #1666 comment 29263), owner Darkwing, reviewer Dewey, after row 169
e7d47c346 log: rows 169 and 175 in-review, row 169 r1 approve, queue revs 2046-2051 (cb4a8bf1f)
cb4a8bf1f queue: revs 2046-2051: row 169 in-review round 1 (Darkwing 2046-2047), row 175 brief re-pin for the wrapper fix (Sage 2048), row 175 in-review round 1 on 7b27ab3f9 (Dewey 2049-2050), row 169 r1 approve recorded (Filbert 2051, comment 29263)
c7939a568 sessions: Filbert row 169 r1 review, approve
423ff5c86 sessions: Dewey row 175 round 1 in-review
3dfaea286 sage: row 175 brief carries the scripts/mosaic dispatch fix (plugins, name, names, follow, threads, thread go to packages/cli), test 12 and a mutant; found in Darkwing's row 169 rehearsal
d63cfca22 log: row 178 brief for mos-0881 (30622a229, c6ef51ee1)
c6ef51ee1 queue: row 178 re-pinned to the mos-0881 brief (rev 2045, Sage)
30622a229 sage: row 178 brief, the turn-on doesn't wait for Jason (mos-0881), with roll-back-at-once on a failed signed-in check; bc310ee pod-label part recorded
47a351add log: rows 176 and 178 briefs revised for mos-0878 (80cabd935, c4e049319)
c4e049319 queue: rows 176 and 178 re-pinned to the mos-0878 briefs, row 178 piece updated and after set to 169, 175, 176 (revs 2041-2044, Sage, mos-0878)
80cabd935 sage: row 176 brief adds the credentials-body and project-root tests (mos-0878 Q1); row 178 brief rewritten for mos-0878 Q2: partial fix after the window rows, console-proof.token slot, ops-01 SealedSecret and middleware under R27, console-allowed-uid recorded as decision 101's uid and left alone
0750b6a49 log: rows 176-178 filed (#1674-#1676, mos-0872, mos-0874), row 175 briefed and claimed
58e173535 queue: rows 176 (#1674), 177 (#1675) and 178 (#1676) added (revs 2038-2040, Sage, mos-0872, mos-0874)
6ee7285c0 sage: briefs for rows 176 (#1674, Console tester listener on 127.0.0.1, 7332 refuses x-mosaic-tester, mos-0872/0874), 177 (#1675, tester threads, scoping) and 178 (#1676, Traefik proof for signed-in requests, Vikunja #385, mos-0874)
835941b7c queue: row 175 widened to tester writes and briefed with no after (revs 2032-2036, Sage, mos-0870 N2, mos-0872); also Dewey's rev 2037 (dewey-175-claim, row 175 in-progress)
1c90c68c5 sage: row 175 brief widened to tester reads and writes (#1673, Q173, mos-0870 N2, mos-0872 Q1-Q3): seven writes recorded as tester, nine human-only items, prefix lifted, project init --tester inside the data root's project area only
d195d171c log: row 166 landed (4b738e2da, #1663 closed), row 175 filed (#1673, mos-0868)
6b8f94524 queue: row 166 done with landing note (revs 2029-2030), row 175 added after 169 (#1673, mos-0868, rev 2031); Sage revs only
f8ac674cc sage: brief for row 175 (#1673, --tester on the window reads, mos-0868); Window B doc after mos-0866 F1-F3 and mos-0868: W4 from the unit template, agents to Mos with --tester, Jason's reads in J1 and J2
4b738e2da stack-release: refuse unreadable drop-ins and quoted units, recheck the bus after a held read, gate on the target copy (row 166, #1663)
64922106d sage: carry-past-row64 names Vikunja P19 #383, no pi window before the pi credential is settled (mos-0865 D2)
c7424db50 log: row 64 closed, D2 coder sessions on both harnesses, #1557 closed (mos-0863, mos-0864)
5cabf919e queue: row 64 done, landing note with D2 #1557 comment 29228 (mos-0864; Sage revs 2027-2028)
c87865ee0 sage: row 64 D2 evidence, scratch-root builder, driver, check and both coder manifests (mos-0863 D2, #1557 comment 29228)
3510c3cbf queue: row 174 for #1672, skill read BOM and fs errors after row 173, not started (mos-0863 D4; Sage rev 2026)
9c80ba7f1 plans: brief for #1672, skill reads keep a leading BOM and report fs errors as skill-refused (row 64 N2/N3, mos-0863 D4)
46de60893 sage: window carry step for any pin past row 64, install and activate the seven role skills from the pinned copy (mos-0863 D3, #1557)
ebfc23c43 sage: row 64 packet, build notes, both gates, mutants and the landing manifest; BUILD.md item 5 corrected for Darkwing N1 (mos-0863 D5, #1557)
6b6567b8b harness: README names bundle-refused for the skill content refusals, skill-refused at the launcher (row 64 F1, #1557 comment 29218)
9f0039711 roles, harness, cli: a managed session gets its role's skills as prompt text on both harnesses (row 64, #1557)
1a01f63ea queue: row 64 round 1 approvals, Filbert rev 2024 and Darkwing rev 2025 on manifest 7689cd9b (#1557)
7c81d5e9c sessions: Filbert row 64 r1 review, approve
12ac2c428 sessions: Sage line for row 64 candidate, gate and in-review round 1
e76c73f72 queue: row 64 started and in-review round 1 on c6d7d538f, reviewers darkwing and filbert (#1557, Sage revs 2022-2023 and the start rev)
087d202bc queue: row 173 for the Seen click intent gap after row 172 (#1671, mos-0861 A1; Sage rev 2021)
a0da43dab plans: brief for the Seen click intent gap after row 172 (#1671, mos-0861 A1)
b5d4d0f22 sessions: Sage line for the row 172 landing and close-out
c24fe5d0f build-log: row 172 landing, the dropped Seen click and the row 165 reload race (#1670)
83db85aa3 queue: row 172 round 1 Darkwing approve (darkwing rev 2018), landing note and done (Sage revs 2019-2020)
be10e0c83 webui: a Seen click during a Board read waits for the read and posts, and the row 165 test loads the page instead of reloading from an evaluate (row 172, #1670)
7f38a2f54 sage: row 172 packet, base control and trace lines corrected (Darkwing D1, D2 on #1670)
0ed9412fc sessions: Sage line for the 170/171/134 build-log and row 172 round 1
9d6e47dd5 queue: row 172 brief re-pin, briefed, start and round 1 in-review on 15c3d8ca1 (Sage revs 2013-2017)
17d566305 sage: row 172 packet, candidate 15c3d8ca1 (cause trace, mutants, 10-run loop, gate)
164e1f97f row 172 brief: the cause is a Seen click dropped during a Board read, and the reload race in the row 165 test (P19 366, #1670)
bab069b3c build-log: rows 170, 171 and 134 landings, with the row 134 range-diff evidence (mos-0859/0860)
b42934b85 queue: row 134 done on 3a600cf5b (Sage revs 2011-2012: note, done)
a85e573d4 cli README: the chief of staff reads the organization revision with organization_revision, not from the human (row 134 follow-up, Filbert #1669 29193)
3a600cf5b bus, harness: a role holding organization.change reads the organization revision itself with organization.revision and the organization_revision tool (row 134, #1669)
04155deff queue: row 171 done on 078518e4e, plus revs 1996-2010 (Sage: 171 reopen/request/note/done, 172 add, 134 review request; Rocko 1997-1998 row 171 round 2 in-review; Researcher 2002-2004 row 134 start and round 1 in-review; Dewey 2007 row 171 approve; Filbert 2008 row 134 approve)
078518e4e bus, cli, webui: a thread project named like a business-file repo refuses project-name-is-repo unless --repo matches, with a clearer CLI refusal (row 171, #1668)
b2d3b6c47 sessions: Filbert row 134 r1 review, approve
ed045ac84 dewey: SESSIONS line for the row 171 round 2 review (#1668)
4d9114ab4 sage: row 172 brief, the board-held sign-out wait under gate load (P19 366, #1670, mos-0858); cause section open until traced
d58c9c5cd queue: row 170 done on cb43dcb45, plus revs 1970-1994 (Sage: 171 scope/re-pin/request/note, 134 re-pins/assign/issue/briefed, 64 and 66 re-pins, 64 start, 170 note and range-diff; Rocko 1970, 1973-1974 row 171 start and round 1; Dewey 1971, 1981-1982 row 170 claim and in-review, 1990 row 171 approve; Filbert 1986 row 170 approve)
cb43dcb45 bus, cli: a tester message to a role nobody holds refuses tester-target-not-running, and talk --tester exits 3 (row 170, #1667)
228aeb503 sage: rows 64/66 brief, skills reach both harnesses as prompt text (pi read is workspace-confined, Claude Code Skill tool offers its own skills; probe in agents/sage/work/queue-64/probe.md)
c9f6e214f dewey: SESSIONS line for the row 171 round 1 review (#1668)
2cef8cd35 sage: row 134 brief owns the three stale revision-from-the-human sentences (Researcher build report)
9b11b8731 sessions: Filbert row 170 r1 review, approve
2e9fe381f docs: register Sage's rows 171, 134, 64 and 66 brief work and the b0721a0b0 push correction
e0bf9960d sage: rows 64 and 66 brief refreshed to 7319bd867 after row 65 (harness module files owned, plugins suite in the gates), row 64 candidate names Sage as author and gate owner (mos-0855)
b0721a0b0 dewey: SESSIONS line for the row 170 build and in-review (#1667)
7319bd867 sage: row 171 brief names cli.mjs (sage-1021, mos-0855), row 134 brief refreshed to 000730949 with owner Researcher, row 42 run log takes mos-0855's triggers (#1668)
000730949 queue: rows 170 and 171 briefed on Mos's approval, row 171 re-pinned to the mos-0854 brief (mos-0854, #1667, #1668) (revs 1964-1969)
fcfa577f2 sage: row 171 brief cites mos-0854 (D1 withdrawn, option B approved) in place of its open decision section (#1668)
92160cb30 queue: rows 170 (P19 380, #1667) and 171 (P19 379, #1668) added queued, briefs 97cc7f0a3 await Mos; Darkwing's row 169 claim (revs 1961-1963)
97cc7f0a3 sage: briefs for P19 380 (tester refusal, #1667, row 170) and P19 379 (project names vs repos, option B, #1668, row 171), for Mos's approval
42817065e queue: row 169 after cleared, in-review waits on 166's landing by note (mos-0852 point 5, #1666) (revs 1959-1960)
56534526b sage: Window B last section rewritten for the approved two-phase path, row 169 (mos-0848 (b), mos-0852, #1558, #1666)
cbdcf1967 queue: row 169 briefed on Mos's brief approval (mos-0852, #1666) (rev 1958)
3ff2360dc sage: Window B P3 recorded done from Darkwing's rehearsal, with what it didn't exercise (#1558)
c5b74bef2 darkwing: Window B P3 scratch rehearsal, activate --pm --migrate 3h to 3i and rollback --restore on blob 4b16e848 (sage-1004, mos-0838 D2, #1558)
3b5c964eb queue: row 169, the stack-release.sh two-phase PM start (P19 382, #1666), brief pinned at bfc5fa7ba36e (revs 1956-1957)
b201760c5 sage: W6 business instances from $C_NEW and the project list channel note in plan A, verb routes checked in A and B (mos-0851), row 169 in the 382 brief (#1558, #1666)
bd8416bc2 plans: brief for P19 382, activate past c216f47db with the PM launched after the harness kind is set (mos-0848, #1666)
421217411 sage: Window A P2 CONSOLE_PASS and the post-W5b channel undo before rollback (mos-0849, #1558)
6e7c23d7d sage: Darkwing's Window A and B scratch --plan and load checks, cited in both plans (#1558)
855c9eb01 sage: Window A and B plans with mos-0846 U1, the 382 bus-exit finding, mos-0845 P19 comments (#1558)
6dbc67302 sage: Window A and B plans with mos-0845 rulings, P19 378-382 filing scripts (#1558)
894ce3f37 sage: file row 65 follow-ups as P19 376 and 377 (mos-0842 item 4, #1558)
73bbbee81 sessions: Sage row 65 landing, c216f47db with gate g3 green (#1558)
a5810fc84 build-log: row 65 landed as c216f47db, gate g3 green, mos-0841 conditions met, not live (#1558)
71fd9b922 queue: row 65 done, landed as c216f47db on #1558 (sage rev 1955)
aed9062b4 sage: row 65 landing notes, c216f47db with gate g3 green, the mos-0840 Routing view, the plugins set patch for Jason, follow-up 5 (#1558)
c216f47db plugins, cli, bus, business, webui: harness, model and thinking from the instance vars, a fallback route, and a harness plug-in kind (row 65, #1558)
866f3c5a8 queue: row 65 round 2 in review on #1558 with candidate 8d7c9e2f1, request 29143 (sage revs 1951-1952); darkwing approve (rev 1953, comment 29144) and dewey approve (rev 1954, comment 29145), both on manifest 8df15e39
24320f80c sessions: Dewey row 65 round 2 review, approve (comment 29145, rev 1954)
b4c9cb359 sage: row 65 round 2 packet, candidate 8d7c9e2f1 on 89ddb0225, manifest, diff, public/ diff (digest a91cf866 unchanged), build notes, gate and 18 mutants (#1558)
89ddb0225 queue: row 65 round 1 verdicts, dewey changes (rev 1947, comment 29136) and darkwing changes (rev 1948, comment 29137); sage moves row 65 back to in-progress (rev 1949) and re-pins the brief to blob 0cdff8739051 (rev 1950) for round 2 (#1558)
0235fa9fd brief: row 65 routing table names the chief of staff's Q169 assistant exception and its tests (round 2 ruling, sage-1006, #1558)
ff9edc778 sessions: Dewey row 65 round 1 review, changes (comment 29136, rev 1947)
9014f9f72 sessions: Sage row 65 build, Mos decision 123 go (mos-0841) and in-review
4c6649454 queue: row 65 in review, round 1 on #1558 with candidate ccdbc2232, request 29133 (sage revs 1945-1946)
1d5897024 sage: row 65 packet, candidate ccdbc2232 manifest, diff, public/ diff, build notes, gate and mutants (#1558)
d8336daef queue: row 65 brief re-pinned for the human-only routes.set verb (sage rev 1944)
841e0b0a2 brief: row 65 routing table saves through a human-only routes.set verb, outside ORGANIZATION_KEYS
4d856a0cd queue: row 65 brief re-pinned to 54cbf1a2 for the Console routing table, and its gate names Mos's decision 123 check (sage revs 1942-1943)
d3af6db97 brief: row 65 adds a Console routing table for harness, model, thinking and fallback (mos-0840), and refuses thinking a harness can't apply
b65e6d5fe sessions: Sage row 168 landing, row 65 brief amendment (decision 151), row 7 posts
e1bfc2cd4 queue: row 65 in progress and brief re-pinned to 802e046c with its gate, row 168 approved by Dewey and done (sage revs 1937, 1939-1941; dewey rev 1938)
8e2cbb555 brief: row 65 keeps the instance vars as its one source, adds fallback vars and the full harness list (decision 151, #1558)
efb51169d ledger: count only stack issue numbers, a tracker-name skip and a --first-issue floor (#1665)
54786df03 sessions: Dewey row 168 review round 1, approve (29121)
c34deedf9 sessions: Sage row 168 build and review request, P19 371 rulings
3bf16114a queue: row 168 in review round 1, manifest candidate, request 29120 (sage, revs 1935-1936)
6da8fdaa9 sage: row 168 packet, candidate f3a966ea4 manifest, diff, build notes and gate (#1665)
e2ad3aa10 queue: row 168 in progress, brief re-pinned to 52ac1975 and piece updated (sage, revs 1932-1934)
03586947a docs: row 168 brief amended before build, floor moves to a --first-issue option (#1665); window-plan: mos-0838 rulings in the 3i draft
e69e646b4 window-plan: P19 371 3i window draft for Mos, one or two windows and the restore caveat
c16ba2f0c queue: row 168 ledger stack refs added and briefed, #1665 (sage)
a1572a8f7 docs: brief for the ledger counting only stack issue numbers (#1665, P19 372, row 7 follow-up)
15357b4ba sessions: Sage AM standup and row 7 week 10-11 ledger rerun record
b90d944c8 queue: row 7 note, 10-11..10-17 ledger rerun 29089 (sage)
296972652 queue: row 126 Filbert r2 approve and done (sage)
a267a64b1 sessions: Sage row 126 landing, P19 371 and 372, row 7 week ledger; Dewey queue-126 packet
ca15d73e9 limits: a daily token quota for the account the stack uses, and bus schema 3h to 3i (row 126, #1620)
54319f552 sessions: Filbert row 126 r2 review, approve
4c385db45 sessions: Dewey row 126 round 4 build and review rounds 1-2
2124cfa76 queue: row 126 Filbert r1 approve, brief re-pin for 3h to 3i, row 7 week note, round 2 in-review (sage)
e264db51b plans: row 126 brief names the 3h to 3i step and the account guard (#1620)
1df04f52f sessions: Filbert row 126 r1 review, approve
9e2b26866 queue: row 167 Filbert approve and done, row 126 round 1 in-review (sage)
640a1ee97 sessions: Sage row 167 landing and row 126 3i ruling
pm: the bus starts without --pm and the PM stays pending; next: Jason's plugins set of harness, then pm-on
bus: scripts/bus-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
Console: scripts/webui-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
CLI: scripts/stack-copy.sh wrapper 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# P3 driver: the live-store stat (mos-0878), prep, seed, run, teardown, the stat again, the Docker network
# names before and after, then the outputs copied to $WIN/p3 with SHA256SUMS. Started only behind
# wait-run.sh (busy.sh) on Sage's go. NEW=<sha> TP=1 for the run on the row 176 tool blob.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$R/out" ] || { echo "all.sh: $R/out exists; move it aside first" >&2; exit 1; }
mkdir -p "$R/out"
S=$R/out/p3-live-store-stat.txt
LIVE=(/home/jwoltje/.mosaic-dev/bus/bus.sqlite /home/jwoltje/.mosaic-dev/bus)
{ echo "# before prep, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } > "$S"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-before.txt"
rc=0
"$B/prep.sh" && "$B/seed.sh" && "$B/run.sh" || rc=$?
"$B/teardown.sh"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-after.txt"
{ echo "# after teardown, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } >> "$S"
cat "$S"
if [ "$(sed -n 2,3p "$S")" = "$(sed -n 5,6p "$S")" ]; then echo "live store stat: match"; else echo "live store stat: DIFFER"; rc=1; fi
if cmp -s "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; then echo "docker networks: unchanged"; else echo "docker networks: CHANGED"; diff "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; fi
echo "all.sh: run exit $rc"
W=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/p3/$(git -C "$REPO" rev-parse --short=9 HEAD)-tp$TP
mkdir -p "$W" && cp -p "$R"/out/*.txt "$R"/out/*.json "$R/out/p3-steps.log" "$W"/ 2>/dev/null; cp -pr "$R/out/snap" "$W"/
cp -p "$B"/*.sh "$B"/*.mjs "$B"/*.cjs "$B"/systemctl "$B"/journalctl "$B"/systemd-analyze "$B"/claude "$W"/ 2>/dev/null; mkdir -p "$W/b" && mv "$W"/*.sh "$W"/*.mjs "$W"/*.cjs "$W"/systemctl "$W"/journalctl "$W"/systemd-analyze "$W"/claude "$W/b"/ 2>/dev/null
rm -f "$W/last.txt"
(cd "$W" && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS)
echo "outputs: $W ($(wc -l < "$W/SHA256SUMS") files, SHA256SUMS sha256 $(sha256sum < "$W/SHA256SUMS" | cut -c1-64))"
exit $rc
@@ -0,0 +1,3 @@
#!/bin/sh
# Fake claude for the scratch rehearsal. It never runs a model; the PM launch is emulated.
echo "9.9.9 (Claude Code fixture)"
@@ -0,0 +1,13 @@
// P3: compares two snapshot.mjs outputs table by table (rows, maxSeq, sha256, and byRun for usage_records).
// usage: node cmp.mjs A.json B.json. Prints one line per table and exits 1 if any differ.
import { readFileSync } from 'node:fs';
const [a, b] = process.argv.slice(2).map((p) => JSON.parse(readFileSync(p, 'utf8')));
let differ = 0;
for (const t of ['usage_records', 'instance_names', 'threads']) {
const x = a.tables[t], y = b.tables[t];
const same = ['rows', 'maxSeq', 'sha256'].every((k) => x[k] === y[k]) && JSON.stringify(x.byRun ?? null) === JSON.stringify(y.byRun ?? null);
console.log(`${same ? 'EQUAL' : 'DIFFER'} ${t}: rows ${x.rows}/${y.rows}, maxSeq ${x.maxSeq}/${y.maxSeq}, sha256 ${x.sha256.slice(0, 12)}/${y.sha256.slice(0, 12)}`);
if (!same) differ = 1;
}
console.log(`schema ${a.schema}/${b.schema}`);
process.exit(differ);
@@ -0,0 +1,21 @@
# Sourced by every P3 script (merged window B+C, repin-merged-bc.md P3): the scratch root and a clean env for every call.
# NEW and TP come from the caller: NEW defaults to 8e888014d (row 175's push, the dry run); TP=1 adds the
# scratch tester port to W3, W5 and the Console checks once the row 176 tool blob is in NEW.
R=/home/jwoltje/darkwing-scratch/mbc/p3
B=$R/b
RB=$R/root
REPO=$R/repo
COPIES=$R/copies
OLD=5fa9cc8f2c66b52408b652b59c3070f7210b44d0
NEW=${NEW:-8e888014d4f4bbbe7f1e6fa598003c374c169856}
TP=${TP:-0}
PORT=47394
TPORT=47395
SNAP=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs
SNAP_SHA=909a11f65c42de1dec6776a55585ad01ed960d25ff827c6b298b3293fbe46406
LOGF=$R/out/p3-steps.log
# env -i keeps every live MOSAIC_*, XDG_*, credential and pi variable out; HOME is scratch too.
E=(env -i HOME=$RB/home PATH=$B:/usr/local/bin:/usr/bin:/bin TMPDIR=$RB/tmp LANG=C.UTF-8
MOSAIC_CONFIG=$RB/cfg/config.json XDG_CONFIG_HOME=$RB/xcfg XDG_DATA_HOME=$RB/xdata
XDG_STATE_HOME=$RB/xstate XDG_RUNTIME_DIR=$RB/run SD_STATE=$RB/sd SD_DATA=$RB/data)
step() { echo "$(date -u +%FT%TZ) $*" >> "$LOGF"; }
@@ -0,0 +1,7 @@
// The Console stand-in: 200 on /healthz, 404 otherwise, on 127.0.0.1:<port>, and on 127.0.0.1:<tester port>
// too when the unit's ExecStart has --tester-port (merged window P3). Writes healthz-<pid> once every port listens.
const http=require('node:http'),fs=require('node:fs'),path=require('node:path');
const ports=process.argv.slice(2).filter(Boolean).map(Number);let up=0;
for(const p of ports)http.createServer((q,r)=>{r.writeHead(q.url==='/healthz'?200:404);r.end(q.url==='/healthz'?'ok\n':'');})
.listen(p,'127.0.0.1',()=>{if(++up===ports.length)fs.writeFileSync(path.join(process.env.SD_STATE,`healthz-${process.pid}`),'');});
process.on('SIGTERM',()=>process.exit(0));
@@ -0,0 +1,6 @@
// P3: prints one field of a JSON document on stdin, by a dotted path (a.b.c); "" when absent.
// usage: node jget.mjs PATH < doc.json
import { readFileSync } from 'node:fs';
let v = JSON.parse(readFileSync(0, 'utf8'));
for (const k of process.argv[2].split('.')) v = v == null ? undefined : v[k];
process.stdout.write(v === undefined ? '' : typeof v === 'string' ? v : JSON.stringify(v));
@@ -0,0 +1,10 @@
#!/usr/bin/node
// Stand-in `journalctl --user -u UNIT --since @EPOCH -o cat` over $SD_STATE/journal.jsonl (the test's).
const fs=require('node:fs'),path=require('node:path');
const sd=process.env.SD_STATE,a=process.argv.slice(2);let unit='',since='';
for(let i=0;i<a.length;i++){if(a[i]==='-u')unit=a[++i];else if(a[i]==='--since')since=a[++i]}
fs.appendFileSync(path.join(sd,'journal-since.log'),since+'\n');
if(!/^@\d+$/.test(since))process.exit(1);
const from=Number(since.slice(1));
let lines=[];try{lines=fs.readFileSync(path.join(sd,'journal.jsonl'),'utf8').split('\n').filter(Boolean).map((l)=>JSON.parse(l))}catch{}
for(const o of lines)if(o.unit===unit&&o.epoch>=from)console.log(o.text);
@@ -0,0 +1,18 @@
// business-check-style load (repin-de352dfaf/business-check.mjs) of a scratch business file under COPY's own
// loader and roles. usage: node load-check.mjs COPY_DIR CONFIG_DIR. Prints counts, plug-in kinds, HOLDS lines, LOAD_OK or REFUSED.
const [copy, dir] = process.argv.slice(2);
const { loadBusiness } = await import(`${copy}/packages/business/src/business.mjs`);
const { resolveInstance } = await import(`${copy}/packages/business/src/resolve.mjs`);
try {
const b = loadBusiness('mosaic-stack', { dir, rolesDir: `${copy}/roles` });
const count = (o) => Object.keys(o ?? {}).length;
console.log(`copy ${copy.split('/').pop().slice(0, 9)}: roles ${count(b.roles)}, projects ${count(b.projects)}, arbiters ${count(b.arbiters)}, plugins ${JSON.stringify(b.plugins)}`);
for (const instance of ['chief', 'pm']) {
const { limits: { authority: a } } = resolveInstance({ system: {}, business: b, instance });
console.log(`HOLDS ${instance} instance.name ${[...a.withinRole, ...a.crossRole].includes('instance.name') ? 'yes' : 'no'}`);
}
console.log('LOAD_OK');
} catch (e) {
console.log(`REFUSED ${e.message}`);
process.exit(1);
}
@@ -0,0 +1,26 @@
// Scratch business file for P3: the committed example, made loadable, with the given plug-ins (mos-0847).
// Bot ids become distinct positive integers, date placeholders become 2027-01-01, every credential file
// points at a path under NOSECRET that does not exist, and both base URLs go to 127.0.0.1:9 (discard),
// so a scratch bus never reaches the live tracker or Gitea. As the live file (P1): `bus.tester` is true
// and every role's `harness` var is claude-code, the chief's included (row 169 finding 3).
// usage: node mkbiz.mjs EXAMPLE NOSECRET PLUGINS_JSON
import { readFileSync } from 'node:fs';
import { basename } from 'node:path';
const [example, nosecret, plugins] = process.argv.slice(2);
const b = JSON.parse(readFileSync(example, 'utf8'));
let id = 0;
const walk = (o) => {
for (const [k, v] of Object.entries(o)) {
if (k === 'botId') o[k] = ++id;
else if (v === 'YYYY-MM-DD') o[k] = '2027-01-01';
else if (k === 'file' && typeof v === 'string') o[k] = `${nosecret}/${basename(v)}`;
else if (v && typeof v === 'object') walk(v);
}
};
walk(b);
b.vars['tracker.baseUrl'] = 'http://127.0.0.1:9';
b.vars['gitea.baseUrl'] = 'http://127.0.0.1:9';
b.vars['bus.tester'] = true;
for (const role of Object.values(b.roles)) role.vars = { ...(role.vars ?? {}), harness: 'claude-code' };
b.plugins = JSON.parse(plugins);
process.stdout.write(JSON.stringify(b, null, 2) + '\n');
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# P3, prep: the tool clone at NEW, the two copies and the scratch business files. Scratch paths only; the
# canonical checkout is read through git clone --shared. Unlike queue-169, no patch is applied: the tool
# is NEW's own stack-release.sh, the day's tool blob.
set -euo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$REPO" ] && [ ! -e "$COPIES" ] && [ ! -e "$R/bfiles" ] || { echo "prep.sh: $R already has a repo, copies or bfiles" >&2; exit 1; }
mkdir -p "$R/out"
git clone -q --shared --no-checkout /mnt/storage/src/mosaic-stack "$REPO"
git -C "$REPO" checkout -q --detach "$NEW"
git -C "$REPO" branch -f refactor "$NEW"
step "tool clone $REPO at $(git -C "$REPO" rev-parse HEAD), refactor $(git -C "$REPO" rev-parse refactor); scripts/stack-release.sh blob $(git -C "$REPO" rev-parse HEAD:scripts/stack-release.sh); TP=$TP"
mkdir -p "$COPIES"
for c in "$OLD" "$NEW"; do (cd "$REPO" && scripts/stack-copy.sh copy "$c" --copies "$COPIES") >> "$LOGF" 2>&1; step "copy $c: exit 0"; done
mkdir -p "$R/bfiles/B/businesses" "$R/bfiles/H/businesses"
EX="$REPO/packages/business/examples/mosaic-stack.example.json"
step "example blob $(git -C "$REPO" hash-object "$EX")"
node "$B/mkbiz.mjs" "$EX" "$R/bfiles/nosecret" '{"usage-source":["transcript"],"channel":["cli","webui"]}' > "$R/bfiles/B/businesses/mosaic-stack.json"
node "$B/mkbiz.mjs" "$EX" "$R/bfiles/nosecret" '{"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}' > "$R/bfiles/H/businesses/mosaic-stack.json"
step "business B (Window A's plug-ins, no harness) $(sha256sum < "$R/bfiles/B/businesses/mosaic-stack.json" | cut -c1-64); H (harness [\"claude-code\"]) $(sha256sum < "$R/bfiles/H/businesses/mosaic-stack.json" | cut -c1-64)"
@@ -0,0 +1,229 @@
#!/usr/bin/env bash
# Merged window B+C, P3 (repin-merged-bc.md draft 3, sage-1112, sage-1117): the rehearsal on the root
# seed.sh made at OLD 5fa9cc8f2 and 3h. Order: the load checks, W1 and S1, W2, W3, W5 and a snapshot,
# W6 as the tester, W7 (PM launch emulated), S2, a P3-only name write after the backup stamp, then the
# rollback after W6: the refusal before the harness undo, harness null as the tester, OLD's load
# check, D3, rollback --restore --plan, the run without --events, the run with --events N from D3,
# and the end state against S1. Every stack-release call names the scratch --copies and --bin.
# Scratch paths only. TP=1 adds --tester-port $TPORT to W3 and W5 and checks it is dropped on the way back.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
OUT=$R/out/p3.txt
SN=$R/out/snap
[ ! -e "$OUT" ] || { echo "run.sh: $OUT exists" >&2; exit 1; }
[ -f "$RB/data/state/stack-active.json" ] || { echo "run.sh: no seeded root" >&2; exit 1; }
mkdir -p "$SN"
SR=(scripts/stack-release.sh)
CB=(--copies "$COPIES" --bin "$RB/bin")
TPF=(); [ "$TP" = 1 ] && TPF=(--tester-port "$TPORT")
C_OLD=(node "$COPIES/$OLD/packages/cli/src/cli.mjs")
C_NEW=(node "$COPIES/$NEW/packages/cli/src/cli.mjs")
DB=$RB/data/bus/bus.sqlite
part() { # part TITLE CMD... : one labeled part of the transcript, with its command and exit code
local title="$1"; shift
{ echo; echo "## $title"; echo "# command: (cd $REPO && <scratch env> $*)"; } >> "$OUT"
step "run: $*"
local rc=0; (cd "$REPO" && "${E[@]}" "$@") > "$R/out/last.txt" 2>&1 || rc=$?
cat "$R/out/last.txt" >> "$OUT"
echo "# exit $rc" >> "$OUT"; step "exit $rc"; RC=$rc
}
note() { echo "# $*" >> "$OUT"; step "$*"; }
stop() { note "STOP: $*"; exit 1; }
expect() { [ "$RC" = "$1" ] || stop "expected exit $1, got $RC"; }
# The last part's output, less a plan's commits: block (its subject lines name refusal codes,
# 2fecddfba names tester-port-target), so has and lacks read only what the tool itself says.
body() { awk '/^commits:/{c=1;next} c && /^ /{next} {c=0;print}' "$R/out/last.txt"; }
has() { grep -qF -- "$1" <(body); } # the last part's output holds this text
lacks() { ! grep -qF -- "$1" <(body); }
lastlog() { tail -1 "$RB/data/state/stack-activation-log.jsonl"; }
pointer() { node "$B/jget.mjs" "$1" < "$RB/data/state/stack-active.json"; }
state() { # the pointer, the unit ExecStarts and the business file's plugins after a part
note "pointer: $(cat "$RB/data/state/stack-active.json")"
note "bus unit ExecStart: $(sed -n 's/^ExecStart=//p' "$RB/xcfg/systemd/user/[email protected]")"
note "Console unit ExecStart: $(sed -n 's/^ExecStart=//p' "$RB/xcfg/systemd/user/mosaic-webui.service")"
note "business file plugins: $(node -e 'console.log(JSON.stringify(require(process.argv[1]).plugins))' "$RB/cfg/businesses/mosaic-stack.json")"
note "activation log, last line: $(lastlog)"
}
snap() { # snap NAME ARGS... : snapshot.mjs on the scratch store, the output kept in out/snap/NAME.json
local name="$1"; shift
part "snapshot $name" node "$SNAP" --store "$DB" "$@"
cp "$R/out/last.txt" "$SN/$name.json"
}
same() { # same A B : the two snapshots match on every table
part "compare $1 with $2" node "$B/cmp.mjs" "$SN/$1.json" "$SN/$2.json"
}
plugins_read() { # the NEW copy's own mosaic plugins --tester --json, its output kept in out/NAME.json
part "$2" "${C_NEW[@]}" plugins --business mosaic-stack --tester --json
cp "$R/out/last.txt" "$R/out/$1.json"
}
plugins_set() { # plugins_set NAME VALUE_JSON TITLE: a patch with the revision of out/NAME-read.json, set as the tester
local rev; rev="$(node "$B/jget.mjs" revision < "$R/out/$1-read.json")"
[ -n "$rev" ] || stop "no revision in $1-read.json"
printf '{"revision":%s,"plugins":{"harness":%s}}\n' "$(node -e 'process.stdout.write(JSON.stringify(process.argv[1]))' "$rev")" "$2" > "$R/out/$1.json"
note "patch $1.json: $(cat "$R/out/$1.json")"
part "$3" "${C_NEW[@]}" plugins set --file "$R/out/$1.json" --business mosaic-stack --tester
}
receipt() { # the last organization receipt: transaction, actor, business and the plug-ins before and after
local f; f="$(find "$RB" -name changes.jsonl -path '*mosaic-stack*' | head -1)"
[ -n "$f" ] || stop "no changes.jsonl for mosaic-stack under $RB"
note "receipt file: ${f#$RB/}, $(wc -l < "$f") line(s)"
note "last receipt: $(tail -1 "$f" | node -e 'const o=JSON.parse(require("fs").readFileSync(0,"utf8"));console.log(JSON.stringify({transaction:o.transaction,actor:o.actor,business:o.business,before:o.before?.plugins,after:o.after?.plugins}))')"
}
markers() { # names only, never values: run markers in this shell's ancestors (the tester walk refuses them)
local p=$$ n=0
while [ "$p" -gt 1 ]; do
tr '\0' '\n' 2>/dev/null < "/proc/$p/environ" | grep -qE '^(MOSAIC_BUS_CAP|MOSAIC_RUN_ID|MOSAIC_AGENT_RUN)=.' && { echo "pid $p has a run marker"; n=$((n + 1)); }
p=$(awk '{print $4}' "/proc/$p/stat" 2>/dev/null) || break
done
echo "ancestors with a run marker: $n"
}
{
echo "# SCRATCH ROOT, NOT LIVE. Merged window B+C P3, run by darkwing from $(date -u +%FT%TZ) (sage-1112, sage-1117)."
echo "# Plan: agents/sage/work/window-plan/repin-merged-bc.md, sha256 $(sha256sum < /mnt/storage/src/mosaic-stack/agents/sage/work/window-plan/repin-merged-bc.md | cut -c1-64)."
echo "# Tool: $REPO, a git clone --shared of the canonical checkout at $(git -C "$REPO" rev-parse HEAD), nothing applied;"
echo "# scripts/stack-release.sh blob $(git -C "$REPO" rev-parse HEAD:scripts/stack-release.sh). refactor in the clone: $(git -C "$REPO" rev-parse refactor)."
echo "# Copies (stack-copy.sh copy): OLD $OLD, NEW $NEW. TP=$TP: $([ "$TP" = 1 ] && echo "W3 and W5 take --tester-port $TPORT" || echo "no --tester-port (the tool at this NEW predates row 176)")."
echo "# Root: $RB. Config $RB/cfg/config.json, data root $RB/data, units in $RB/xcfg/systemd/user."
echo "# Business file: the committed example (blob $(git -C "$REPO" hash-object packages/business/examples/mosaic-stack.example.json)) made loadable by mkbiz.mjs: plugins"
echo "# {\"usage-source\":[\"transcript\"],\"channel\":[\"cli\",\"webui\"]}, no harness, bus.tester true, every role's harness var claude-code;"
echo "# sha256 $(sha256sum < "$R/bfiles/B/businesses/mosaic-stack.json" | cut -c1-64)."
echo "# Store: seeded at 3h by OLD's Store before the bus first started (store-seed.mjs): 5 usage_records, 2 instance_names, 1 thread."
echo "# The harness set and its undo are the real NEW copy's mosaic plugins set --tester against the scratch bus, no stand-in."
echo "# snapshot.mjs: $SNAP, sha256 $(sha256sum < "$SNAP" | cut -c1-64) (expected $SNAP_SHA)."
echo "# Stand-ins ($B): systemctl runs the copy's real 'scripts/mosaic bus start mosaic-stack'. With pm-mode emulate a --pm"
echo "# start runs the bus WITHOUT --pm and EMULATES the PM launch: no claude runs; a waiting runner, one sessions.json entry"
echo "# and one 'launched chief' journal line stand in for it (no session credential goes to scratch). The Console is a"
echo "# /healthz stand-in on 127.0.0.1:$PORT, and on 127.0.0.1:$TPORT when the unit has --tester-port. journalctl and"
echo "# systemd-analyze are the test's; claude is a fixture that prints a version. Credential files are fake placeholders."
echo "# Environment for every call: env -i with HOME, PATH, TMPDIR, LANG, MOSAIC_CONFIG, XDG_* and SD_* only (names: $(printf '%s\n' "${E[@]:2}" | cut -d= -f1 | paste -sd' ' -))."
} > "$OUT"
step "--- run.sh"
[ "$(sha256sum < "$SNAP" | cut -c1-64)" = "$SNAP_SHA" ] || stop "snapshot.mjs is not the copy Mos read"
state
# --- the load checks (P1 shape, on the scratch file)
part "L1. business-check of OLD on a file that has harness (expect REFUSED unknown kind \"harness\")" node "$B/load-check.mjs" "$COPIES/$OLD" "$R/bfiles/H"
expect 1; has 'unknown kind "harness"' || stop 'no unknown kind "harness" refusal'
part "L2. control: NEW on the same file" node "$B/load-check.mjs" "$COPIES/$NEW" "$R/bfiles/H"; expect 0
part "L3. OLD on the rehearsal file" node "$B/load-check.mjs" "$COPIES/$OLD" "$RB/cfg"; expect 0
part "L4. NEW on the rehearsal file" node "$B/load-check.mjs" "$COPIES/$NEW" "$RB/cfg"; expect 0
part "L5. the P1 values of the rehearsal file" node -e '
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))}))' "$RB/cfg/businesses/mosaic-stack.json"
expect 0; has '"busTester":true' && has '"pluginKinds":["usage-source","channel"]' && has '"launchBy":"chief","chiefHarness":"claude-code","piRoles":[]' || stop "P1 values differ"
{ echo; echo "## L6. run markers in this shell's ancestors (names only; the tester walk refuses one)"; } >> "$OUT"
markers > "$R/out/last.txt"; cat "$R/out/last.txt" >> "$OUT"
has 'ancestors with a run marker: 0' || stop "a run marker above this shell; the tester proof would refuse"
# --- W1, S1, W2
part "W1a. agents as the tester (OLD's CLI; the chief must not be working)" "${C_OLD[@]}" agents --business mosaic-stack --tester --json
expect 0
part "W1b. launches list (OLD's CLI)" "${C_OLD[@]}" launches list --json; expect 0
note "W1 start stamp: $(date -u +%FT%TZ)"
snap S1 --held; expect 0
has '"schema": "3h"' || stop "S1 is not at 3h"
part "W2. status" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$OLD" ] && [ "$(pointer schema)" = 3h ] && [ -z "$(pointer pmPending)" ] || stop "W2: pointer not on OLD at 3h with no pending"
# --- W3, W5
part "W3. activate NEW --pm-after-harness --migrate ${TPF[*]} --plan" "${SR[@]}" activate "$NEW" mosaic-stack --pm-after-harness --migrate "${TPF[@]}" --plan "${CB[@]}"
expect 0
for c in pm-after-harness-target pm-after-harness-set unknown-kind-for-target tester-port-target; do lacks "$c" || stop "W3 names $c"; done
has '3h' && has '3i' && has '--migrate (given)' || stop "W3 plan lacks the 3h to 3i step or --migrate (given)"
[ "$TP" = 1 ] && { has "--tester-port $TPORT" || has "\"--tester-port\",\"$TPORT\"" || stop "W3 plan does not show --tester-port $TPORT in the Console flags"; }
cp "$R/out/last.txt" "$R/out/W3-plan.txt"
part "W5. activate NEW --pm-after-harness --migrate ${TPF[*]} (phase 1, migrates)" "${SR[@]}" activate "$NEW" mosaic-stack --pm-after-harness --migrate "${TPF[@]}" "${CB[@]}"
expect 0
state
ACT="$(lastlog | node "$B/jget.mjs" activation)"; BK="$(lastlog | node "$B/jget.mjs" backup)"
[ "$(lastlog | node "$B/jget.mjs" result)" = ok ] && [ -n "$ACT" ] && [ "$BK" = "$ACT" ] || stop "W5: last log line is not ok with this run's backup"
BDIR="$RB/data/backups/stack/$BK"; STAMP="$(cat "$BDIR/STAMP")"
note "W5 activation $ACT; backup $BDIR; STAMP $STAMP; SCHEMA $(cat "$BDIR/SCHEMA"); files: $(ls "$BDIR" | paste -sd' ' -)"
[ "$(cat "$BDIR/SCHEMA")" = 3h ] || stop "the backup is not at 3h"
(cd "$BDIR" && sha256sum -c --quiet SHA256SUMS) >> "$OUT" 2>&1 && note "backup SHA256SUMS: OK" || stop "backup SHA256SUMS does not check"
part "W5b. status (pending)" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$NEW" ] && [ "$(pointer schema)" = 3i ] && [ "$(pointer pm)" = false ] && [ "$(pointer pmPending)" = true ] || stop "W5: pointer not on NEW, 3i, pm false, pmPending true"
if [ "$TP" = 1 ]; then
pointer console | grep -qF "\"--tester-port\",\"$TPORT\"" || stop "W5: the pointer's Console flags lack --tester-port $TPORT"
(exec 3<>/dev/tcp/127.0.0.1/$TPORT) 2>/dev/null && note "tester port $TPORT listens (stand-in)" || stop "tester port $TPORT is closed"
fi
snap W5 --held; expect 0
has '"schema": "3i"' || stop "the store is not at 3i after W5"
same S1 W5; expect 0
# --- W6, W7, S2
plugins_read W6-read "W6a. plugins --tester --json (NEW's CLI), for the revision"; expect 0
plugins_set W6 '["claude-code"]' "W6b. plugins set harness [\"claude-code\"] as the tester"; expect 0
plugins_read W6-after "W6c. plugins read again"; expect 0
has '"harness": [' && has '"claude-code"' || stop "W6: harness is not [\"claude-code\"]"
node -e 'const a=require(process.argv[1]).plugins,b=require(process.argv[2]).plugins;process.exit(JSON.stringify(a["usage-source"])===JSON.stringify(b["usage-source"])&&JSON.stringify(a.channel)===JSON.stringify(b.channel)?0:1)' "$R/out/W6-read.json" "$R/out/W6-after.json" \
&& note "W6: usage-source and channel unchanged" || stop "W6: usage-source or channel changed"
receipt
tail -1 "$OUT" | grep -q '"actor":"tester"' || stop "W6: the receipt's actor is not tester"
part "W6d. business-check under NEW on the patched file" node "$B/load-check.mjs" "$COPIES/$NEW" "$RB/cfg"; expect 0
state
part "W7. pm-on (PM launch emulated)" "${SR[@]}" pm-on mosaic-stack "${CB[@]}"; expect 0
state
[ "$(pointer pm)" = true ] && [ -z "$(pointer pmPending)" ] || stop "W7: pointer is not pm true with no pmPending"
part "W7b. status after pm-on" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
part "W7c. launches list (NEW's CLI)" "${C_NEW[@]}" launches list --json
snap S2 --held; expect 0
same S1 S2; expect 0
# --- P3 only: one tester write after the backup stamp, so D3 has a row to count and the restore one to drop
part "X1. name chief p3-name-3 as the tester (P3 only, after the stamp)" "${C_NEW[@]}" name chief p3-name-3 --business mosaic-stack --tester
X1=$RC
# --- the rollback after W6
part "R0. rollback --restore $ACT --plan before the harness undo (expect unknown-kind-for-target)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --plan "${CB[@]}"
[ "$RC" != 0 ] && has unknown-kind-for-target || stop "R0 did not refuse unknown-kind-for-target"
plugins_read R1-read "R1a. plugins --tester --json, for the revision"; expect 0
plugins_set R1 'null' "R1b. plugins set harness null as the tester"; expect 0
plugins_read R1-after "R1c. plugins read again"; expect 0
lacks '"harness"' || stop "R1: harness is still set"
receipt
tail -1 "$OUT" | grep -q '"actor":"tester"' || stop "R1: the receipt's actor is not tester"
part "R2. business-check under OLD" node "$B/load-check.mjs" "$COPIES/$OLD" "$RB/cfg"; expect 0
snap D3 --held --after "$STAMP"; expect 0
N="$(node "$B/jget.mjs" eventsAfter < "$SN/D3.json")"
note "D3 after $STAMP: events $N, usage_records $(node "$B/jget.mjs" tables.usage_records.rowsAfter < "$SN/D3.json"), instance_names $(node "$B/jget.mjs" tables.instance_names.rowsAfter < "$SN/D3.json"), threads $(node "$B/jget.mjs" tables.threads.rowsAfter < "$SN/D3.json") (X1 exit $X1)"
[ -n "$N" ] || stop "D3 has no eventsAfter"
part "R3. rollback --restore $ACT --plan" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --plan "${CB[@]}"; expect 0
[ "$TP" = 1 ] && { has 'tester-port' || stop "R3 plan does not say it drops --tester-port"; }
part "R4. rollback --restore $ACT without --events (expect post-backup-events when D3 counted any)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" "${CB[@]}"
if [ "$N" = 0 ]; then
expect 0
else
[ "$RC" != 0 ] && has post-backup-events || stop "R4 did not refuse post-backup-events"
M="$(sed -n 's/.*refusing post-backup-events: \([0-9][0-9]*\) event.*/\1/p' "$R/out/last.txt" | head -1)"
note "R4 refused with $M event(s); D3 counted $N"
[ "$(pointer copy)" = "$NEW" ] && [ "$(pointer pm)" = true ] || stop "R4's refusal changed the pointer"
part "R5. rollback --restore $ACT --events $N (N from D3)" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --events "$N" "${CB[@]}"
if [ "$RC" != 0 ] && has post-backup-events; then
M2="$(sed -n 's/.*refusing post-backup-events: \([0-9][0-9]*\) event.*/\1/p' "$R/out/last.txt" | head -1)"
note "FINDING: the event count moved between D3 ($N) and R5 ($M2); one rerun with --events $M2"
part "R5b. rollback --restore $ACT --events $M2" "${SR[@]}" rollback mosaic-stack --restore "$ACT" --events "$M2" "${CB[@]}"
fi
expect 0
fi
POST="$(sed -n 's/^restore: .*moves to \(.*\) and is kept;.*/\1/p' "$R/out/last.txt" | head -1)"
note "post-attempt store: ${POST:-(none named)}$([ -n "$POST" ] && [ -e "$POST" ] && echo ', present')"
state
# --- the end state
part "F1. status at the end" "${SR[@]}" status mosaic-stack "${CB[@]}"; expect 0
[ "$(pointer copy)" = "$OLD" ] && [ "$(pointer schema)" = 3h ] && [ "$(pointer pm)" = true ] && [ -z "$(pointer pmPending)" ] || stop "F1: pointer not on OLD, 3h, pm true"
pointer console | grep -qF -- '--tester-port' && stop "F1: the pointer's Console flags still have --tester-port"
grep -qF -- '--tester-port' "$RB/xcfg/systemd/user/mosaic-webui.service" && stop "F1: the Console unit still has --tester-port"
(exec 3<>/dev/tcp/127.0.0.1/$TPORT) 2>/dev/null && stop "F1: tester port $TPORT still listens"
note "F1: pointer on OLD at 3h, pm true, no --tester-port in the pointer or the Console unit, port $TPORT closed"
snap F --held; expect 0
has '"schema": "3h"' || stop "the store is not back at 3h"
same S1 F; expect 0
part "F2. agents as the tester (OLD's CLI)" "${C_OLD[@]}" agents --business mosaic-stack --tester --json; expect 0
part "F3. launches list (OLD's CLI)" "${C_OLD[@]}" launches list --json; expect 0
note "P3: PASS"
echo "done: $OUT"
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# P3, seed: a scratch root at OLD 5fa9cc8f2 and 3h on stand-in units, with synthetic store rows written by
# OLD's Store before the bus first starts, then adopt. Real OLD bus host (PM launch emulated), healthz
# stand-in for the Console. Scratch paths only.
set -euo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$RB" ] || { echo "seed.sh: $RB exists; remove it first" >&2; exit 1; }
for p in $PORT $TPORT; do ! (exec 3<>/dev/tcp/127.0.0.1/$p) 2>/dev/null || { echo "seed.sh: port $p is in use" >&2; exit 1; }; done
mkdir -p "$RB"/{home,cfg/businesses,xcfg,xdata,xstate,run,sd,bin,tmp,data/notify/mosaic-stack}
chmod 700 "$RB/run"
echo emulate > "$RB/sd/pm-mode"
cat > "$RB/cfg/config.json" <<EOC
{"configVersion":1,"environment":"development","dataRoot":"$RB/data","execution":{"backend":"docker","provider":"zai","model":"glm-5.3-flash","adapter":"mock"}}
EOC
cp "$R/bfiles/B/businesses/mosaic-stack.json" "$RB/cfg/businesses/mosaic-stack.json"
printf '{"notifyVersion":1,"binding":null}' > "$RB/data/notify/mosaic-stack/notify.json"; chmod 600 "$RB/data/notify/mosaic-stack/notify.json"
step "root: $RB; business file $(sha256sum < "$RB/cfg/businesses/mosaic-stack.json" | cut -c1-64) (the example with usage-source transcript and channel cli,webui, no harness, bus.tester true, every role's harness var claude-code)"
# The broker refuses to boot unless every credential file in the business file exists, mode 0600. These are
# FAKE placeholder strings, not tokens; both base URLs in the file are 127.0.0.1:9.
NS="$R/bfiles/nosecret"; [ ! -e "$NS" ] || { echo "seed.sh: $NS exists; remove it first" >&2; exit 1; }
mkdir -m 700 "$NS"
for f in $(node -e 'const b=require(process.argv[1]);const o=[];(function w(x){if(x&&typeof x==="object")for(const[k,v]of Object.entries(x)){if(k==="file"&&typeof v==="string")o.push(v);w(v)}})(b);console.log(o.join(" "))' "$RB/cfg/businesses/mosaic-stack.json"); do
case "$f" in "$NS"/*) ;; *) echo "seed.sh: credential path outside $NS: $f" >&2; exit 1;; esac
printf 'scratch-fake-placeholder-%s\n' "$(basename "$f" .token)" > "$f"; chmod 600 "$f"
done
step "fake credential files: $(ls "$NS" | wc -l) under $NS, each 'scratch-fake-placeholder-<name>', mode 0600"
step "store seed: $(node "$B/store-seed.mjs" "$COPIES/$OLD" "$RB/data" 2>&1)"
printf '#!/usr/bin/env bash\n# mosaic-cli wrapper (Q81, agents/sage/work/q81/mosaic-cli.sh)\n[ "${1:-}" = __lease-capability ] && exec "%s/mosaic-old" "$@"\nexit 1\n' "$RB/bin" > "$RB/bin/mosaic"; chmod 755 "$RB/bin/mosaic"
run() { step "run: $*"; local rc=0; (cd "$REPO" && "${E[@]}" "$@") >> "$LOGF" 2>&1 || rc=$?; step "exit $rc"; return $rc; }
run scripts/bus-service.sh install --copy $OLD --copies "$COPIES" --pm --claude "$B/claude"
run systemctl --user start [email protected]
run scripts/webui-service.sh install --copy $OLD --copies "$COPIES" --port $PORT --business mosaic-stack
run systemctl --user start mosaic-webui.service
run scripts/stack-copy.sh wrapper $OLD --copies "$COPIES" --bin "$RB/bin"
run "$COPIES/$OLD/scripts/mosaic" bus status --json
run "$COPIES/$OLD/scripts/mosaic" launches list --json
run scripts/stack-release.sh adopt mosaic-stack --copies "$COPIES" --bin "$RB/bin"
run scripts/stack-release.sh status mosaic-stack --copies "$COPIES" --bin "$RB/bin" || true
step "pointer: $(cat "$RB/data/state/stack-active.json")"
@@ -0,0 +1,24 @@
// P3: synthetic rows in the scratch store before the OLD bus first starts, so S1, the migration, D3 and the
// restore have something to hash: usage records (a known end, a begin only, an unknown end), two instance
// names and a thread with a project. OLD's own Store writes them at 3h. Synthetic values only.
// usage: node store-seed.mjs OLD_COPY DATA_ROOT
import { pathToFileURL } from 'node:url';
const [old, root] = process.argv.slice(2);
const { Store, SCHEMA_VERSION } = await import(pathToFileURL(`${old}/packages/bus/src/store.mjs`).href);
if (SCHEMA_VERSION !== '3h') throw Error(`OLD is ${SCHEMA_VERSION}, not 3h`);
const s = new Store(root);
const u = (at, run, turn, phase, status, n, cursor) =>
s.run(`INSERT INTO usage_records(at,business,run,instance,provider,model,account,turn,source,phase,status,code,cursor,input,output,cache_write,cache_read)
VALUES (?,?,?,?,?,?,NULL,?,?,?,?,?,?,?,?,?,?)`, at, 'mosaic-stack', run, 'chief', 'anthropic', 'scratch-model', turn, 'transcript', phase, status,
status === 'unknown' ? 'no-new-usage' : null, cursor, ...(status === 'known' ? [n, n * 2, 0, n * 3] : [null, null, null, null]));
u('2026-10-19T10:00:00.000Z', 'p3-run-a', 't1', 'begin', 'known', 0, '{"offset":1}');
u('2026-10-19T10:00:05.000Z', 'p3-run-a', 't1', 'end', 'known', 1200, null);
u('2026-10-19T10:01:00.000Z', 'p3-run-a', 't2', 'begin', 'known', 0, '{"offset":2}');
u('2026-10-19T13:00:00.000Z', 'p3-run-b', 't1', 'begin', 'known', 0, '{"offset":3}');
u('2026-10-19T13:00:09.000Z', 'p3-run-b', 't1', 'end', 'unknown', 0, null);
s.run(`INSERT INTO instance_names(at,business,instance,name,by) VALUES (?,?,?,?,?)`, '2026-10-19T09:00:00.000Z', 'mosaic-stack', 'chief', 'p3-name-1', 'tester');
s.run(`INSERT INTO instance_names(at,business,instance,name,by) VALUES (?,?,?,?,?)`, '2026-10-19T14:00:00.000Z', 'mosaic-stack', 'chief', 'p3-name-2', 'tester');
s.run(`INSERT INTO projects(id,at,business,name,repo,created_by) VALUES (?,?,?,?,?,?)`, 'p3-proj', '2026-10-19T09:00:00.000Z', 'mosaic-stack', 'p3-project', null, 'tester');
s.run(`INSERT INTO threads(id,at,business,project,instance,owner,name) VALUES (?,?,?,?,?,?,?)`, 'p3-th1', '2026-10-19T09:30:00.000Z', 'mosaic-stack', 'p3-proj', 'chief', 'tester', 'p3-thread');
s.close();
console.log('seeded 5 usage_records, 2 instance_names, 1 project, 1 thread at 3h');
@@ -0,0 +1,136 @@
#!/usr/bin/node
// sage-1004/1006 Window B rehearsal: a stand-in `systemctl --user`, based on the one in
// packages/cli/tests/stack-release.test.mjs. Unit state lives in $SD_STATE/units.json and every call
// goes to calls.log. Unlike the test's holder, a bus start runs the copy's real
// `scripts/mosaic bus start <business>` from the unit's WorkingDirectory, without --pm and under this
// scratch environment. Its output becomes journal lines. With --pm in ExecStart, the PM launch is
// EMULATED: no claude runs. A scratch runner process stands in for the session, with one
// sessions.json entry and one `launched` journal line. A Console start runs a scratch /healthz
// server on the unit's --port. Nothing here reads or writes a live unit, store or journal.
// Row 169 rehearsal: when $SD_STATE/pm-mode holds "real", a bus start with --pm runs the unit's argv as
// it is, --pm included, so the copy's own launchPm runs (step 5). The start then waits up to 30 s more
// for the `launched` line or the bus exiting, and journals all of it. A bus that exited is "failed",
// as systemd shows a Type=simple unit whose main process exited 3 (RestartPreventExitStatus=2 3 4,
// so no restart). A `launched` line in real mode writes REAL-LAUNCH to pids.log; run.sh stops on it.
const fs = require('node:fs'), path = require('node:path'), cp = require('node:child_process');
const sd = process.env.SD_STATE, data = process.env.SD_DATA, unitDir = path.join(process.env.XDG_CONFIG_HOME, 'systemd', 'user');
const args = process.argv.slice(2).filter((a) => a !== '--user'), [verb, ...rest] = args;
fs.appendFileSync(path.join(sd, 'calls.log'), `${new Date().toISOString()} ${args.join(' ')}\n`);
const stFile = path.join(sd, 'units.json');
const load = () => { try { return JSON.parse(fs.readFileSync(stFile, 'utf8')); } catch { return {}; } };
const save = (s) => { fs.writeFileSync(stFile + '.tmp', JSON.stringify(s)); fs.renameSync(stFile + '.tmp', stFile); };
const sleep = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
const alive = (pid) => { try { const s = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); return s[s.lastIndexOf(')') + 2] !== 'Z'; } catch { return false; } };
const startTime = (pid) => { const s = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); return s.slice(s.lastIndexOf(')') + 2).split(' ')[19]; };
const isBus = (u) => /^mosaic-bus@[a-z0-9-]+\.service$/.test(u), inst = (u) => u.slice('mosaic-bus@'.length, -'.service'.length);
const journal = (unit, text) => fs.appendFileSync(path.join(sd, 'journal.jsonl'), JSON.stringify({ epoch: Math.floor(Date.now() / 1000), unit, text }) + '\n');
const unitFile = (u) => {
const main = isBus(u) ? '[email protected]' : u, file = path.join(unitDir, main);
if (!fs.existsSync(file)) return null;
const drops = [];
for (const d of isBus(u) ? [main + '.d', u + '.d'] : [u + '.d']) { const dir = path.join(unitDir, d); if (fs.existsSync(dir)) for (const f of fs.readdirSync(dir).sort()) if (f.endsWith('.conf')) drops.push(path.join(dir, f)); }
const r = { wd: '', exec: '', env: [], drops };
for (const f of [file, ...drops]) for (let line of fs.readFileSync(f, 'utf8').split('\n')) {
line = line.replace(/%i/g, isBus(u) ? inst(u) : '').replace(/%h/g, process.env.HOME);
const m = /^(WorkingDirectory|ExecStart|Environment)=(.*)$/.exec(line); if (!m) continue;
if (m[1] === 'WorkingDirectory') r.wd = m[2]; else if (m[1] === 'ExecStart') { if (m[2]) r.exec = m[2]; } else r.env.push(m[2]);
}
return r;
};
// Every fd above 2 is closed first, so no child holds stack-release.sh's lock (fd 9).
const CLOSE = 'for fd in /proc/self/fd/*; do n=${fd##*/}; [ "$n" -gt 2 ] && eval "exec $n>&-" 2>/dev/null; done; exec "$@"';
const spawnDetached = (argv, opts) => { const ch = cp.spawn('bash', ['-c', CLOSE, 'standin', ...argv], { detached: true, ...opts }); ch.unref(); return ch; };
const sessionsFile = path.join(data, 'bus-host', 'sessions.json');
const readSessions = () => { try { return JSON.parse(fs.readFileSync(sessionsFile, 'utf8')); } catch { return { sessionsVersion: 1, sessions: [] }; } };
const writeSessions = (doc) => { fs.mkdirSync(path.dirname(sessionsFile), { recursive: true, mode: 0o700 }); fs.writeFileSync(sessionsFile + '.tmp', JSON.stringify(doc, null, 2) + '\n', { mode: 0o600 }); fs.renameSync(sessionsFile + '.tmp', sessionsFile); };
if (verb === 'show') {
const u = rest[0], props = []; for (let i = 1; i < rest.length; i++) if (rest[i] === '-p') props.push(rest[++i]);
const f = unitFile(u), st = load()[u] || {};
for (const p of props) {
if (p === 'LoadState') console.log(`LoadState=${f ? 'loaded' : 'not-found'}`);
else if (p === 'WorkingDirectory') console.log(`WorkingDirectory=${f ? f.wd : ''}`);
else if (p === 'ExecStart') console.log(f && f.exec ? `ExecStart={ path=${f.exec.split(' ')[0]} ; argv[]=${f.exec} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }` : 'ExecStart=');
else if (p === 'Environment') console.log(`Environment=${f ? f.env.join(' ') : ''}`);
else if (p === 'MainPID') console.log(`MainPID=${st.state === 'active' && st.pid ? st.pid : 0}`);
else if (p === 'DropInPaths') console.log(`DropInPaths=${f ? f.drops.join(' ') : ''}`);
}
process.exit(0);
}
if (verb === 'is-active') { const q = rest[0] === '--quiet', u = q ? rest[1] : rest[0], st = load()[u] || {}; let s = st.state || 'inactive'; if (s === 'active' && st.pid && !alive(st.pid)) s = 'failed'; if (!q) console.log(s); process.exit(s === 'active' ? 0 : 3); }
if (verb === 'is-enabled') { console.log('disabled'); process.exit(1); }
if (verb === 'daemon-reload') process.exit(0);
if (verb === 'list-units') {
const pats = rest.filter((a) => !a.startsWith('--')).map((p) => new RegExp('^' + p.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$'));
for (const [u, s] of Object.entries(load())) if (pats.some((re) => re.test(u))) console.log(`${u} loaded ${s.state} ${s.state === 'active' ? 'running' : 'dead'} standin`);
process.exit(0);
}
if (verb === 'start') {
const u = rest[0], f = unitFile(u); if (!f) { console.error(`Unit ${u} not found.`); process.exit(5); }
const s = load();
if (!isBus(u)) {
const argv = f.exec.split(' '), i = argv.indexOf('--port'), port = i > 0 ? argv[i + 1] : '7332';
const t = argv.indexOf('--tester-port'), tport = t > 0 ? argv[t + 1] : '';
const ch = spawnDetached([process.execPath, path.join(__dirname, 'healthz.cjs'), port, tport], { stdio: 'ignore', cwd: sd });
fs.appendFileSync(path.join(sd, 'pids.log'), `healthz ${ch.pid}\n`);
const end = Date.now() + 10000;
while (!fs.existsSync(path.join(sd, `healthz-${ch.pid}`))) { if (Date.now() > end) { console.error('healthz stand-in did not start'); process.exit(1); } sleep(20); }
s[u] = { state: 'active', pid: ch.pid, wd: f.wd }; save(s); process.exit(0);
}
const argv = f.exec.split(' '), pm = argv.slice(1).includes('--pm');
let mode = 'emulate'; try { mode = fs.readFileSync(path.join(sd, 'pm-mode'), 'utf8').trim(); } catch {}
const realPm = pm && mode === 'real', real = realPm ? argv : argv.filter((a) => a !== '--pm');
const env = { ...process.env }; for (const e of f.env) { const k = e.slice(0, e.indexOf('=')); if (k === 'PATH' || k === 'MOSAIC_CLAUDE_BIN') env[k] = e.slice(k.length + 1); }
const out = path.join(sd, `bus-${Date.now()}.out`), fd = fs.openSync(out, 'a');
const ch = spawnDetached(real, { stdio: ['ignore', fd, fd], cwd: f.wd, env });
fs.closeSync(fd);
fs.appendFileSync(path.join(sd, 'pids.log'), `bus ${ch.pid} ${real.join(' ')} > ${out}\n`);
const end = Date.now() + 60000; let text = '';
while (!/^bus host up/m.test(text)) {
if (!alive(ch.pid) && realPm) { text = fs.readFileSync(out, 'utf8'); if (/^bus host up/m.test(text)) break; }
if (!alive(ch.pid)) { for (const l of text.split('\n').filter(Boolean)) journal(u, l); s[u] = { state: 'failed', pid: null, wd: f.wd }; save(s); console.error(`bus exited before host up; see ${out}`); process.exit(1); }
if (Date.now() > end) { console.error(`bus host up not seen in 60 s; see ${out}`); process.exit(1); }
sleep(100); text = fs.readFileSync(out, 'utf8');
}
if (realPm) {
const end3 = Date.now() + 30000;
while (!/^launched /m.test(text) && alive(ch.pid) && Date.now() < end3) { sleep(100); text = fs.readFileSync(out, 'utf8'); }
sleep(200); text = fs.readFileSync(out, 'utf8');
if (/^launched /m.test(text)) fs.appendFileSync(path.join(sd, 'pids.log'), `REAL-LAUNCH ${ch.pid}\n`);
}
for (const l of text.split('\n').filter(Boolean)) journal(u, l);
if (realPm) {
const up = alive(ch.pid);
fs.appendFileSync(path.join(sd, 'pids.log'), `real-pm ${ch.pid} ${up ? 'running' : 'exited'}\n`);
s[u] = up ? { state: 'active', pid: ch.pid, wd: f.wd, out, journaled: text.length } : { state: 'failed', pid: null, wd: f.wd };
save(s); process.exit(0);
}
s[u] = { state: 'active', pid: ch.pid, wd: f.wd, out, journaled: text.length };
if (pm) {
// The emulated PM launch: a runner that only waits, one sessions.json entry, one journal line.
const runner = spawnDetached([process.execPath, '-e', 'setInterval(()=>{},1<<30)'], { stdio: 'ignore', cwd: sd });
const end2 = Date.now() + 5000; while (!fs.existsSync(`/proc/${runner.pid}/stat`) && Date.now() < end2) sleep(10);
const run = `remul${runner.pid}`, b = inst(u);
const doc = readSessions(); doc.sessions.push({ run, business: b, instance: 'chief', harness: 'claude-code', model: 'emulated', launchedBy: 'standin-pm-emulation', runnerPid: runner.pid, runnerStartTime: startTime(runner.pid), startedAt: new Date().toISOString() }); writeSessions(doc);
journal(u, `launched chief: run ${run}, claude-code emulated`);
fs.appendFileSync(path.join(sd, 'pids.log'), `runner ${runner.pid} ${run}\n`);
s[u].runner = runner.pid; s[u].run = run;
}
save(s); process.exit(0);
}
if (verb === 'stop') {
const u = rest[0], s = load(), st = s[u];
if (st && st.pid) {
try { process.kill(st.pid, 'SIGTERM'); } catch {}
const end = Date.now() + 20000; while (alive(st.pid) && Date.now() < end) sleep(50);
if (alive(st.pid)) { fs.appendFileSync(path.join(sd, 'pids.log'), `SIGKILL ${st.pid}\n`); try { process.kill(st.pid, 'SIGKILL'); } catch {} }
if (st.out) { const text = fs.readFileSync(st.out, 'utf8'); for (const l of text.slice(st.journaled || 0).split('\n').filter(Boolean)) journal(u, l); }
}
if (st && st.runner) {
try { process.kill(st.runner, 'SIGTERM'); } catch {}
const doc = readSessions(); doc.sessions = doc.sessions.filter((x) => x.run !== st.run); writeSessions(doc);
}
if (st) { s[u] = { wd: st.wd, state: 'inactive', pid: null }; save(s); }
process.exit(0);
}
console.error(`stand-in systemctl: unsupported: ${args.join(' ')}`); process.exit(1);
@@ -0,0 +1,4 @@
#!/usr/bin/node
// Stand-in `systemd-analyze --user unit-paths` (the test's): only the scratch unit dir.
if(process.argv[2]!=='--user'||process.argv[3]!=='unit-paths')process.exit(1);
console.log(require('node:path').join(process.env.XDG_CONFIG_HOME,'systemd','user'));
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# P3: stops the scratch units through the stand-in, then confirms every PID it started is gone and the port is closed.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
T=$R/out/p3-teardown.txt
{
echo "# teardown $(date -u +%FT%TZ)"
for u in mosaic-webui.service [email protected]; do
(cd "$REPO" && "${E[@]}" systemctl --user stop "$u"); echo "stop $u exit $?"
done
left=0
while read -r kind pid _; do
if [ -e "/proc/$pid" ] && grep -q "$R" "/proc/$pid/cmdline" 2>/dev/null; then echo "ALIVE $kind $pid"; left=1; fi
done < <(grep -v "^REAL-LAUNCH\|^SIGKILL\|^real-pm" "$RB/sd/pids.log")
for p in /proc/[0-9]*; do c=$(readlink "$p/cwd" 2>/dev/null) || continue; case $c in "$R"*) case "$(tr "\0" " " < "$p/cmdline" 2>/dev/null)" in *b/all.sh*|*b/teardown.sh*) continue;; esac; echo "cwd-in-root ${p#/proc/} $c"; left=1;; esac; done
for p in $PORT $TPORT; do if (exec 3<>/dev/tcp/127.0.0.1/$p) 2>/dev/null; then echo "port $p open"; left=1; else echo "port $p closed"; fi; done
echo "left: $left"
} 2>&1 | tee "$T"
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Waits until busy.sh passes twice, 60 s apart, then runs all.sh, teed. Gives up after 90 minutes.
set -uo pipefail
end=$((SECONDS + 5400))
while :; do
if ~/darkwing-scratch/busy.sh > /dev/null; then
sleep 60
if ~/darkwing-scratch/busy.sh; then break; fi
fi
[ "$SECONDS" -lt "$end" ] || { echo "wait-run: still busy after 90 min"; exit 9; }
sleep 30
done
echo "wait-run: clear at $(date -u +%FT%TZ)"
/home/jwoltje/darkwing-scratch/mbc/p3/b/all.sh 2>&1 | tee /home/jwoltje/darkwing-scratch/mbc/p3/all-$(date -u +%Y%m%dT%H%M%SZ).log
exit "${PIPESTATUS[0]}"
@@ -0,0 +1,15 @@
addy-gen_default
bridge
compose-audit_default
host
jarvis-crypto_default
mage-ai_mage-network
mosaic-dev_default
mosaic-internal
mosaic-mono-v1_default
mosaic-public
neni-content-engine-dashboard_default
none
sage-phr-ng_sage-network
t205-directus_dd-internal
t205-payload_pl-internal
@@ -0,0 +1,15 @@
addy-gen_default
bridge
compose-audit_default
host
jarvis-crypto_default
mage-ai_mage-network
mosaic-dev_default
mosaic-internal
mosaic-mono-v1_default
mosaic-public
neni-content-engine-dashboard_default
none
sage-phr-ng_sage-network
t205-directus_dd-internal
t205-payload_pl-internal
@@ -0,0 +1,6 @@
# before prep, 2026-10-20T00:32:34Z
/home/jwoltje/.mosaic-dev/bus/bus.sqlite 1792446324
/home/jwoltje/.mosaic-dev/bus 1792446325
# after teardown, 2026-10-20T00:32:43Z
/home/jwoltje/.mosaic-dev/bus/bus.sqlite 1792446324
/home/jwoltje/.mosaic-dev/bus 1792446325
@@ -0,0 +1,166 @@
2026-10-20T00:32:35Z tool clone /home/jwoltje/darkwing-scratch/mbc/p3/repo at 8e888014d4f4bbbe7f1e6fa598003c374c169856, refactor 8e888014d4f4bbbe7f1e6fa598003c374c169856; scripts/stack-release.sh blob 0b501ffbc24735468ca7e91845b86badfb2dd0b3; TP=0
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 127 packages in 1s
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts @google/[email protected] (preinstall: echo 'preinstall: no-op')
npm warn install-scripts [email protected] (postinstall: node install.js)
npm warn install-scripts [email protected] (postinstall: node scripts/postinstall)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
copied: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
2026-10-20T00:32:37Z copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0: exit 0
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 127 packages in 1s
npm warn install-scripts 3 packages had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts @google/[email protected] (preinstall: echo 'preinstall: no-op')
npm warn install-scripts [email protected] (postinstall: node install.js)
npm warn install-scripts [email protected] (postinstall: node scripts/postinstall)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
copied: /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856
2026-10-20T00:32:38Z copy 8e888014d4f4bbbe7f1e6fa598003c374c169856: exit 0
2026-10-20T00:32:38Z example blob 3a81ca0faea6d3dc3b29ae513c799497ed53f9d7
2026-10-20T00:32:38Z business B (Window A's plug-ins, no harness) c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32; H (harness ["claude-code"]) 486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a
2026-10-20T00:32:38Z root: /home/jwoltje/darkwing-scratch/mbc/p3/root; business file c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32 (the example with usage-source transcript and channel cli,webui, no harness, bus.tester true, every role's harness var claude-code)
2026-10-20T00:32:38Z fake credential files: 9 under /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/nosecret, each 'scratch-fake-placeholder-<name>', mode 0600
2026-10-20T00:32:39Z store seed: seeded 5 usage_records, 2 instance_names, 1 project, 1 thread at 3h
2026-10-20T00:32:39Z run: scripts/bus-service.sh install --copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --pm --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
written: /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user/[email protected]
claude: /home/jwoltje/darkwing-scratch/mbc/p3/b/claude (9.9.9 (Claude Code fixture))
daemon-reload done
next, for one business (one per data root):
mkdir -m 0700 -p <dataRoot>/notify/<business> the notifier refuses a looser directory
write <dataRoot>/notify/<business>/notify.json, mode 0600:
{"notifyVersion": 1, "binding": "<discord binding>"} or "binding": null for no DMs
systemctl --user enable --now mosaic-bus@<business> start now and at login
systemctl --user status mosaic-bus@<business>
journalctl --user -u mosaic-bus@<business> -f the host's log
systemctl --user stop mosaic-bus@<business> SIGTERM; restartable
survive logout and reboot only with lingering on: loginctl enable-linger jwoltje
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: systemctl --user start [email protected]
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: scripts/webui-service.sh install --copy 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
written: /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user/mosaic-webui.service
serve: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
daemon-reload done
this script starts nothing: the Console holds the human's capability. Jason
starts and restarts it, or Mos under lead decision 102 (sends then enter the
trail as Jason); no other agent does:
systemctl --user enable --now mosaic-webui start now and at login
systemctl --user status mosaic-webui
journalctl --user -u mosaic-webui -f the Console's log
systemctl --user stop mosaic-webui SIGTERM; restartable
scripts/webui-service.sh status unit state and /healthz
survive logout and reboot only with lingering on: loginctl enable-linger jwoltje
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: systemctl --user start mosaic-webui.service
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: scripts/stack-copy.sh wrapper 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
wrapper: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus status --json
{
"host": {
"business": "mosaic-stack",
"pid": 290751,
"startedAt": "2026-10-20T00:32:39.283Z",
"notifier": null,
"live": true
},
"socket": true,
"writerLock": {
"pid": 290768,
"at": "2026-10-20T00:32:39.350Z",
"live": true
},
"boot": {
"ok": true,
"at": "2026-10-20T00:32:39.282Z",
"business": "mosaic-stack",
"file": "/home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json",
"reason": null,
"lastGood": "2026-10-20T00:32:39.282Z"
}
}
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic launches list --json
[
{
"run": "remul290777",
"business": "mosaic-stack",
"instance": "chief",
"harness": "claude-code",
"model": "emulated",
"launchedBy": "standin-pm-emulation",
"runnerPid": 290777,
"runnerStartTime": "55754960",
"startedAt": "2026-10-20T00:32:39.385Z",
"live": true
}
]
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: scripts/stack-release.sh adopt mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
adopted 5fa9cc8f2c66b52408b652b59c3070f7210b44d0 for mosaic-stack (pm 1, schema 3h)
2026-10-20T00:32:39Z exit 0
2026-10-20T00:32:39Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
pointer: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/state/stack-active.json
{"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T003239Z-5fa9cc8f2c66","at":"2026-10-20T00:32:39Z"}
log (last five lines):
{"at":"2026-10-20T00:32:39Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T003239Z-5fa9cc8f2c66","result":"ok"}
check:
bus: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
Console: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
CLI: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
result: pass
bus status:
host: mosaic-stack, pid 290751, running, since 2026-10-20T00:32:39.283Z, notifier off
socket: present
writer.lock: pid 290768
boot: organization file loaded at 2026-10-20T00:32:39.282Z
unit flags: match the pointer
drift: 138 commit(s) on refactor since the pointer's copy
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T003239Z-5fa9cc8f2c66","at":"2026-10-20T00:32:39Z"}
2026-10-20T00:32:40Z --- run.sh
2026-10-20T00:32:40Z pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T003239Z-5fa9cc8f2c66","at":"2026-10-20T00:32:39Z"}
2026-10-20T00:32:40Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus start %i --pm
2026-10-20T00:32:40Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
2026-10-20T00:32:40Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
2026-10-20T00:32:40Z activation log, last line: {"at":"2026-10-20T00:32:39Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T003239Z-5fa9cc8f2c66","result":"ok"}
2026-10-20T00:32:40Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H
2026-10-20T00:32:40Z exit 1
2026-10-20T00:32:40Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z run: node -e
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))})) /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs agents --business mosaic-stack --tester --json
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z run: node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs launches list --json
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z W1 start stamp: 2026-10-20T00:32:40Z
2026-10-20T00:32:40Z run: node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held
2026-10-20T00:32:40Z exit 0
2026-10-20T00:32:40Z run: scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T00:32:41Z exit 0
2026-10-20T00:32:41Z run: scripts/stack-release.sh activate 8e888014d4f4bbbe7f1e6fa598003c374c169856 mosaic-stack --pm-after-harness --migrate --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T00:32:41Z exit 0
2026-10-20T00:32:41Z run: scripts/stack-release.sh activate 8e888014d4f4bbbe7f1e6fa598003c374c169856 mosaic-stack --pm-after-harness --migrate --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
2026-10-20T00:32:42Z exit 0
2026-10-20T00:32:42Z pointer: {"copy":"8e888014d4f4bbbe7f1e6fa598003c374c169856","business":"mosaic-stack","pm":false,"pmPending":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3i","activation":"20261020T003241Z-8e888014d4f4","at":"2026-10-20T00:32:42Z"}
2026-10-20T00:32:42Z bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856/scripts/mosaic bus start %i
2026-10-20T00:32:42Z Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
2026-10-20T00:32:42Z business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
2026-10-20T00:32:42Z activation log, last line: {"at":"2026-10-20T00:32:42Z","op":"activate","from":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","to":"8e888014d4f4bbbe7f1e6fa598003c374c169856","backup":"20261020T003241Z-8e888014d4f4","activation":"20261020T003241Z-8e888014d4f4","result":"ok","pm":"pending"}
2026-10-20T00:32:42Z W5 activation 20261020T003241Z-8e888014d4f4; backup /home/jwoltje/darkwing-scratch/mbc/p3/root/data/backups/stack/20261020T003241Z-8e888014d4f4; STAMP 2026-10-20T00:32:41.938Z; SCHEMA 3h; files: bus DATA_ROOT LISTING.txt MODES.txt ROLLBACK_SET SCHEMA SHA256SUMS SOURCE.sha256 STAMP
2026-10-20T00:32:42Z STOP: backup SHA256SUMS does not check
@@ -0,0 +1,6 @@
# teardown 2026-10-20T00:32:42Z
stop mosaic-webui.service exit 0
stop [email protected] exit 0
port 47394 closed
port 47395 closed
left: 0
@@ -0,0 +1,326 @@
# SCRATCH ROOT, NOT LIVE. Merged window B+C P3, run by darkwing from 2026-10-20T00:32:40Z (sage-1112, sage-1117).
# Plan: agents/sage/work/window-plan/repin-merged-bc.md, sha256 696f0adb7a02c62b26ebb9f760c4c6b4f8805ec2acc62c388677b644c98b63ea.
# Tool: /home/jwoltje/darkwing-scratch/mbc/p3/repo, a git clone --shared of the canonical checkout at 8e888014d4f4bbbe7f1e6fa598003c374c169856, nothing applied;
# scripts/stack-release.sh blob 0b501ffbc24735468ca7e91845b86badfb2dd0b3. refactor in the clone: 8e888014d4f4bbbe7f1e6fa598003c374c169856.
# Copies (stack-copy.sh copy): OLD 5fa9cc8f2c66b52408b652b59c3070f7210b44d0, NEW 8e888014d4f4bbbe7f1e6fa598003c374c169856. TP=0: no --tester-port (the tool at this NEW predates row 176).
# Root: /home/jwoltje/darkwing-scratch/mbc/p3/root. Config /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/config.json, data root /home/jwoltje/darkwing-scratch/mbc/p3/root/data, units in /home/jwoltje/darkwing-scratch/mbc/p3/root/xcfg/systemd/user.
# Business file: the committed example (blob 3a81ca0faea6d3dc3b29ae513c799497ed53f9d7) made loadable by mkbiz.mjs: plugins
# {"usage-source":["transcript"],"channel":["cli","webui"]}, no harness, bus.tester true, every role's harness var claude-code;
# sha256 c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32.
# Store: seeded at 3h by OLD's Store before the bus first started (store-seed.mjs): 5 usage_records, 2 instance_names, 1 thread.
# The harness set and its undo are the real NEW copy's mosaic plugins set --tester against the scratch bus, no stand-in.
# snapshot.mjs: /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs, sha256 909a11f65c42de1dec6776a55585ad01ed960d25ff827c6b298b3293fbe46406 (expected 909a11f65c42de1dec6776a55585ad01ed960d25ff827c6b298b3293fbe46406).
# Stand-ins (/home/jwoltje/darkwing-scratch/mbc/p3/b): systemctl runs the copy's real 'scripts/mosaic bus start mosaic-stack'. With pm-mode emulate a --pm
# start runs the bus WITHOUT --pm and EMULATES the PM launch: no claude runs; a waiting runner, one sessions.json entry
# and one 'launched chief' journal line stand in for it (no session credential goes to scratch). The Console is a
# /healthz stand-in on 127.0.0.1:47394, and on 127.0.0.1:47395 when the unit has --tester-port. journalctl and
# systemd-analyze are the test's; claude is a fixture that prints a version. Credential files are fake placeholders.
# Environment for every call: env -i with HOME, PATH, TMPDIR, LANG, MOSAIC_CONFIG, XDG_* and SD_* only (names: HOME PATH TMPDIR LANG MOSAIC_CONFIG XDG_CONFIG_HOME XDG_DATA_HOME XDG_STATE_HOME XDG_RUNTIME_DIR SD_STATE SD_DATA).
# pointer: {"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T003239Z-5fa9cc8f2c66","at":"2026-10-20T00:32:39Z"}
# bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/scripts/mosaic bus start %i --pm
# Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
# business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
# activation log, last line: {"at":"2026-10-20T00:32:39Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T003239Z-5fa9cc8f2c66","result":"ok"}
## L1. business-check of OLD on a file that has harness (expect REFUSED unknown kind "harness")
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H)
REFUSED /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H/businesses/mosaic-stack.json plugins names unknown kind "harness"; adding a kind is a core change
# exit 1
## L2. control: NEW on the same file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/bfiles/H)
copy 8e888014d: roles 6, projects 1, arbiters 2, plugins {"usage-source":["transcript"],"channel":["cli","webui"],"harness":["claude-code"]}
HOLDS chief instance.name yes
HOLDS pm instance.name no
LOAD_OK
# exit 0
## L3. OLD on the rehearsal file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg)
copy 5fa9cc8f2: roles 6, projects 1, arbiters 2, plugins {"usage-source":["transcript"],"channel":["cli","webui"]}
HOLDS chief instance.name yes
HOLDS pm instance.name no
LOAD_OK
# exit 0
## L4. NEW on the rehearsal file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/b/load-check.mjs /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856 /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg)
copy 8e888014d: roles 6, projects 1, arbiters 2, plugins {"usage-source":["transcript"],"channel":["cli","webui"]}
HOLDS chief instance.name yes
HOLDS pm instance.name no
LOAD_OK
# exit 0
## L5. the P1 values of the rehearsal file
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node -e
const b=require(process.argv[1]);const r=Object.entries(b.roles);
console.log(JSON.stringify({busTester:b.vars["bus.tester"],pluginKinds:Object.keys(b.plugins??{}),launchBy:b.launch?.by,
chiefHarness:b.roles[b.launch?.by]?.vars?.harness??null,piRoles:r.filter(([,x])=>[x.vars?.harness,x.vars?.["fallback.harness"]].includes("pi")).map(([k])=>k),
harnessByRole:Object.fromEntries(r.map(([k,x])=>[k,x.vars?.harness??null]))})) /home/jwoltje/darkwing-scratch/mbc/p3/root/cfg/businesses/mosaic-stack.json)
{"busTester":true,"pluginKinds":["usage-source","channel"],"launchBy":"chief","chiefHarness":"claude-code","piRoles":[],"harnessByRole":{"pm":"claude-code","cto":"claude-code","coder":"claude-code","reviewer":"claude-code","chief":"claude-code","assistant":"claude-code"}}
# exit 0
## L6. run markers in this shell's ancestors (names only; the tester walk refuses one)
ancestors with a run marker: 0
## W1a. agents as the tester (OLD's CLI; the chief must not be working)
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs agents --business mosaic-stack --tester --json)
[]
# exit 0
## W1b. launches list (OLD's CLI)
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0/packages/cli/src/cli.mjs launches list --json)
[
{
"run": "remul290777",
"business": "mosaic-stack",
"instance": "chief",
"harness": "claude-code",
"model": "emulated",
"launchedBy": "standin-pm-emulation",
"runnerPid": 290777,
"runnerStartTime": "55754960",
"startedAt": "2026-10-20T00:32:39.385Z",
"live": true
}
]
# exit 0
# W1 start stamp: 2026-10-20T00:32:40Z
## snapshot S1
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> node /mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/snapshot.mjs --store /home/jwoltje/darkwing-scratch/mbc/p3/root/data/bus/bus.sqlite --held)
{
"schema": "3h",
"tables": {
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "04f8f0d94725145f7204a37d232fbf19c5c4f1e2930fda37482dff5b5cd484e4"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "15169aaf4e94d892f2202d0fd7d5af79b75ba017d23375ae389bae25dcc16edb"
}
}
}
# exit 0
## W2. status
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> scripts/stack-release.sh status mosaic-stack --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin)
pointer: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/state/stack-active.json
{"copy":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","business":"mosaic-stack","pm":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3h","activation":"20261020T003239Z-5fa9cc8f2c66","at":"2026-10-20T00:32:39Z"}
log (last five lines):
{"at":"2026-10-20T00:32:39Z","op":"adopt","from":null,"to":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","backup":null,"activation":"20261020T003239Z-5fa9cc8f2c66","result":"ok"}
check:
bus: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
Console: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
CLI: /home/jwoltje/darkwing-scratch/mbc/p3/copies/5fa9cc8f2c66b52408b652b59c3070f7210b44d0
result: pass
bus status:
host: mosaic-stack, pid 290751, running, since 2026-10-20T00:32:39.283Z, notifier off
socket: present
writer.lock: pid 290768
boot: organization file loaded at 2026-10-20T00:32:39.282Z
unit flags: match the pointer
drift: 138 commit(s) on refactor since the pointer's copy
# exit 0
## W3. activate NEW --pm-after-harness --migrate --plan
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> scripts/stack-release.sh activate 8e888014d4f4bbbe7f1e6fa598003c374c169856 mosaic-stack --pm-after-harness --migrate --plan --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin)
plan: activate for mosaic-stack
from: 5fa9cc8f2c66b52408b652b59c3070f7210b44d0
to: 8e888014d4f4bbbe7f1e6fa598003c374c169856
store schema: 3h (read from the store the running bus holds)
target schema: 3i
migration: 3h to 3i, after a backup of the stopped store
migration steps: 3h to 3i
needs: --migrate (given)
needs: Jason present for this run (decision 96 condition 2)
commits: the run adds 138 (newest first, at most 200):
8e888014d log: row 175 landed (98d29769e), row 176 brief amended and launched, merged window drafted; sessions: Sage
473258a51 queue: revs 2072-2076: row 175 round 3 approve on 2e30f2a1 (Filbert 2072, comment 29279), landing note and done after 98d29769e (Sage 2073, 2074); row 176 brief re-pinned to 0f7119af9566 for the stack-release --tester-port pointer change and row 175 F1 (Sage 2075), queued to briefed (Sage 2076)
2fecddfba sage: row 176 brief: activate --tester-port N writes the flag into the pointer's Console flags, a rollback or an activate to a copy whose Console lacks it drops it, tester-port-target refuses before anything stops; tests and three mutants; row 175 F1 (TOOLS.md step 2) rides along
98d29769e bus, cli: tester reads and the W1-W7 tester writes, recorded as tester; scripts/mosaic sends plugins, name and names to the CLI (row 175, #1673)
1d81c54ff sessions: Filbert row 175 r3 review, approve
716ddcf1e queue: revs 2058-2071: row 179 start, in-review and request (Darkwing 2058, 2060, 2061), issue #1677 (Sage 2059), r1 approve (Dewey 2062, comment 29271), landing note and done after 9e74925c2 (Sage 2063, 2064); row 175 r2 request on f9e41b918 (Dewey 2065-2067, comment 29275), back to in-progress to rebase onto 9e74925c2 (Sage 2068, 2069), round 3 request on the rebased candidate 2e30f2a1 (Dewey 2070, 2071, comment 29276)
0f45a3e6e sessions: Dewey row 175 round 2 to in-review on 989699f7c, row 179 approved
9e74925c2 docs: TOOLS.md follow-ups F1-F3 from the row 169 review (row 179, #1677)
ce5807989 log: row 169 landed (264756a30), row 179 briefed, row 175 to round 2 (1bfc9833b)
1bfc9833b queue: revs 2052-2057: row 179 added and briefed (Sage 2052, 2057), row 169 landing notes and done after 264756a30 (Sage 2053, 2054, 2056), row 175 r1 approve recorded (Filbert 2055, comment 29264)
c98a5d17a sessions: Dewey row 175 round 1 approved
8f2ac5236 sessions: Filbert row 175 r1 review, approve
264756a30 stack-release: activate --pm-after-harness, pm-on and the pending pointer, so a re-pin past c216f47db starts the PM after the harness kind is set (row 169, #1666)
b2a75f318 sage: brief for the row 169 TOOLS.md follow-ups F1-F3 (Filbert, #1666 comment 29263), owner Darkwing, reviewer Dewey, after row 169
e7d47c346 log: rows 169 and 175 in-review, row 169 r1 approve, queue revs 2046-2051 (cb4a8bf1f)
cb4a8bf1f queue: revs 2046-2051: row 169 in-review round 1 (Darkwing 2046-2047), row 175 brief re-pin for the wrapper fix (Sage 2048), row 175 in-review round 1 on 7b27ab3f9 (Dewey 2049-2050), row 169 r1 approve recorded (Filbert 2051, comment 29263)
c7939a568 sessions: Filbert row 169 r1 review, approve
423ff5c86 sessions: Dewey row 175 round 1 in-review
3dfaea286 sage: row 175 brief carries the scripts/mosaic dispatch fix (plugins, name, names, follow, threads, thread go to packages/cli), test 12 and a mutant; found in Darkwing's row 169 rehearsal
d63cfca22 log: row 178 brief for mos-0881 (30622a229, c6ef51ee1)
c6ef51ee1 queue: row 178 re-pinned to the mos-0881 brief (rev 2045, Sage)
30622a229 sage: row 178 brief, the turn-on doesn't wait for Jason (mos-0881), with roll-back-at-once on a failed signed-in check; bc310ee pod-label part recorded
47a351add log: rows 176 and 178 briefs revised for mos-0878 (80cabd935, c4e049319)
c4e049319 queue: rows 176 and 178 re-pinned to the mos-0878 briefs, row 178 piece updated and after set to 169, 175, 176 (revs 2041-2044, Sage, mos-0878)
80cabd935 sage: row 176 brief adds the credentials-body and project-root tests (mos-0878 Q1); row 178 brief rewritten for mos-0878 Q2: partial fix after the window rows, console-proof.token slot, ops-01 SealedSecret and middleware under R27, console-allowed-uid recorded as decision 101's uid and left alone
0750b6a49 log: rows 176-178 filed (#1674-#1676, mos-0872, mos-0874), row 175 briefed and claimed
58e173535 queue: rows 176 (#1674), 177 (#1675) and 178 (#1676) added (revs 2038-2040, Sage, mos-0872, mos-0874)
6ee7285c0 sage: briefs for rows 176 (#1674, Console tester listener on 127.0.0.1, 7332 refuses x-mosaic-tester, mos-0872/0874), 177 (#1675, tester threads, scoping) and 178 (#1676, Traefik proof for signed-in requests, Vikunja #385, mos-0874)
835941b7c queue: row 175 widened to tester writes and briefed with no after (revs 2032-2036, Sage, mos-0870 N2, mos-0872); also Dewey's rev 2037 (dewey-175-claim, row 175 in-progress)
1c90c68c5 sage: row 175 brief widened to tester reads and writes (#1673, Q173, mos-0870 N2, mos-0872 Q1-Q3): seven writes recorded as tester, nine human-only items, prefix lifted, project init --tester inside the data root's project area only
d195d171c log: row 166 landed (4b738e2da, #1663 closed), row 175 filed (#1673, mos-0868)
6b8f94524 queue: row 166 done with landing note (revs 2029-2030), row 175 added after 169 (#1673, mos-0868, rev 2031); Sage revs only
f8ac674cc sage: brief for row 175 (#1673, --tester on the window reads, mos-0868); Window B doc after mos-0866 F1-F3 and mos-0868: W4 from the unit template, agents to Mos with --tester, Jason's reads in J1 and J2
4b738e2da stack-release: refuse unreadable drop-ins and quoted units, recheck the bus after a held read, gate on the target copy (row 166, #1663)
64922106d sage: carry-past-row64 names Vikunja P19 #383, no pi window before the pi credential is settled (mos-0865 D2)
c7424db50 log: row 64 closed, D2 coder sessions on both harnesses, #1557 closed (mos-0863, mos-0864)
5cabf919e queue: row 64 done, landing note with D2 #1557 comment 29228 (mos-0864; Sage revs 2027-2028)
c87865ee0 sage: row 64 D2 evidence, scratch-root builder, driver, check and both coder manifests (mos-0863 D2, #1557 comment 29228)
3510c3cbf queue: row 174 for #1672, skill read BOM and fs errors after row 173, not started (mos-0863 D4; Sage rev 2026)
9c80ba7f1 plans: brief for #1672, skill reads keep a leading BOM and report fs errors as skill-refused (row 64 N2/N3, mos-0863 D4)
46de60893 sage: window carry step for any pin past row 64, install and activate the seven role skills from the pinned copy (mos-0863 D3, #1557)
ebfc23c43 sage: row 64 packet, build notes, both gates, mutants and the landing manifest; BUILD.md item 5 corrected for Darkwing N1 (mos-0863 D5, #1557)
6b6567b8b harness: README names bundle-refused for the skill content refusals, skill-refused at the launcher (row 64 F1, #1557 comment 29218)
9f0039711 roles, harness, cli: a managed session gets its role's skills as prompt text on both harnesses (row 64, #1557)
1a01f63ea queue: row 64 round 1 approvals, Filbert rev 2024 and Darkwing rev 2025 on manifest 7689cd9b (#1557)
7c81d5e9c sessions: Filbert row 64 r1 review, approve
12ac2c428 sessions: Sage line for row 64 candidate, gate and in-review round 1
e76c73f72 queue: row 64 started and in-review round 1 on c6d7d538f, reviewers darkwing and filbert (#1557, Sage revs 2022-2023 and the start rev)
087d202bc queue: row 173 for the Seen click intent gap after row 172 (#1671, mos-0861 A1; Sage rev 2021)
a0da43dab plans: brief for the Seen click intent gap after row 172 (#1671, mos-0861 A1)
b5d4d0f22 sessions: Sage line for the row 172 landing and close-out
c24fe5d0f build-log: row 172 landing, the dropped Seen click and the row 165 reload race (#1670)
83db85aa3 queue: row 172 round 1 Darkwing approve (darkwing rev 2018), landing note and done (Sage revs 2019-2020)
be10e0c83 webui: a Seen click during a Board read waits for the read and posts, and the row 165 test loads the page instead of reloading from an evaluate (row 172, #1670)
7f38a2f54 sage: row 172 packet, base control and trace lines corrected (Darkwing D1, D2 on #1670)
0ed9412fc sessions: Sage line for the 170/171/134 build-log and row 172 round 1
9d6e47dd5 queue: row 172 brief re-pin, briefed, start and round 1 in-review on 15c3d8ca1 (Sage revs 2013-2017)
17d566305 sage: row 172 packet, candidate 15c3d8ca1 (cause trace, mutants, 10-run loop, gate)
164e1f97f row 172 brief: the cause is a Seen click dropped during a Board read, and the reload race in the row 165 test (P19 366, #1670)
bab069b3c build-log: rows 170, 171 and 134 landings, with the row 134 range-diff evidence (mos-0859/0860)
b42934b85 queue: row 134 done on 3a600cf5b (Sage revs 2011-2012: note, done)
a85e573d4 cli README: the chief of staff reads the organization revision with organization_revision, not from the human (row 134 follow-up, Filbert #1669 29193)
3a600cf5b bus, harness: a role holding organization.change reads the organization revision itself with organization.revision and the organization_revision tool (row 134, #1669)
04155deff queue: row 171 done on 078518e4e, plus revs 1996-2010 (Sage: 171 reopen/request/note/done, 172 add, 134 review request; Rocko 1997-1998 row 171 round 2 in-review; Researcher 2002-2004 row 134 start and round 1 in-review; Dewey 2007 row 171 approve; Filbert 2008 row 134 approve)
078518e4e bus, cli, webui: a thread project named like a business-file repo refuses project-name-is-repo unless --repo matches, with a clearer CLI refusal (row 171, #1668)
b2d3b6c47 sessions: Filbert row 134 r1 review, approve
ed045ac84 dewey: SESSIONS line for the row 171 round 2 review (#1668)
4d9114ab4 sage: row 172 brief, the board-held sign-out wait under gate load (P19 366, #1670, mos-0858); cause section open until traced
d58c9c5cd queue: row 170 done on cb43dcb45, plus revs 1970-1994 (Sage: 171 scope/re-pin/request/note, 134 re-pins/assign/issue/briefed, 64 and 66 re-pins, 64 start, 170 note and range-diff; Rocko 1970, 1973-1974 row 171 start and round 1; Dewey 1971, 1981-1982 row 170 claim and in-review, 1990 row 171 approve; Filbert 1986 row 170 approve)
cb43dcb45 bus, cli: a tester message to a role nobody holds refuses tester-target-not-running, and talk --tester exits 3 (row 170, #1667)
228aeb503 sage: rows 64/66 brief, skills reach both harnesses as prompt text (pi read is workspace-confined, Claude Code Skill tool offers its own skills; probe in agents/sage/work/queue-64/probe.md)
c9f6e214f dewey: SESSIONS line for the row 171 round 1 review (#1668)
2cef8cd35 sage: row 134 brief owns the three stale revision-from-the-human sentences (Researcher build report)
9b11b8731 sessions: Filbert row 170 r1 review, approve
2e9fe381f docs: register Sage's rows 171, 134, 64 and 66 brief work and the b0721a0b0 push correction
e0bf9960d sage: rows 64 and 66 brief refreshed to 7319bd867 after row 65 (harness module files owned, plugins suite in the gates), row 64 candidate names Sage as author and gate owner (mos-0855)
b0721a0b0 dewey: SESSIONS line for the row 170 build and in-review (#1667)
7319bd867 sage: row 171 brief names cli.mjs (sage-1021, mos-0855), row 134 brief refreshed to 000730949 with owner Researcher, row 42 run log takes mos-0855's triggers (#1668)
000730949 queue: rows 170 and 171 briefed on Mos's approval, row 171 re-pinned to the mos-0854 brief (mos-0854, #1667, #1668) (revs 1964-1969)
fcfa577f2 sage: row 171 brief cites mos-0854 (D1 withdrawn, option B approved) in place of its open decision section (#1668)
92160cb30 queue: rows 170 (P19 380, #1667) and 171 (P19 379, #1668) added queued, briefs 97cc7f0a3 await Mos; Darkwing's row 169 claim (revs 1961-1963)
97cc7f0a3 sage: briefs for P19 380 (tester refusal, #1667, row 170) and P19 379 (project names vs repos, option B, #1668, row 171), for Mos's approval
42817065e queue: row 169 after cleared, in-review waits on 166's landing by note (mos-0852 point 5, #1666) (revs 1959-1960)
56534526b sage: Window B last section rewritten for the approved two-phase path, row 169 (mos-0848 (b), mos-0852, #1558, #1666)
cbdcf1967 queue: row 169 briefed on Mos's brief approval (mos-0852, #1666) (rev 1958)
3ff2360dc sage: Window B P3 recorded done from Darkwing's rehearsal, with what it didn't exercise (#1558)
c5b74bef2 darkwing: Window B P3 scratch rehearsal, activate --pm --migrate 3h to 3i and rollback --restore on blob 4b16e848 (sage-1004, mos-0838 D2, #1558)
3b5c964eb queue: row 169, the stack-release.sh two-phase PM start (P19 382, #1666), brief pinned at bfc5fa7ba36e (revs 1956-1957)
b201760c5 sage: W6 business instances from $C_NEW and the project list channel note in plan A, verb routes checked in A and B (mos-0851), row 169 in the 382 brief (#1558, #1666)
bd8416bc2 plans: brief for P19 382, activate past c216f47db with the PM launched after the harness kind is set (mos-0848, #1666)
421217411 sage: Window A P2 CONSOLE_PASS and the post-W5b channel undo before rollback (mos-0849, #1558)
6e7c23d7d sage: Darkwing's Window A and B scratch --plan and load checks, cited in both plans (#1558)
855c9eb01 sage: Window A and B plans with mos-0846 U1, the 382 bus-exit finding, mos-0845 P19 comments (#1558)
6dbc67302 sage: Window A and B plans with mos-0845 rulings, P19 378-382 filing scripts (#1558)
894ce3f37 sage: file row 65 follow-ups as P19 376 and 377 (mos-0842 item 4, #1558)
73bbbee81 sessions: Sage row 65 landing, c216f47db with gate g3 green (#1558)
a5810fc84 build-log: row 65 landed as c216f47db, gate g3 green, mos-0841 conditions met, not live (#1558)
71fd9b922 queue: row 65 done, landed as c216f47db on #1558 (sage rev 1955)
aed9062b4 sage: row 65 landing notes, c216f47db with gate g3 green, the mos-0840 Routing view, the plugins set patch for Jason, follow-up 5 (#1558)
c216f47db plugins, cli, bus, business, webui: harness, model and thinking from the instance vars, a fallback route, and a harness plug-in kind (row 65, #1558)
866f3c5a8 queue: row 65 round 2 in review on #1558 with candidate 8d7c9e2f1, request 29143 (sage revs 1951-1952); darkwing approve (rev 1953, comment 29144) and dewey approve (rev 1954, comment 29145), both on manifest 8df15e39
24320f80c sessions: Dewey row 65 round 2 review, approve (comment 29145, rev 1954)
b4c9cb359 sage: row 65 round 2 packet, candidate 8d7c9e2f1 on 89ddb0225, manifest, diff, public/ diff (digest a91cf866 unchanged), build notes, gate and 18 mutants (#1558)
89ddb0225 queue: row 65 round 1 verdicts, dewey changes (rev 1947, comment 29136) and darkwing changes (rev 1948, comment 29137); sage moves row 65 back to in-progress (rev 1949) and re-pins the brief to blob 0cdff8739051 (rev 1950) for round 2 (#1558)
0235fa9fd brief: row 65 routing table names the chief of staff's Q169 assistant exception and its tests (round 2 ruling, sage-1006, #1558)
ff9edc778 sessions: Dewey row 65 round 1 review, changes (comment 29136, rev 1947)
9014f9f72 sessions: Sage row 65 build, Mos decision 123 go (mos-0841) and in-review
4c6649454 queue: row 65 in review, round 1 on #1558 with candidate ccdbc2232, request 29133 (sage revs 1945-1946)
1d5897024 sage: row 65 packet, candidate ccdbc2232 manifest, diff, public/ diff, build notes, gate and mutants (#1558)
d8336daef queue: row 65 brief re-pinned for the human-only routes.set verb (sage rev 1944)
841e0b0a2 brief: row 65 routing table saves through a human-only routes.set verb, outside ORGANIZATION_KEYS
4d856a0cd queue: row 65 brief re-pinned to 54cbf1a2 for the Console routing table, and its gate names Mos's decision 123 check (sage revs 1942-1943)
d3af6db97 brief: row 65 adds a Console routing table for harness, model, thinking and fallback (mos-0840), and refuses thinking a harness can't apply
b65e6d5fe sessions: Sage row 168 landing, row 65 brief amendment (decision 151), row 7 posts
e1bfc2cd4 queue: row 65 in progress and brief re-pinned to 802e046c with its gate, row 168 approved by Dewey and done (sage revs 1937, 1939-1941; dewey rev 1938)
8e2cbb555 brief: row 65 keeps the instance vars as its one source, adds fallback vars and the full harness list (decision 151, #1558)
efb51169d ledger: count only stack issue numbers, a tracker-name skip and a --first-issue floor (#1665)
54786df03 sessions: Dewey row 168 review round 1, approve (29121)
c34deedf9 sessions: Sage row 168 build and review request, P19 371 rulings
3bf16114a queue: row 168 in review round 1, manifest candidate, request 29120 (sage, revs 1935-1936)
6da8fdaa9 sage: row 168 packet, candidate f3a966ea4 manifest, diff, build notes and gate (#1665)
e2ad3aa10 queue: row 168 in progress, brief re-pinned to 52ac1975 and piece updated (sage, revs 1932-1934)
03586947a docs: row 168 brief amended before build, floor moves to a --first-issue option (#1665); window-plan: mos-0838 rulings in the 3i draft
e69e646b4 window-plan: P19 371 3i window draft for Mos, one or two windows and the restore caveat
c16ba2f0c queue: row 168 ledger stack refs added and briefed, #1665 (sage)
a1572a8f7 docs: brief for the ledger counting only stack issue numbers (#1665, P19 372, row 7 follow-up)
15357b4ba sessions: Sage AM standup and row 7 week 10-11 ledger rerun record
b90d944c8 queue: row 7 note, 10-11..10-17 ledger rerun 29089 (sage)
296972652 queue: row 126 Filbert r2 approve and done (sage)
a267a64b1 sessions: Sage row 126 landing, P19 371 and 372, row 7 week ledger; Dewey queue-126 packet
ca15d73e9 limits: a daily token quota for the account the stack uses, and bus schema 3h to 3i (row 126, #1620)
54319f552 sessions: Filbert row 126 r2 review, approve
4c385db45 sessions: Dewey row 126 round 4 build and review rounds 1-2
2124cfa76 queue: row 126 Filbert r1 approve, brief re-pin for 3h to 3i, row 7 week note, round 2 in-review (sage)
e264db51b plans: row 126 brief names the 3h to 3i step and the account guard (#1620)
1df04f52f sessions: Filbert row 126 r1 review, approve
9e2b26866 queue: row 167 Filbert approve and done, row 126 round 1 in-review (sage)
640a1ee97 sessions: Sage row 167 landing and row 126 3i ruling
pm: the bus starts without --pm and the PM stays pending; next: Jason's plugins set of harness, then pm-on
bus: scripts/bus-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
Console: scripts/webui-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
CLI: scripts/stack-copy.sh wrapper 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
# exit 0
## W5. activate NEW --pm-after-harness --migrate (phase 1, migrates)
# command: (cd /home/jwoltje/darkwing-scratch/mbc/p3/repo && <scratch env> scripts/stack-release.sh activate 8e888014d4f4bbbe7f1e6fa598003c374c169856 mosaic-stack --pm-after-harness --migrate --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin)
stack-release: captured the rollback set: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/state/stack-rollback/20261020T003241Z-8e888014d4f4
stack-release: stopped both units
stack-release: stopped store schema: 3h
stack-release: backup: /home/jwoltje/darkwing-scratch/mbc/p3/root/data/backups/stack/20261020T003241Z-8e888014d4f4
stack-release: migrated the store to 3i
stack-release: installed 8e888014d4f4bbbe7f1e6fa598003c374c169856
stack-release: gate passed on 8e888014d4f4bbbe7f1e6fa598003c374c169856
stack-release: activate ok: 8e888014d4f4bbbe7f1e6fa598003c374c169856 is live for mosaic-stack without its PM; the PM is pending: Jason's plugins set of harness, then pm-on
# exit 0
# pointer: {"copy":"8e888014d4f4bbbe7f1e6fa598003c374c169856","business":"mosaic-stack","pm":false,"pmPending":true,"claude":"/home/jwoltje/darkwing-scratch/mbc/p3/b/claude","console":["--port","47394","--business","mosaic-stack"],"schema":"3i","activation":"20261020T003241Z-8e888014d4f4","at":"2026-10-20T00:32:42Z"}
# bus unit ExecStart: /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856/scripts/mosaic bus start %i
# Console unit ExecStart: /usr/bin/node /home/jwoltje/darkwing-scratch/mbc/p3/copies/8e888014d4f4bbbe7f1e6fa598003c374c169856/packages/webui/src/cli.mjs serve --checkout /home/jwoltje/darkwing-scratch/mbc/p3/repo --port 47394 --business mosaic-stack
# business file plugins: {"usage-source":["transcript"],"channel":["cli","webui"]}
# activation log, last line: {"at":"2026-10-20T00:32:42Z","op":"activate","from":"5fa9cc8f2c66b52408b652b59c3070f7210b44d0","to":"8e888014d4f4bbbe7f1e6fa598003c374c169856","backup":"20261020T003241Z-8e888014d4f4","activation":"20261020T003241Z-8e888014d4f4","result":"ok","pm":"pending"}
# W5 activation 20261020T003241Z-8e888014d4f4; backup /home/jwoltje/darkwing-scratch/mbc/p3/root/data/backups/stack/20261020T003241Z-8e888014d4f4; STAMP 2026-10-20T00:32:41.938Z; SCHEMA 3h; files: bus DATA_ROOT LISTING.txt MODES.txt ROLLBACK_SET SCHEMA SHA256SUMS SOURCE.sha256 STAMP
sha256sum: bus.sqlite: No such file or directory
bus.sqlite: FAILED open or read
sha256sum: WARNING: 1 listed file could not be read
# STOP: backup SHA256SUMS does not check
@@ -0,0 +1,36 @@
{
"schema": "3h",
"tables": {
"usage_records": {
"rows": 5,
"maxSeq": 5,
"sha256": "23cf81fa23849b58c272cb4ee668b359a4dea7a34a4dc9e18573b9a9633bf6b2",
"byRun": [
{
"business": "mosaic-stack",
"run": "p3-run-a",
"input": "1200",
"output": "2400",
"unknownTurns": 1
},
{
"business": "mosaic-stack",
"run": "p3-run-b",
"input": "0",
"output": "0",
"unknownTurns": 1
}
]
},
"instance_names": {
"rows": 2,
"maxSeq": 2,
"sha256": "04f8f0d94725145f7204a37d232fbf19c5c4f1e2930fda37482dff5b5cd484e4"
},
"threads": {
"rows": 1,
"maxSeq": 1,
"sha256": "15169aaf4e94d892f2202d0fd7d5af79b75ba017d23375ae389bae25dcc16edb"
}
}
}
@@ -0,0 +1,13 @@
{
"business": "mosaic-stack",
"revision": "c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
]
}
}
@@ -0,0 +1,16 @@
{
"business": "mosaic-stack",
"revision": "486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
],
"harness": [
"claude-code"
]
}
}
@@ -0,0 +1 @@
{"revision":"486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a","plugins":{"harness":null}}
@@ -0,0 +1,35 @@
9cbf9a23e41e546a6b92a3403ee800e6e325ca5c9065e9580fd3678c304dd979 ./b/all.sh
6b25b038e3d7f4d12d169613a6f7e214d2c4f69e34fb98d446f4adad3876e44d ./b/claude
4f9dffbf3d6e75e14b19f8d4ef45b390e4997cccc61caa9323cf822ffed4c58c ./b/cmp.mjs
0b9147124dbef220a2a17c647b2f9582155ff25c5ee3712378ef2d07c978ba66 ./b/env.sh
89c201e59d7bb6427041734757d170df7c9b39d96d8cb680a57fbb9eff5ab5aa ./b/healthz.cjs
fb1f19bb5a464d575ffdeb133a9a2df7fdf507218e683fddaaa170280d5c9fed ./b/jget.mjs
e1dcabdd3e43cae6f885a44fc1fe357406c00d896c03fff889f8b61dd4e15683 ./b/journalctl
2aed6b4762c6f48cd338f15134822118dddac9ce6246ef5c4fc9faff6f80178e ./b/load-check.mjs
dc9ebad483d55f8016b73d6fb36a7b6e6d7921bc052a605aeabec8a650136ed0 ./b/mkbiz.mjs
7a0821f59d23d318d7d2d5a24b24f774548acc25c31da15d92566e9d6c614f42 ./b/prep.sh
3a673f0ade68f3f1c60897536e8a0c8a08e06a07dc084de80f607a8920569c26 ./b/run.sh
073f1952e35f464fe26fa9c86161b322c3f10f20814128b000b9c368e5c9de2a ./b/seed.sh
98d10dc85c7ea32e032529935d2cf39b4d63196e5e7ab05bd4332b43833e88fb ./b/store-seed.mjs
e3669292be33f8b8298d9d1a00ba19e5ca42e3b50fc995007c9fc4587d0df6cd ./b/systemctl
30908331d33adead6e32b9da5b77ca29283f42446636527946541618331dc8a2 ./b/systemd-analyze
6e9494e2b4f306ca2320f0cc274d9d4aeb925c73cc94a9c678f607a2b14667ed ./b/teardown.sh
0a4884269bd5914075294e803262078bd7aa12c8b8e119b1aa7b8d58fb8c5f72 ./b/wait-run.sh
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-after.txt
b3a59cabad922206911f53bbbd664c2409f1356947e580e97a990d60220d6f09 ./docker-networks-before.txt
c73ce32b18a84015ffc8dd52160ed0dcfa53cdd1eee1bbd4cc8e8f0b6a856f90 ./p3-live-store-stat.txt
aee335fdece077a8486c6ed803797536c1c47445064b9c78ca2507fe37979880 ./p3-steps.log
ce39cc946d97e24ee766f54c58c3127f18abe03529a66c2ffb84bfb226928bb8 ./p3-teardown.txt
516bf39a2a92ea3c5856e068982a99a37724c32c31ac0ec22a77f7d4d739bcdf ./p3.txt
c15a0ab6898c3841929fc0ea1c7dc91c83c0c14caaf35f576f42459428f3d0fc ./R1-after.json
813399ad5b05721b3e332783d15f4c66c788fd4edb6d8395c335fa21c22c7664 ./R1.json
3381436016f77d9845361d469fd0d77dd67ae1227bd573c1b4bd82abc7e50df4 ./R1-read.json
3e38ac7b318f14e30bfdb4dcf6939682b4a6ee6615d0c84172f8aa0384daa8cc ./snap/D3.json
9e3ee240b117169fe3f252fc6b4f6834c7bf5629015a5f00764a18f44aa7bd60 ./snap/F.json
9e3ee240b117169fe3f252fc6b4f6834c7bf5629015a5f00764a18f44aa7bd60 ./snap/S1.json
c8c448bb30ca2803ddb82fb1d58acc5cbc63c85cf5280239f620c0915ec03339 ./snap/S2.json
c8c448bb30ca2803ddb82fb1d58acc5cbc63c85cf5280239f620c0915ec03339 ./snap/W5.json
d4202b7bee78b0b8e4e2738c63f22d3e898d310948b2e06d0b7bb17b9bd1558c ./W3-plan.txt
3381436016f77d9845361d469fd0d77dd67ae1227bd573c1b4bd82abc7e50df4 ./W6-after.json
387d31ef17e1b1dfbd0ae26298418aa9fff5a0a1d6b836a7bc4be282c4f6a654 ./W6.json
c15a0ab6898c3841929fc0ea1c7dc91c83c0c14caaf35f576f42459428f3d0fc ./W6-read.json
@@ -0,0 +1,152 @@
plan: activate for mosaic-stack
from: 5fa9cc8f2c66b52408b652b59c3070f7210b44d0
to: 8e888014d4f4bbbe7f1e6fa598003c374c169856
store schema: 3h (read from the store the running bus holds)
target schema: 3i
migration: 3h to 3i, after a backup of the stopped store
migration steps: 3h to 3i
needs: --migrate (given)
needs: Jason present for this run (decision 96 condition 2)
commits: the run adds 138 (newest first, at most 200):
8e888014d log: row 175 landed (98d29769e), row 176 brief amended and launched, merged window drafted; sessions: Sage
473258a51 queue: revs 2072-2076: row 175 round 3 approve on 2e30f2a1 (Filbert 2072, comment 29279), landing note and done after 98d29769e (Sage 2073, 2074); row 176 brief re-pinned to 0f7119af9566 for the stack-release --tester-port pointer change and row 175 F1 (Sage 2075), queued to briefed (Sage 2076)
2fecddfba sage: row 176 brief: activate --tester-port N writes the flag into the pointer's Console flags, a rollback or an activate to a copy whose Console lacks it drops it, tester-port-target refuses before anything stops; tests and three mutants; row 175 F1 (TOOLS.md step 2) rides along
98d29769e bus, cli: tester reads and the W1-W7 tester writes, recorded as tester; scripts/mosaic sends plugins, name and names to the CLI (row 175, #1673)
1d81c54ff sessions: Filbert row 175 r3 review, approve
716ddcf1e queue: revs 2058-2071: row 179 start, in-review and request (Darkwing 2058, 2060, 2061), issue #1677 (Sage 2059), r1 approve (Dewey 2062, comment 29271), landing note and done after 9e74925c2 (Sage 2063, 2064); row 175 r2 request on f9e41b918 (Dewey 2065-2067, comment 29275), back to in-progress to rebase onto 9e74925c2 (Sage 2068, 2069), round 3 request on the rebased candidate 2e30f2a1 (Dewey 2070, 2071, comment 29276)
0f45a3e6e sessions: Dewey row 175 round 2 to in-review on 989699f7c, row 179 approved
9e74925c2 docs: TOOLS.md follow-ups F1-F3 from the row 169 review (row 179, #1677)
ce5807989 log: row 169 landed (264756a30), row 179 briefed, row 175 to round 2 (1bfc9833b)
1bfc9833b queue: revs 2052-2057: row 179 added and briefed (Sage 2052, 2057), row 169 landing notes and done after 264756a30 (Sage 2053, 2054, 2056), row 175 r1 approve recorded (Filbert 2055, comment 29264)
c98a5d17a sessions: Dewey row 175 round 1 approved
8f2ac5236 sessions: Filbert row 175 r1 review, approve
264756a30 stack-release: activate --pm-after-harness, pm-on and the pending pointer, so a re-pin past c216f47db starts the PM after the harness kind is set (row 169, #1666)
b2a75f318 sage: brief for the row 169 TOOLS.md follow-ups F1-F3 (Filbert, #1666 comment 29263), owner Darkwing, reviewer Dewey, after row 169
e7d47c346 log: rows 169 and 175 in-review, row 169 r1 approve, queue revs 2046-2051 (cb4a8bf1f)
cb4a8bf1f queue: revs 2046-2051: row 169 in-review round 1 (Darkwing 2046-2047), row 175 brief re-pin for the wrapper fix (Sage 2048), row 175 in-review round 1 on 7b27ab3f9 (Dewey 2049-2050), row 169 r1 approve recorded (Filbert 2051, comment 29263)
c7939a568 sessions: Filbert row 169 r1 review, approve
423ff5c86 sessions: Dewey row 175 round 1 in-review
3dfaea286 sage: row 175 brief carries the scripts/mosaic dispatch fix (plugins, name, names, follow, threads, thread go to packages/cli), test 12 and a mutant; found in Darkwing's row 169 rehearsal
d63cfca22 log: row 178 brief for mos-0881 (30622a229, c6ef51ee1)
c6ef51ee1 queue: row 178 re-pinned to the mos-0881 brief (rev 2045, Sage)
30622a229 sage: row 178 brief, the turn-on doesn't wait for Jason (mos-0881), with roll-back-at-once on a failed signed-in check; bc310ee pod-label part recorded
47a351add log: rows 176 and 178 briefs revised for mos-0878 (80cabd935, c4e049319)
c4e049319 queue: rows 176 and 178 re-pinned to the mos-0878 briefs, row 178 piece updated and after set to 169, 175, 176 (revs 2041-2044, Sage, mos-0878)
80cabd935 sage: row 176 brief adds the credentials-body and project-root tests (mos-0878 Q1); row 178 brief rewritten for mos-0878 Q2: partial fix after the window rows, console-proof.token slot, ops-01 SealedSecret and middleware under R27, console-allowed-uid recorded as decision 101's uid and left alone
0750b6a49 log: rows 176-178 filed (#1674-#1676, mos-0872, mos-0874), row 175 briefed and claimed
58e173535 queue: rows 176 (#1674), 177 (#1675) and 178 (#1676) added (revs 2038-2040, Sage, mos-0872, mos-0874)
6ee7285c0 sage: briefs for rows 176 (#1674, Console tester listener on 127.0.0.1, 7332 refuses x-mosaic-tester, mos-0872/0874), 177 (#1675, tester threads, scoping) and 178 (#1676, Traefik proof for signed-in requests, Vikunja #385, mos-0874)
835941b7c queue: row 175 widened to tester writes and briefed with no after (revs 2032-2036, Sage, mos-0870 N2, mos-0872); also Dewey's rev 2037 (dewey-175-claim, row 175 in-progress)
1c90c68c5 sage: row 175 brief widened to tester reads and writes (#1673, Q173, mos-0870 N2, mos-0872 Q1-Q3): seven writes recorded as tester, nine human-only items, prefix lifted, project init --tester inside the data root's project area only
d195d171c log: row 166 landed (4b738e2da, #1663 closed), row 175 filed (#1673, mos-0868)
6b8f94524 queue: row 166 done with landing note (revs 2029-2030), row 175 added after 169 (#1673, mos-0868, rev 2031); Sage revs only
f8ac674cc sage: brief for row 175 (#1673, --tester on the window reads, mos-0868); Window B doc after mos-0866 F1-F3 and mos-0868: W4 from the unit template, agents to Mos with --tester, Jason's reads in J1 and J2
4b738e2da stack-release: refuse unreadable drop-ins and quoted units, recheck the bus after a held read, gate on the target copy (row 166, #1663)
64922106d sage: carry-past-row64 names Vikunja P19 #383, no pi window before the pi credential is settled (mos-0865 D2)
c7424db50 log: row 64 closed, D2 coder sessions on both harnesses, #1557 closed (mos-0863, mos-0864)
5cabf919e queue: row 64 done, landing note with D2 #1557 comment 29228 (mos-0864; Sage revs 2027-2028)
c87865ee0 sage: row 64 D2 evidence, scratch-root builder, driver, check and both coder manifests (mos-0863 D2, #1557 comment 29228)
3510c3cbf queue: row 174 for #1672, skill read BOM and fs errors after row 173, not started (mos-0863 D4; Sage rev 2026)
9c80ba7f1 plans: brief for #1672, skill reads keep a leading BOM and report fs errors as skill-refused (row 64 N2/N3, mos-0863 D4)
46de60893 sage: window carry step for any pin past row 64, install and activate the seven role skills from the pinned copy (mos-0863 D3, #1557)
ebfc23c43 sage: row 64 packet, build notes, both gates, mutants and the landing manifest; BUILD.md item 5 corrected for Darkwing N1 (mos-0863 D5, #1557)
6b6567b8b harness: README names bundle-refused for the skill content refusals, skill-refused at the launcher (row 64 F1, #1557 comment 29218)
9f0039711 roles, harness, cli: a managed session gets its role's skills as prompt text on both harnesses (row 64, #1557)
1a01f63ea queue: row 64 round 1 approvals, Filbert rev 2024 and Darkwing rev 2025 on manifest 7689cd9b (#1557)
7c81d5e9c sessions: Filbert row 64 r1 review, approve
12ac2c428 sessions: Sage line for row 64 candidate, gate and in-review round 1
e76c73f72 queue: row 64 started and in-review round 1 on c6d7d538f, reviewers darkwing and filbert (#1557, Sage revs 2022-2023 and the start rev)
087d202bc queue: row 173 for the Seen click intent gap after row 172 (#1671, mos-0861 A1; Sage rev 2021)
a0da43dab plans: brief for the Seen click intent gap after row 172 (#1671, mos-0861 A1)
b5d4d0f22 sessions: Sage line for the row 172 landing and close-out
c24fe5d0f build-log: row 172 landing, the dropped Seen click and the row 165 reload race (#1670)
83db85aa3 queue: row 172 round 1 Darkwing approve (darkwing rev 2018), landing note and done (Sage revs 2019-2020)
be10e0c83 webui: a Seen click during a Board read waits for the read and posts, and the row 165 test loads the page instead of reloading from an evaluate (row 172, #1670)
7f38a2f54 sage: row 172 packet, base control and trace lines corrected (Darkwing D1, D2 on #1670)
0ed9412fc sessions: Sage line for the 170/171/134 build-log and row 172 round 1
9d6e47dd5 queue: row 172 brief re-pin, briefed, start and round 1 in-review on 15c3d8ca1 (Sage revs 2013-2017)
17d566305 sage: row 172 packet, candidate 15c3d8ca1 (cause trace, mutants, 10-run loop, gate)
164e1f97f row 172 brief: the cause is a Seen click dropped during a Board read, and the reload race in the row 165 test (P19 366, #1670)
bab069b3c build-log: rows 170, 171 and 134 landings, with the row 134 range-diff evidence (mos-0859/0860)
b42934b85 queue: row 134 done on 3a600cf5b (Sage revs 2011-2012: note, done)
a85e573d4 cli README: the chief of staff reads the organization revision with organization_revision, not from the human (row 134 follow-up, Filbert #1669 29193)
3a600cf5b bus, harness: a role holding organization.change reads the organization revision itself with organization.revision and the organization_revision tool (row 134, #1669)
04155deff queue: row 171 done on 078518e4e, plus revs 1996-2010 (Sage: 171 reopen/request/note/done, 172 add, 134 review request; Rocko 1997-1998 row 171 round 2 in-review; Researcher 2002-2004 row 134 start and round 1 in-review; Dewey 2007 row 171 approve; Filbert 2008 row 134 approve)
078518e4e bus, cli, webui: a thread project named like a business-file repo refuses project-name-is-repo unless --repo matches, with a clearer CLI refusal (row 171, #1668)
b2d3b6c47 sessions: Filbert row 134 r1 review, approve
ed045ac84 dewey: SESSIONS line for the row 171 round 2 review (#1668)
4d9114ab4 sage: row 172 brief, the board-held sign-out wait under gate load (P19 366, #1670, mos-0858); cause section open until traced
d58c9c5cd queue: row 170 done on cb43dcb45, plus revs 1970-1994 (Sage: 171 scope/re-pin/request/note, 134 re-pins/assign/issue/briefed, 64 and 66 re-pins, 64 start, 170 note and range-diff; Rocko 1970, 1973-1974 row 171 start and round 1; Dewey 1971, 1981-1982 row 170 claim and in-review, 1990 row 171 approve; Filbert 1986 row 170 approve)
cb43dcb45 bus, cli: a tester message to a role nobody holds refuses tester-target-not-running, and talk --tester exits 3 (row 170, #1667)
228aeb503 sage: rows 64/66 brief, skills reach both harnesses as prompt text (pi read is workspace-confined, Claude Code Skill tool offers its own skills; probe in agents/sage/work/queue-64/probe.md)
c9f6e214f dewey: SESSIONS line for the row 171 round 1 review (#1668)
2cef8cd35 sage: row 134 brief owns the three stale revision-from-the-human sentences (Researcher build report)
9b11b8731 sessions: Filbert row 170 r1 review, approve
2e9fe381f docs: register Sage's rows 171, 134, 64 and 66 brief work and the b0721a0b0 push correction
e0bf9960d sage: rows 64 and 66 brief refreshed to 7319bd867 after row 65 (harness module files owned, plugins suite in the gates), row 64 candidate names Sage as author and gate owner (mos-0855)
b0721a0b0 dewey: SESSIONS line for the row 170 build and in-review (#1667)
7319bd867 sage: row 171 brief names cli.mjs (sage-1021, mos-0855), row 134 brief refreshed to 000730949 with owner Researcher, row 42 run log takes mos-0855's triggers (#1668)
000730949 queue: rows 170 and 171 briefed on Mos's approval, row 171 re-pinned to the mos-0854 brief (mos-0854, #1667, #1668) (revs 1964-1969)
fcfa577f2 sage: row 171 brief cites mos-0854 (D1 withdrawn, option B approved) in place of its open decision section (#1668)
92160cb30 queue: rows 170 (P19 380, #1667) and 171 (P19 379, #1668) added queued, briefs 97cc7f0a3 await Mos; Darkwing's row 169 claim (revs 1961-1963)
97cc7f0a3 sage: briefs for P19 380 (tester refusal, #1667, row 170) and P19 379 (project names vs repos, option B, #1668, row 171), for Mos's approval
42817065e queue: row 169 after cleared, in-review waits on 166's landing by note (mos-0852 point 5, #1666) (revs 1959-1960)
56534526b sage: Window B last section rewritten for the approved two-phase path, row 169 (mos-0848 (b), mos-0852, #1558, #1666)
cbdcf1967 queue: row 169 briefed on Mos's brief approval (mos-0852, #1666) (rev 1958)
3ff2360dc sage: Window B P3 recorded done from Darkwing's rehearsal, with what it didn't exercise (#1558)
c5b74bef2 darkwing: Window B P3 scratch rehearsal, activate --pm --migrate 3h to 3i and rollback --restore on blob 4b16e848 (sage-1004, mos-0838 D2, #1558)
3b5c964eb queue: row 169, the stack-release.sh two-phase PM start (P19 382, #1666), brief pinned at bfc5fa7ba36e (revs 1956-1957)
b201760c5 sage: W6 business instances from $C_NEW and the project list channel note in plan A, verb routes checked in A and B (mos-0851), row 169 in the 382 brief (#1558, #1666)
bd8416bc2 plans: brief for P19 382, activate past c216f47db with the PM launched after the harness kind is set (mos-0848, #1666)
421217411 sage: Window A P2 CONSOLE_PASS and the post-W5b channel undo before rollback (mos-0849, #1558)
6e7c23d7d sage: Darkwing's Window A and B scratch --plan and load checks, cited in both plans (#1558)
855c9eb01 sage: Window A and B plans with mos-0846 U1, the 382 bus-exit finding, mos-0845 P19 comments (#1558)
6dbc67302 sage: Window A and B plans with mos-0845 rulings, P19 378-382 filing scripts (#1558)
894ce3f37 sage: file row 65 follow-ups as P19 376 and 377 (mos-0842 item 4, #1558)
73bbbee81 sessions: Sage row 65 landing, c216f47db with gate g3 green (#1558)
a5810fc84 build-log: row 65 landed as c216f47db, gate g3 green, mos-0841 conditions met, not live (#1558)
71fd9b922 queue: row 65 done, landed as c216f47db on #1558 (sage rev 1955)
aed9062b4 sage: row 65 landing notes, c216f47db with gate g3 green, the mos-0840 Routing view, the plugins set patch for Jason, follow-up 5 (#1558)
c216f47db plugins, cli, bus, business, webui: harness, model and thinking from the instance vars, a fallback route, and a harness plug-in kind (row 65, #1558)
866f3c5a8 queue: row 65 round 2 in review on #1558 with candidate 8d7c9e2f1, request 29143 (sage revs 1951-1952); darkwing approve (rev 1953, comment 29144) and dewey approve (rev 1954, comment 29145), both on manifest 8df15e39
24320f80c sessions: Dewey row 65 round 2 review, approve (comment 29145, rev 1954)
b4c9cb359 sage: row 65 round 2 packet, candidate 8d7c9e2f1 on 89ddb0225, manifest, diff, public/ diff (digest a91cf866 unchanged), build notes, gate and 18 mutants (#1558)
89ddb0225 queue: row 65 round 1 verdicts, dewey changes (rev 1947, comment 29136) and darkwing changes (rev 1948, comment 29137); sage moves row 65 back to in-progress (rev 1949) and re-pins the brief to blob 0cdff8739051 (rev 1950) for round 2 (#1558)
0235fa9fd brief: row 65 routing table names the chief of staff's Q169 assistant exception and its tests (round 2 ruling, sage-1006, #1558)
ff9edc778 sessions: Dewey row 65 round 1 review, changes (comment 29136, rev 1947)
9014f9f72 sessions: Sage row 65 build, Mos decision 123 go (mos-0841) and in-review
4c6649454 queue: row 65 in review, round 1 on #1558 with candidate ccdbc2232, request 29133 (sage revs 1945-1946)
1d5897024 sage: row 65 packet, candidate ccdbc2232 manifest, diff, public/ diff, build notes, gate and mutants (#1558)
d8336daef queue: row 65 brief re-pinned for the human-only routes.set verb (sage rev 1944)
841e0b0a2 brief: row 65 routing table saves through a human-only routes.set verb, outside ORGANIZATION_KEYS
4d856a0cd queue: row 65 brief re-pinned to 54cbf1a2 for the Console routing table, and its gate names Mos's decision 123 check (sage revs 1942-1943)
d3af6db97 brief: row 65 adds a Console routing table for harness, model, thinking and fallback (mos-0840), and refuses thinking a harness can't apply
b65e6d5fe sessions: Sage row 168 landing, row 65 brief amendment (decision 151), row 7 posts
e1bfc2cd4 queue: row 65 in progress and brief re-pinned to 802e046c with its gate, row 168 approved by Dewey and done (sage revs 1937, 1939-1941; dewey rev 1938)
8e2cbb555 brief: row 65 keeps the instance vars as its one source, adds fallback vars and the full harness list (decision 151, #1558)
efb51169d ledger: count only stack issue numbers, a tracker-name skip and a --first-issue floor (#1665)
54786df03 sessions: Dewey row 168 review round 1, approve (29121)
c34deedf9 sessions: Sage row 168 build and review request, P19 371 rulings
3bf16114a queue: row 168 in review round 1, manifest candidate, request 29120 (sage, revs 1935-1936)
6da8fdaa9 sage: row 168 packet, candidate f3a966ea4 manifest, diff, build notes and gate (#1665)
e2ad3aa10 queue: row 168 in progress, brief re-pinned to 52ac1975 and piece updated (sage, revs 1932-1934)
03586947a docs: row 168 brief amended before build, floor moves to a --first-issue option (#1665); window-plan: mos-0838 rulings in the 3i draft
e69e646b4 window-plan: P19 371 3i window draft for Mos, one or two windows and the restore caveat
c16ba2f0c queue: row 168 ledger stack refs added and briefed, #1665 (sage)
a1572a8f7 docs: brief for the ledger counting only stack issue numbers (#1665, P19 372, row 7 follow-up)
15357b4ba sessions: Sage AM standup and row 7 week 10-11 ledger rerun record
b90d944c8 queue: row 7 note, 10-11..10-17 ledger rerun 29089 (sage)
296972652 queue: row 126 Filbert r2 approve and done (sage)
a267a64b1 sessions: Sage row 126 landing, P19 371 and 372, row 7 week ledger; Dewey queue-126 packet
ca15d73e9 limits: a daily token quota for the account the stack uses, and bus schema 3h to 3i (row 126, #1620)
54319f552 sessions: Filbert row 126 r2 review, approve
4c385db45 sessions: Dewey row 126 round 4 build and review rounds 1-2
2124cfa76 queue: row 126 Filbert r1 approve, brief re-pin for 3h to 3i, row 7 week note, round 2 in-review (sage)
e264db51b plans: row 126 brief names the 3h to 3i step and the account guard (#1620)
1df04f52f sessions: Filbert row 126 r1 review, approve
9e2b26866 queue: row 167 Filbert approve and done, row 126 round 1 in-review (sage)
640a1ee97 sessions: Sage row 167 landing and row 126 3i ruling
pm: the bus starts without --pm and the PM stays pending; next: Jason's plugins set of harness, then pm-on
bus: scripts/bus-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --claude /home/jwoltje/darkwing-scratch/mbc/p3/b/claude
Console: scripts/webui-service.sh install --copy 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --port 47394 --business mosaic-stack
CLI: scripts/stack-copy.sh wrapper 8e888014d4f4bbbe7f1e6fa598003c374c169856 --copies /home/jwoltje/darkwing-scratch/mbc/p3/copies --bin /home/jwoltje/darkwing-scratch/mbc/p3/root/bin
@@ -0,0 +1,16 @@
{
"business": "mosaic-stack",
"revision": "486540eb9cbf45768b5bfb79a1391ebdf64dd5620068dc67cbac35ccfdfc1b5a",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
],
"harness": [
"claude-code"
]
}
}
@@ -0,0 +1,13 @@
{
"business": "mosaic-stack",
"revision": "c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32",
"plugins": {
"usage-source": [
"transcript"
],
"channel": [
"cli",
"webui"
]
}
}
@@ -0,0 +1 @@
{"revision":"c8f30cf15e69eb38dd35eca06266aa69eebb4bfef5267cd0e922671bb9751d32","plugins":{"harness":["claude-code"]}}
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# P3 driver: the live-store stat (mos-0878), prep, seed, run, teardown, the stat again, the Docker network
# names before and after, then the outputs copied to $WIN/p3 with SHA256SUMS. Started only behind
# wait-run.sh (busy.sh) on Sage's go. NEW=<sha> TP=1 for the run on the row 176 tool blob.
set -uo pipefail
. /home/jwoltje/darkwing-scratch/mbc/p3/b/env.sh
[ ! -e "$R/out" ] || { echo "all.sh: $R/out exists; move it aside first" >&2; exit 1; }
mkdir -p "$R/out"
S=$R/out/p3-live-store-stat.txt
LIVE=(/home/jwoltje/.mosaic-dev/bus/bus.sqlite /home/jwoltje/.mosaic-dev/bus)
{ echo "# before prep, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } > "$S"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-before.txt"
rc=0
"$B/prep.sh" && "$B/seed.sh" && "$B/run.sh" || rc=$?
"$B/teardown.sh"
docker network ls --format '{{.Name}}' | sort > "$R/out/docker-networks-after.txt"
{ echo "# after teardown, $(date -u +%FT%TZ)"; stat -c '%n %Y' "${LIVE[@]}"; } >> "$S"
cat "$S"
if [ "$(sed -n 2,3p "$S")" = "$(sed -n 5,6p "$S")" ]; then echo "live store stat: match"; else echo "live store stat: DIFFER"; rc=1; fi
if cmp -s "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; then echo "docker networks: unchanged"; else echo "docker networks: CHANGED"; diff "$R/out/docker-networks-before.txt" "$R/out/docker-networks-after.txt"; fi
echo "all.sh: run exit $rc"
W=/mnt/storage/src/mosaic-stack/agents/darkwing/work/window-merged-bc/p3/$(git -C "$REPO" rev-parse --short=9 HEAD)-tp$TP
mkdir -p "$W" && cp -p "$R"/out/*.txt "$R"/out/*.json "$R/out/p3-steps.log" "$W"/ 2>/dev/null; cp -pr "$R/out/snap" "$W"/
cp -p "$B"/*.sh "$B"/*.mjs "$B"/*.cjs "$B"/systemctl "$B"/journalctl "$B"/systemd-analyze "$B"/claude "$W"/ 2>/dev/null; mkdir -p "$W/b" && mv "$W"/*.sh "$W"/*.mjs "$W"/*.cjs "$W"/systemctl "$W"/journalctl "$W"/systemd-analyze "$W"/claude "$W/b"/ 2>/dev/null
rm -f "$W/last.txt"
(cd "$W" && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS)
echo "outputs: $W ($(wc -l < "$W/SHA256SUMS") files, SHA256SUMS sha256 $(sha256sum < "$W/SHA256SUMS" | cut -c1-64))"
exit $rc
Loaded 100 of 183 files, more files were not shown because too many files have changed in this diff. Show more