Skip to content

fix(onlion): fold at one batch so the read window covers everything waiting - #121

Merged
wefio merged 1 commit into
mainfrom
fix/v1.4-window-covers-pending
Oct 28, 2026
Merged

wefio merged 1 commit into
mainfrom
fix/v1.4-window-covers-pending

Conversation

@wefio

@wefio wefio commented Oct 28, 2026

Copy link
Copy Markdown
Owner

What this fixes

The previous version read the newest pending entries, which fixed the streaming case and left
the mirror image: the window holds eight entries while the standing backlog lived between the
batch and the trigger (16..23 at a trigger of 24), so whichever end the window took, part of it
was invisible until it folded.

Measured on the deployed service, twenty sequential Adds to one user:

version pending after 20 adds markers 0-19 found
window reads the oldest 20 0-7 found, 8-19 missing
window reads the newest 20 0-7 missing, 12/19 found
fold at one batch (this PR) 4 all 20 found

The change

  • FOLD_TRIGGER drops to FOLD_BATCH: folding as soon as a full batch waits keeps pending
    below the read window. It costs no extra partition writes - a fold absorbs exactly one batch,
    so the cadence is one fold per batch of accepts at any trigger above the batch. What it
    removes is the standing tail.
  • MAX_PENDING_READ grows to two batches, because the trigger is not a hard bound: with
    concurrent accepts a few more can arrive before the fold commits, and anything past the
    window is invisible. The cost is one embedding call per entry actually pending.
  • One test adds twenty facts one at a time and requires all twenty to be searchable while the
    log is still live, with the pending count below the window.

Verification

  • npm run verify: 34 PASS.
  • Deployed as dprdf1xm08hi, live revision adfa1f9c, pending_read_limit: 16,
    merge_batch: 8.
  • Live check after deployment: 20 sequential Adds left pending_entries: 4, sqlite_bytes
    1.63 MB (the folds ran), and all twenty markers were found.

…aiting

Reading the newest entries fixed the streaming case and left the mirror image: the window
holds eight entries, the standing backlog lived between the batch and the trigger (16..23 at
a trigger of 24), so whichever end the window took, part of it was invisible until it folded.

The backlog is what has to change, not the end. Folding as soon as one batch is waiting keeps
pending below the window, and it costs no extra partition writes: a fold absorbs exactly one
batch, so the cadence is one fold per batch of accepts at any trigger above the batch. What
the lower trigger removes is the standing tail, not throughput.

`MAX_PENDING_READ` grows to two batches because the trigger is not a hard bound - with
concurrent accepts a few more can arrive before the fold commits, and anything past the
window is invisible. The cost is one embedding call per entry actually pending, normally one
batch and never this bound.

Pinned by a test that adds twenty facts one at a time and requires all twenty to be
searchable with the log still live, plus the pending count below the window.

Verified: npm run verify passes (34 PASS).
@wefio
wefio merged commit dc45452 into main Oct 28, 2026
8 checks passed
@wefio
wefio deleted the fix/v1.4-window-covers-pending branch October 28, 2026 18:06
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