OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-room commits / b0597f8

0.2.10: fire watchers on autobase 'update' (fixes solo-write finalization lag)
A direct write on a notary (e.g. apply-write on the sole indexer) appended but never finalized: sb.watch -> tick -> sign() is only re-fired from the apply path (_apply's _fireWatchers) and on presence changes, but the autobase's own 'update' event — which fires when the BACKGROUND apply of this node's OWN optimistic write completes — was never wired to the watcher fan-out. So a solo write had no event to trigger its own sign; it finalized only when some other event (co-owner replication, another write) drove an apply. _openBase now does base.on('update', () => _fireWatchers()). sign() is idempotent and the tick coalesces, so extra fires are cheap. Repro/regression: hyper-proto-peer test/finalization-lag.repro.test.js. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b0597f8ddfc67655008121068fcf6f44b86c6e42
by plankatron <fleeky@gmail.com> · 2026-07-21T23:17:47.000Z

Changed files (2) +11 -1

lib/state-base.js +10 -0
……@@ -406,6 +406,16 @@ export class StateBaseV3 {
406406 this.base = new Autobase(this.store, bootstrapKey, baseOpts)
407407 await this.base.ready()
408408
409 // Fire the watcher fan-out on EVERY autobase view advance — crucially including the BACKGROUND
410 // apply-completion of THIS node's OWN optimistic write. Without this, a solo write (e.g. a direct
411 // apply-write on the notary) appends but the sb.watch -> tick -> sign() chain never re-fires: the
412 // apply-path _fireWatchers() only runs on an explicit base.update() drain with new nodes, and the
413 // autoUpdate view advance does not go through _apply. So the write would finalize only when some
414 // OTHER event (a co-owner's replication, another write, a presence change) happens to drive an apply
415 // — the "direct notary write never finalizes" lag. See test/finalization-lag.repro.test.js. sign() is
416 // idempotent (no-ops on an unchanged data root) and the tick coalesces, so extra fires are cheap.
417 this.base.on('update', () => this._fireWatchers())
418
409419 if (this._network) {
410420 if (!this.swarm) {
411421 this.swarm = new Hyperswarm(this._swarmOpts || undefined)
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "atproto-room",
3 "version": "0.2.9",
3 "version": "0.2.10",
44 "description": "Attestation-gated, encrypted multi-writer room engine — StateBase (keet-model admission) + Lease + signer + RepoBase + LabelBase/LabelRoom + serve-membrane. Extracted from hyper-proto-peer; consumed by the atproto peer (repo devices) and the co-authored labeler.",
55 "type": "module",
66 "main": "index.js",