Hold 0116's rule per kind, and the window no listener may lengthen - #261
Merged
iderex merged 1 commit intoAug 31, 2026
Merged
Conversation
0116 decides what a change the server reported does to what is cached: an item the message names as removed or updated is invalidated, every library query result is shortened to zero rather than invalidated, artwork, dimensions and capability answers have no rule, a per-account message reaches only the account it names, and no state of a listener ever lengthens a freshness window. None of that was in the tree. `src/cache/notification.rs` holds the part a comparison of identifiers and a match on a kind settle. The shortening is the half that is otherwise got wrong in the expensive direction. A query result is keyed by a digest over the request, a digest cannot be asked whether the answer under it contained a given item, so invalidating every one of them on a notification empties the tile wall once per the server's batching interval for the whole of a library scan. Shortening serves the entry at once, marks it stale with its age, and lets the screen correct itself. The degradation rule is a type rather than a sentence. `WhatAListenerDoesToAThreshold` has one variant, so a read path that wanted to hold a library list for a day because a connection is up has to add a second one, which is a change to 0116 rather than a line somebody writes while a cache hit rate is being looked at. What that prevents is the failure #116 names: a listener that is connected and silent for a reason nobody noticed, producing a cache that is confidently wrong for as long as the lengthened window lasts. The account test prevents the other one. 0041 keys the cache per account, and a rule reading the identifiers without the account lets one person on a shared device move another person's entries. One answer here is a reading rather than a sentence in 0116, and it says so where it is made: a per-account message leaves a library query result where the table put it, because a position report is a per-account change on 0057's cadence and a rule shortening every query result on each of them would leave the tile wall permanently stale while anything is playing. #116 stays open. Both its conditions drive the fake server - one makes a change on it, the other breaks a connection without closing it cleanly - and nothing in this tree opens a connection, which is #27. Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
iderex
deleted the
the-rule-per-kind-and-the-window-no-listener-lengthens-116
branch
August 31, 2026 10:03
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.
The issue this belongs to
#116. This does not close it, and the reason is at the end.
What changed
src/cache/notification.rsholds the part of 0116 a comparison of identifiersand a match on a kind settle. It is the second of the three ways 0006 says an
entry stops being trusted; the third, the passage of time, is already in
src/cache/freshness.rs.what_a_notification_doesanswers for one entry and one message. An item themessage names as removed or updated is invalidated, because what is held is
wrong rather than old and 0043 answers a later read with
Absent. An item namedonly as added moves nothing. Every library query result is shortened to zero on a
library change whether or not the message named an item, because the entry is
keyed by a digest over the request and a digest cannot be asked whether the
answer under it contained a given item. Artwork bytes, decoded dimensions and
capability answers have no rule under either message. A per-account message
invalidates the item entries it names and reaches nothing keyed under another
account.
WhatAListenerDoesToAThresholdis 0116's degradation rule written as a type. Ithas one variant, and
what_a_listener_does_to_a_thresholdis total overListenerState::all()and answers the same way for all five states, includingthe one anybody would be tempted to reward.
One answer is a reading rather than a sentence in 0116, and it is written as one
with its argument on the function that makes it: a per-account message leaves a
library query result where the table put it.
What failure it prevents
Three, and each is named in #116 or in 0116 as the thing that goes wrong.
A tile wall that empties and refills while a library scan runs. Invalidating
every query result is the more obviously correct reading of "the answer may have
changed", it is what gets written when nobody has decided, and during a scan the
server batches a notification once per its own configured interval, so what a
person watches is the screen emptying repeatedly.
A cache that is confidently wrong for as long as a lengthened window lasts. A
core being told about every change can hold a library list for a day instead of
five minutes and the hit rate improves visibly; a listener that is connected and
silent for a reason nobody noticed then serves that day out of a stale cache, and
silent is exactly what a listener is when something has gone wrong with it.
One person on a shared device moving another person's entries. 0041 keys per
account and the per-account message carries the account it is about, so a rule
that read the identifiers and not the account would cross that key.
None of the three has happened here: there is no listener in this tree to have
got any of them wrong yet, which is the point of deciding before the caller
exists.
Evidence
Every command run at
bdd08fa52efea9a5289fedd1a2050d714ec73161, the head beingpushed.
The legs of the gate this machine can run, each by its own script and each by its
own exit code:
What a guard here refuses, and the proof it bites
A query result is shortened and never invalidated. The violation is the one
line somebody writes when they read "the answer may have changed":
A per-account message reaches only its own account. The violation is the
account test dropped, which is exactly what a rule written from the identifier
list alone looks like:
No state of a listener lengthens a window, and this guard has two layers, so
the violation has to defeat both. The type is the first: with one variant there
is nothing to return that means "kept longer", so the change has to widen the
enum before it can be written. Widened and written, the run refuses it:
A second variant added and never returned reddens nothing, which was run and is
stated here rather than left for a reader to assume: the type refuses the value,
the cases refuse the use, and neither covers the other.
Each violation above was applied to the working tree, run, and reverted. With all
three restored:
What this does not cover
#116's own conditions are untouched and this does not close it. They ask for
a test that makes a change on the fake server and proves a cached read reflects
it, and a test that breaks the mechanism without closing it cleanly. Both drive a
connection, nothing in this tree opens one, and that is #27. The reading already
on the issue about whether the fake server reaches an established upgrade is not
restated in this body and nothing here answers it.
No listener, no reconnection and no delay. Nothing here opens, reads, closes
or counts a connection, and there is no schedule of its own, which is 0116's
decision rather than a gap: 0038 bounds a request's attempts and 0045 is the
recovery schedule for a server that is gone.
No bound as a number. #116 asks that a change be reflected within a stated
bound and 0116 answers that the core cannot state one, because the server's own
batching sits ahead of it on an operator's setting. Nothing here claims a number.
Nothing applies any of this to a cache. The answers are values a read path
will act on, and no read path exists: nothing in this tree fetches bytes out of a
store and hands them anywhere.
The coverage leg was not judged on this machine. Its instrumentation reads
zero lines for every area here, on this branch and on an unmodified checkout of
the default branch alike, so the number is absent rather than low.
.github/workflows/coverage.ymlruns on this pull request and is what judges it.The pinned-surface register carries the new module with its reason.
Three other legs were not run here.
headlessneeds a program this machinedoes not carry (
ip: command not found),thread-detectorneeds a nightlycompiler this tree deliberately does not pin, and
mutationis weekly ratherthan a pull-request leg. None was skipped by editing anything; they were not run.
Who has read it
Nobody but me has read this change. There is no second reader on this board
tonight, and the evidence above stands in place of one rather than the question
being left open.