docs(design): scheduled-publish redesign — sortAt + a pending bitmap (PROPOSAL) - #324
Closed
JustMaier wants to merge 1 commit into
Closed
docs(design): scheduled-publish redesign — sortAt + a pending bitmap (PROPOSAL)#324JustMaier wants to merge 1 commit into
JustMaier wants to merge 1 commit into
Conversation
…a pending bitmap
PROPOSAL, not a decision. Justin's, 2026-07-15. Records the design, the failure
classes it targets, what it explicitly does NOT fix, and what must be measured
before committing. Nothing benchmarked.
The design: write Image."sortAt" at SCHEDULE time (future for scheduled posts);
BitDex holds a `pending` bitmap it clears locally on a sweep and the ENGINE
excludes on every query. Consequence: publish sends BitDex nothing at all — no
batch to apply, lose, or verify.
Answers the question "is it all queryOpSet?" — it is not. Two distinct data
families plus a third that has cost as much time:
A) fan-out: one PG row must become N BitDex writes and BitDex works out which
N. queryOpSet ships a QUERY and resolves it against its own index at apply
time, never checking what it matched. Confirmed live: 13 of 20 images stuck
at publishedAt=0, invisible, none self-healed at 5.8h. Also: DocCache
evicted by Post id not image slots; fan-out dedup collapse; Post fan-out
firing pre-insert.
B) deferred/activation: a special state that isn't a bitmap, isn't durable
like the rest, needing an event replayed at an exact instant. The ~49.7k
orphan loss, #313 reschedule-drop, the ~1/320 activation-miss, and the
ENTIRE verifier apparatus built to detect its failures.
C) instrument failures: the verifier's false orphans (no data was ever lost),
and ~10 prose defects found in three review passes that found ZERO defects
in the design.
The shared root, and why the design works: both A and B are a write resolved or
replayed LATER, against state that has MOVED, with NO RECORD of what it was
supposed to affect. Neither has an error path because neither knows what correct
looks like. The cure is general: make it a durable VALUE that can be compared,
not an EVENT that must fire correctly. A value can be diffed and repaired; "did
an op fire correctly three hours ago" has no answer, only consequences.
Explicitly NOT fixed, recorded so it isn't forgotten: queryOpSet survives for
availability, postedToId, and every other post-level field — the redesign
removes one caller, not the pattern. The fan-out moves rather than disappears. A
missed reschedule still publishes early (but becomes auditable).
Stronger variant argued in-doc: DERIVE pending (sortAt > now) from the sort
layers rather than store it — a derived bitmap cannot drift.
Evidence log carries its own caveats: n=3 events, an anecdote not a rate; the
denominator is the only solid number; four hypotheses refuted by one measurement
each; one partial at n=1, unexplained, no rule named off it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Closing — not wanted as a PR. Design doc kept locally instead, per Justin. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Docs-only. A PROPOSAL, not a decision — Justin's, 2026-07-15. Nothing benchmarked, nothing scheduled.
The design
Write
Image."sortAt"at schedule time (future for scheduled posts). BitDex holds apendingbitmap it clears locally on a sweep, and the engine — not the caller — excludes it from every query.The consequence that matters: publish sends BitDex nothing at all. No op crosses the wire at Tf. There is no batch to apply, lose, or verify.
What it answers
It is not all queryOpSet. Two distinct data families, plus a third that has cost as much engineering time:
queryOpSetships a query, resolves it against its own index at apply time, and never checks what it matched. Confirmed live: 13 of 20 images stuck atpublishedAt = 0, invisible, none self-healed at 5.8h — FD #69397's report verbatim. Same family: DocCache evicted by Post id rather than image slots; fan-out dedup collapse; Post fan-out firing pre-insert.The shared root — and why the design works
Both A and B are a write resolved or replayed LATER, against state that has MOVED, with NO RECORD of what it was supposed to affect. Neither has an error path, because neither knows what correct looks like.
A value can be diffed against the source and repaired. "Did an op fire correctly three hours ago?" has no answer — only consequences.
sortAtis a value.publishedAt-via-queryOpSet is an event.What it deletes
Family B entirely — no batch ⇒ no orphan class. The deferred map (durability domain #4) becomes a bitmap.
isPublished. And the whole verifier: #320, #321, PR #323, the barrier,publish_seq,VerifyGate, the ring. All of it verifies a batch that would not exist.What it does NOT fix — stated so it isn't forgotten
queryOpSetsurvives foravailability,postedToId, and every other post-level field. One caller removed, not the pattern.Caveats that travel
n = 3 events. An anecdote, not a rate. The denominator (15,942 images / 3,593 posts, no
LIMIT) is the only solid number. Four hypotheses were refuted by one measurement each, and the one true partial (13/7) is n=1 and unexplained — no rule named off it. The hot-path ANDNOT cost is unmeasured, and unmeasured premises died four times in one evening on exactly this subject.🤖 Generated with Claude Code