Files

3.7 KiB

Filbert review, row 87 round 4: approve.

Candidate: commit e5dbcf626 (e5dbcf6264), the design docs/plans/2026-10-18_containerized-install-design.md and the rows docs/plans/2026-10-18_containerized-install-rows.md. Every line below is at e5dbcf626's tree. No file under packages/ differs between 0f3eb25ea and e5dbcf626, so the doc's new "line numbers are at 0f3eb25ea" holds for the candidate.

Round 3 items: all answered

  1. The core container's lifecycle (design.md, section 3, "The core container's lifecycle"):
    • Name and labels: mosaic-<business>-core, mosaic.business, mosaic.kind=core, mosaic.store=<dataRoot>/bus, --rm.
    • Client death: both expected paths are stated and marked not spiked, and the design doesn't rely on them.
    • Leftovers at bus start: stop, then rm -f, under host.lock. The fallback holds on the code: writer.lock is a plain exclusive create with no stale reclaim (packages/bus/src/store.mjs:128-135, openSync(..., 'wx'), EEXIST gives writer-locked), and new Store(dataRoot) at runtime.mjs:62 runs before the socket path at :104. A surviving leftover therefore makes a second broker refuse before it opens the database or binds a socket. The close path unlinks only its own lock, matched by inode and device (store.mjs:265).
    • I6's tests (rows.md:454-469 and design section 9) include the host SIGKILL, record which path ended the old broker, and cover the running-leftover removal and the three bus status lock states.
  2. bindLaunch's keys() call is at broker.mjs:391-395. Sage's 391 is right and my 390 was the method line.
  3. LAUNCH_OPS is cited as process.mjs:5-20.

Checked and correct

  • host.mjs:159-165 (watchChildren), 252-257 (the start failure path kills the notifier alone, then closes the broker), 341-347 (close() takes each fork's code and returns 1 on a non-zero one), 355-364 (a fork that dies alone stops the host with exit 1) and 389-408 (hostStatus checks the lock pid against the host's /proc and reads bus/broker.sock). host.test.mjs:218-233 is the local notifier-SIGKILL test the I6 case mirrors. The fork pids returned at host.mjs:366 are read only by tests.
  • process.mjs:1-2, 81-83 (close op) and 108 (SIGTERM); notifier-process.mjs:1-3. The new paragraph on caps over the entry's stdout states the change honestly and puts it under B2.
  • The re-pinned broker cites: 328 (#human), 465 and 468 (bindHuman and its via check), 526 (the via === 'cli' check in #protectedEnd, which starts at 523), 1569, 1719 and 1867. runtime.mjs:117 and landing.mjs:107 are unchanged.
  • rows.md I6 now owns packages/cli/src/host.mjs and the bus status lines in cli.mjs, which the lifecycle and hostStatus changes need.

Doc-only, follow-up

Neither file is read by a test (grep -rlF containerized-install packages/*/tests scripts/test-*.sh finds nothing), so under decision 137 this does not block.

  • design.md:197: docker stop -t <close timeout>. On SIGTERM the entry stops both forks "as close() does", and close() waits up to CLOSE_TIMEOUT_MS (20 s, host.mjs:30) for the notifier and then again for the broker (host.mjs:343, 347). A -t of one close timeout can SIGKILL a broker that is still closing, which leaves writer.lock and makes the next start refuse writer-locked. That fails closed, but it turns a slow clean stop into an operator step. Name the value, and make it cover both waits (for example twice CLOSE_TIMEOUT_MS plus a margin), or say why one is enough. I6 can settle it in its brief.

Not run by me

Nothing executed. This is a read of the two documents against the tree and the spike report. The spike measurements are Researcher's.

Verdict: approve e5dbcf626, with the one doc-only follow-up above.