Skip to content

room-share: a legacy room's read recomputes the clamp target per line, so a long log reads in quadratic time #2766

Closed

Description

@HugoXK

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.

Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: cf0f9c9d48a042a1a6a760635f30b2c3
Branch: dev/1-room-floor-once
Base: f2ef4df
At: 2026-11-10T01:08:50Z

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.

Written-by: FlyBot Lead
Bot: FlyBot Dev-1

Reading a room whose saved log predates seq calls the join-floor clamp's target computation once per line, so the read is quadratic in the log's length; the same read on a room that has a counter is linear.

Where

Introduced by the clamp fix in #2759 (core/src/host/room-membership.js at its tip, 8eead216f75d92e51c0e8b01c9bb541de3ed9e0d):

  • linesFrom (:499) is (room.log ?? []).filter(line => (line.seq ?? 0) >= floorOf(room, actor)) — floorOf runs once per line.
  • floorOf (:477-498) calls clampTargetOf (:473-476) before its healthy-floor early return, and for a room without seq that is (room.log ?? []).reduce(...) over the whole log.

So a legacy room with n lines does n reduces of n lines. Rooms that carry seq are unaffected (clampTargetOf returns room.seq in O(1)), and ensureLog adds a seq on the next append, so the shape is the window before a legacy room's first new line — a long-standing room read in that window is slow.

Reproduction and measurements

Deterministic counter rather than a wall clock: wrap room.log in class CountingLog extends Array { reduce(...) } and assert the reduce count for one read.

Red first on the #2759 tip tree (193036664d…, tree 9690e6bc81…), source untouched:

# legacy n=20000: 29987ms, reduce calls=20000
not ok 1 - a legacy room read computes its clamp target once, not once per line
    the clamp target is computed once per read, saw 20000
# modern n=20000: 17ms, reduce calls=0
ok 2 - a room with a counter reads the same window without a per-line reduce
# tests 2 / # pass 1 / # fail 1

FlyBot Test measured the same shape independently (floor clamp probe on the #2759 tip): 5,000 lines 185 ms, 20,000 lines 5,498 ms; a one-line hoist made it 4.4 ms.

After the fix on the same tree (one call site, +6/−1):

# legacy n=20000: 8ms, reduce calls=1
# modern n=20000: 4ms, reduce calls=0
# tests 2 / # pass 2 / # fail 0

No regression: core/test/room-membership.test.js + core/test/room-context.test.js on the same tree # tests 47 / # pass 47 / # fail 0 (including the 26 #2754 cases).

Expected

linesFrom computes the floor once per read and filters against the value:

const linesFrom = (room, actor) => {
  const floor = floorOf(room, actor)          // one clamp target per read
  return (room.log ?? []).filter(line => (line.seq ?? 0) >= floor)
}

Behaviour must not change: the memo, the clamp, the warn-once-per-room rule and every visible window stay exactly as the #2759 tests assert. callsIn, presentRoom and roomHistory all go through linesFrom, so they are covered by the same change; do not add a second copy of the filter.

Red-first cases to keep: the reduce count for a legacy room is 1 (not n) for one read, a modern room stays at 0, and the two #2754 windows (floor above seq, and the catch-up past it) read identically to the tip.

Sequencing (important)

This edits a function that #2759 introduces, so the PR must land after #2759: open it from live main once #2759 has merged, or from a rebase onto that merge. Do not stack this branch on the unmerged #2759 tip — a PR carrying #2759's commits would be a duplicate of it.

Dedupe

Checked live main f2ef4dfaccedd40315bd585474d0902118dc0ba8 and the open/closed issue list: the clamp itself is #2754 (issue) / #2759 (its PR) and is not merged yet; #2613 (closed) stopped writing the host counter as a guest room's floor; nothing open or closed covers the per-line cost of that clamp. This is a follow-up to #2754, not a duplicate of it.

Risk tier: T2 (read path of room history; no stored value changes).

Activity

  1. HugoXK commented on Nov 10, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: cf0f9c9d48a042a1a6a760635f30b2c3
    Reason: merged as 74d08c5 on main 07:35:22Z; issue closed completed
    At: 2026-11-10T07:37:53Z

  2. added a commit that references this issue on Nov 10, 2026
    74d08c5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions