Concurrency review, September 2026
The work that came out of @danshearer's concurrency review of the forge layer, at trunk 4910c69016e5: https://markdownpastebin.com/?id=ba05d64fb32940588fab39b1827db23e
Every item below is a ticket. Each ticket carries what happens, what should happen, where in the code, and the fix shape. The lists are in priority order.
Single node
- 54dc6a4148 Chat presence: a tab opening or closing during a presence change crashes the whole server — Critical, Immediate
- 508fd44ab0 Live-update streams leak one goroutine per closed tab — Severe, High
- 61cd995161 No HTTP timeouts and no limit on anonymous chat streams — Severe, High
- c21e27c2d6 Any error reading the ingest cursor triggers a full reindex that empties the index first — Severe, High
- 7ae62edbcc SQLite pragmas and busy_timeout reach one pooled connection; concurrent writes fail busy — Important, High
- fe5069ef76 The login rate limiter trusts X-Forwarded-For — Important, High
- e60889c0d7 Landing accept: two accepts both proceed, and a push between check and merge lands an unchecked tip — Severe, Medium
- 3d2980cf29 Check-then-write outside a transaction: invite redemption, last-admin/owner checks, ticket promotion — Important, Medium
- 8e6ecbb15c Store writes that bypass the lease guard: attachments, settings, config import, CI pipeline save — Important, Medium
- 86a22fabef A failed reindex leaves the census goroutine and its zit frames process behind — Important, Medium
- b880cb13c8 A node that falls behind the stream's one-hour window is never detected — Important, Medium
- 2af687e64f A CI result can be lost: run marked complete before its tag is written — Important, Medium
- 4a9f45bab5 CI webhook events carry no hash, so their ids collide — Minor, Medium
- 83b111e004 HandlerWith sets package-level variables that request goroutines read — Minor, Medium
- 128ffbf478 No graceful shutdown; imgproxy lock map never pruned — Minor, Medium
Several nodes
Designed in RFC 0001; needed before a second node runs. All Low priority until then.
- a598314e3f Node identity comes from --addr, so two nodes can share a lease owner name and a consumer
- 935f72e648 The lease is checked once before a zit write; a long write can overlap the next holder's; the grace period depends on process history
- 1d09827992 Background jobs run on every node: CI dispatch and polling, mirror pulls, auto-accept, the chat bridge, event publishing
- 18ca45f20e The shared OLTP file assumes one host (design)
- 4116d2f4a2 Write routing to the lease holder is designed but not built (design)
- 8af7bf74ca The private-repository list is cached per process
Follow-ups found while landing the work
Each is a ticket of its own.
- 3a2d821f59 web: TestStreamPatchesRailOnActivity fails under -race on clean trunk — Minor
- 55d25c1639 ingest: a failed rebuild never resumes the derived maintenance it suspended — Important
- 955c5cee5a ingest: a stale reset message after a rebuild could clear the fresh index — Minor, unreproduced
- 21e312b2f9 ingest: rebuilds after long downtime all start at once — Minor
Also found: the sync gate read protocol cards out of pushed file contents, so a push carrying a file with a line like login TEXT NOT NULL, was refused as user TEXT. Fixed by framing payloads card by card (landing push-gate-frames-cards).
Not ticketed
The review names about 25 lower-severity findings but lists only three, all filed above. Two fixes need zit's cooperation and say so in their tickets: an expected-tip check on merge (landing accept) and a pre-commit lease check for long writes.