Skip to content

fix(sync): resolve the device roster once per backfill pass - #470

Merged
th3-br41n merged 1 commit into
mainfrom
fix/10-3c-roster-per-pass
Aug 3, 2026
Merged

fix(sync): resolve the device roster once per backfill pass#470
th3-br41n merged 1 commit into
mainfrom
fix/10-3c-roster-per-pass

Conversation

@th3-br41n

Copy link
Copy Markdown
Contributor

Closes the MEDIUM the 10.3c key-distribution gate raised against its own diff (harness #245).

The cost

fanOutEntityWrapToSiblings re-opened VaultPropertiesStore — a Y.Doc load — on every call, and the pairing backfill calls it once per entity. An N-entity vault paid N properties-doc loads on top of its N × devices HPKE seals, on exactly the pairing gesture the IE-11 long-pass treatment exists to keep responsive. It scaled with vault size.

resolveSiblingRoster() exposes the read; the backfill hoists it out of the loop. The single-entity ongoing producer still reads fresh — that is correct for one entity.

Why the hoist does not land alone

The in-flight guard used ??=, which hands a concurrent caller the running promise. Combined with a per-pass roster that becomes a correctness bug rather than just a swallowed re-run: a device that paired mid-pass would never be a recipient for any entity — not even ones scanned after it joined. Previously the per-entity read papered over this for the tail of the pass.

So a dirty flag now re-runs the pass once when a roster change arrives during one. Cheap, because the fan-out no-ops a recipient that already holds a wrap.

Tests

  • a caller-supplied roster produces the same wire result as a per-entity read (the equivalence that makes hoisting safe)
  • an empty supplied roster wraps for nobody — so the hoist cannot silently fall back to a fresh read, which would make the caching untestable and its cost unbounded

typecheck:packages clean; collab/ 194 passing, wrap-fanout + wrap-backfill 17 passing.

Not in scope

The gate's LOW (the roster is not signature-verified on the read path) stays with LAN-2b, as filed.

🤖 Generated with Claude Code

The 10.3c gate's own MEDIUM finding. `fanOutEntityWrapToSiblings` re-opened
`VaultPropertiesStore` — a Y.Doc load — on every call, and the pairing
backfill calls it once per entity. An N-entity vault therefore paid N
properties-doc loads on top of its N × devices HPKE seals, on exactly the
pairing gesture the IE-11 long-pass treatment exists to keep responsive, and
it scaled with vault size.

`resolveSiblingRoster()` now exposes the read, and the backfill hoists it out
of the loop. The single-entity ongoing producer still reads fresh, which is
what it wants.

Hoisting alone would have opened a hole, so it does not land alone: the
in-flight guard used `??=`, which hands a concurrent caller the running
promise. With a per-pass roster, a device that paired mid-pass would never be
a recipient for ANY entity — not even ones scanned after it joined. A dirty
flag now re-runs the pass once when a roster change arrives during one, which
is cheap because the fan-out no-ops a recipient that already has a wrap.

Two tests pin the contract: a caller-supplied roster produces the same wire
result as a per-entity read, and an empty supplied roster wraps for nobody
(so the hoist cannot silently fall back to a fresh read).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@th3-br41n
th3-br41n merged commit 87d61d0 into main Aug 3, 2026
3 checks passed
@th3-br41n
th3-br41n deleted the fix/10-3c-roster-per-pass branch August 3, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant