# Row 254 build: library sync follow-up (C2-03a deferrals) Row 254, #1759, reviewer Dewey, gate owner Sage. Brief: docs/plans/2026-10-21_library-sync-followup.md (0de97f429), for the deferrals Dewey named in the row 222 approval (#1723 comment 30138). Built on origin/refactor c3d88840c, which carries row 222 (0b33f5e9d) and row 196 (7247d80c7). Launch: sage-2163. ## What it does 1. **Client timeout.** `packages/bus/src/human-cli.mjs` gives `library.sync` a 130 s client timeout. Every other verb keeps Client's 5 s default (`timeout: undefined` takes the default). The server holds a library verb's socket for 120 s (`packages/bus/src/server.mjs`, the `socket.setTimeout(120_000)` branch), and the fetch alone may take 100 s (GIT_LIMITS). So the client waits past the server and gets the server's own answer, including its `request-timeout`, instead of giving up first. - The Console has no library route, so there is no Console timeout to change (brief item 1, "when one exists"). When a route is added, note that webui `humanCall` kills its child at 30 s by default. The route would need `timeoutMs` above 130 s for library.sync. - `tester-cli.mjs` is unchanged: library.sync is human-only, so the tester gets `human-required`. 2. **STATUS codes (215 N3).** `packages/webui/src/bus.mjs` maps six codes: | Code | Status | Why | |---|---|---| | library-sync-busy | 409 | a sync is running; read status again | | library-diverged | 409 | held for a human accept | | library-accept-stale | 409 | the tip moved; read status again | | library-accept-invalid | 400 | a malformed accept | | library-credential-missing | 503 | the remote can't be reached, like no bus to ask | | library-fetch-failed | 503 | the same | Neither 503 is 502, the default for an unknown code, so dropping any one entry changes its status and the test catches it. 3. **README (222 N4).** `packages/library/README.md` Sync section: the transport timeouts, that a client timeout leaves the sync running, that a second call gets `library-sync-busy`, and that `library.status` shows the result. It also says the Console has no library route yet. - Correction to row 222's BUILD.md, "What it does": "`webui/src/cli.mjs`: the Console gets the call" was not true. `cli.mjs` builds `librarySync` and passes it to `startServer`, and `serve.mjs` never reads it (checked on c3d88840c: no library reference in serve.mjs). ## Channel proof re-pin `packages/bus/tests/channel-proof.test.mjs` pins both changed files by hash. The test change is two baseline values and a header comment, nothing else: | File | Old | New | |---|---|---| | packages/bus/src/human-cli.mjs | 269c3a66008c0d57… | 9c9af66b98ea0a490c9a880fc81c3c62414a8ee0b5ba6478608771b8c4f87932 | | packages/webui/src/bus.mjs | 934ab2f9b6bde72a… | e69d17d4385a4d190d15373ed1a26e270a5c6906eec9e61fcc2bb6b05849cabb | human.mjs and transport.mjs are unchanged, and so are the entry-path test and the plug-in import ban. No other test pins either file: `git grep` for both old hashes finds only queue.json history and old packets, and the one 64-hex string in webui service.test.mjs is a made-up UID. ## Dewey's other 222 notes None is a few lines in a file this row changes, so all three stay deferred: - N1: a close waits on every entry left in a pass (runtime.mjs). - N2: a held tip still gets its tree read, and a refused read hides the divergence (sync.mjs). - N3: held states log every tick (runtime.mjs). ## Tests - `packages/webui/tests/library-status.test.mjs` (new): each of the six codes maps to its status, and an unknown code is 502. - `packages/bus/tests/library-sync.test.mjs`, a new test. A stand-in bus socket answers every request after 6 s, and the real human-cli.mjs runs two requests in parallel. library.sync gets the answer, and library.status gets `outcome-unknown` at 5 s. It takes about 6 s. - `packages/bus/tests/channel-proof.test.mjs`: the new baselines. Planned mutants on Sage's slot: 1. Drop the human-cli timeout line: the library-sync test fails (sync gets outcome-unknown) and the channel-proof hash fails. 2. Drop one STATUS entry (`library-fetch-failed`): library-status test fails, and so does the channel-proof hash. Both files are hash-pinned, so channel-proof kills any edit to them. Each mutant is also expected to be killed by its behaviour test, and the run lists every failing test so that can be checked.