Skip to content

Serve 0046's cold start out of the cache alone, and name the calls it cannot answer - #264

Merged
iderex merged 1 commit into
mainfrom
what-a-cold-start-serves-and-what-it-does-not-46
Aug 31, 2026
Merged

Serve 0046's cold start out of the cache alone, and name the calls it cannot answer#264
iderex merged 1 commit into
mainfrom
what-a-cold-start-serves-and-what-it-does-not-46

Conversation

@iderex

@iderex iderex commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

The issue this belongs to

#46. This does not close it, and the reason is at the end.

What changed

src/cache/cold_start.rs holds the part of 0046 a match on a kind and a match on
a call settle.

what_a_start_serves is the ordering. It takes how the secret read went and
every path through it is decided by what the cache held, so the four states of
that read include the two that tempt a start path into waiting and a case can
name them. What comes back is 0043's own answer unchanged: a cold start carves no
exception into the freshness table, so a stale entry is stale here too.

is_servable_before_a_session_is_restored is 0046's first table, as a total
function over EntryKind rather than a list, so a sixth kind added to 0006
arrives here as a compile error rather than as an entry silently outside the rule.

before_a_session_is_restored is the second list, which is of calls rather than
of entries: a playback handover, any write toward the server, a read that demands
freshness and a sign-in all need a token, and an ordinary read does not.

WhatAStartServes carries no session state, which is the record's own section on
a full screen not being a signed-in screen.

What failure it prevents

A blank screen on a locked device while a complete answer sits in the store.
0033 makes a device locked at a background start fail the secret read rather than
answer it. A start path that read the secret first then shows nothing at all - on
the one device where the person is also most likely to have no network, which is
the case the cache exists for. 0046 says the natural way to write a start path is
the wrong way round, because restoring a session reads as the first step given
that everything else needs a session.

A demand for freshness answered out of the cache. 0006 fixes that such a read
returns a fresh answer or a named failure and never a stale one. It sits one line
away from the ordinary read in any start path, and collapsing the two is how a
cold start becomes a promise the cache contract refuses.

A screen that looks signed in because it is full. Nothing this module answers
with carries a session state, so a client has nowhere to infer one from.

None of the three has happened here: there is no start path in this tree to have
got any of them wrong, which is the record's own argument for writing the ordering
before the code.

Evidence

Every command run at f2d7a66731819a8a2612d10e99f92884610f9437, the head being
pushed.

cargo build --locked --all-targets
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.74s

cargo test --locked 2>&1 | grep -c '^test .* ok$'
644

cargo test --locked 2>&1 | grep -c '^test result: FAILED'
0

cargo test --locked --lib cache::cold_start 2>&1 | grep -E '^test result'
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 479 filtered out; finished in 0.00s

The legs of the gate this machine can run, each by its own script and each by its
own exit code:

for s in format invariants doc-paths lint test excluded-targets targets; do
  bash .github/$s/$s.sh check >/dev/null 2>&1; echo "$s exit=$?"
done
format exit=0
invariants exit=0
doc-paths exit=0
lint exit=0
test exit=0
excluded-targets exit=0
targets exit=0

cargo clippy --all-targets -- -D warnings -D clippy::all -D clippy::pedantic -D clippy::cargo 2>&1 | grep -cE '^(error|warning)'
0

What a guard here refuses, and the proof it bites

Two violations, each applied to the working tree, run, and reverted.

The cache read is not sequenced behind the secret read. The violation is the
ordering 0046 exists against, written the way a start path writes it:

(in what_a_start_serves)
+    if matches!(the_secret_read, HowTheSecretReadWent::TheStoreCouldNotAnswer) {
+        return WhatAStartServes::TheCacheHasNotAnsweredYet;
+    }

cargo test --locked --lib cache::cold_start 2>&1 | grep -E 'was withheld|^    cache|^test result'
assertion `left == right` failed: a complete answer in the store was withheld while the secret read was TheStoreCouldNotAnswer
    cache::cold_start::tests::a_store_that_could_not_answer_does_not_empty_the_screen
    cache::cold_start::tests::what_is_served_does_not_move_with_how_the_secret_read_went
test result: FAILED. 6 passed; 2 failed; 0 ignored; 0 measured; 479 filtered out

A demand for freshness is not the read beside it. The violation is the two
collapsed into one arm:

-        CallAtStart::AReadOfSomethingCached => WhetherItCanBeAnsweredYet::OutOfTheCache,
+        CallAtStart::AReadOfSomethingCached | CallAtStart::AReadThatDemandsFreshness => {
+            WhetherItCanBeAnsweredYet::OutOfTheCache
+        }

cargo test --locked --lib cache::cold_start 2>&1 | grep -E 'was answered before|^    cache|^test result'
assertion `left == right` failed: a-read-that-demands-freshness was answered before there was a token to answer it with
    cache::cold_start::tests::a_demand_for_freshness_is_not_the_read_beside_it
    cache::cold_start::tests::only_a_read_of_something_cached_is_answerable_before_there_is_a_token
test result: FAILED. 6 passed; 2 failed; 0 ignored; 0 measured; 479 filtered out

With both restored:

cargo test --locked --lib cache::cold_start 2>&1 | grep -E '^test result'
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 479 filtered out; finished in 0.00s

What this does not cover

#46's own condition is untouched and this does not close it. It starts the
core with a populated cache and an unreachable server and proves a library list is
served without any successful network call. Creating a core is #115 and
flowfin_core::Core carries no method for it, so there is nothing here to start.
The reading already on the issue about the two stores being traits with nothing
between them to order is not restated in this body.

No store is read and no session is named. Both stores are traits a client
implements and nothing here holds one, so this says what a start serves and serves
nothing.

No measurement point. 0046 refuses to name a second pair, because 0008 already
opens the core's interval at the first library query after creation and separates
the warm-cache variant this path is. Nothing here is measured, and #62 is where
this path becomes a number.

Nothing here decides who is holding the device. Naming a session is the act
that exposes its cache and that act is the client's. 0041 keeps two accounts on
one device out of each other's entries; it does not and cannot keep one account's
entries from whoever picked the device up, and nothing in this change changes that
in either direction.

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.yml runs 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. headless needs a program this machine
does not carry (ip: command not found), thread-detector needs a nightly
compiler this tree deliberately does not pin, and mutation is weekly rather than
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.

… cannot answer

0046 decides that a cache read is answerable from the moment the core is
created, that the cache read must not be sequenced behind the secret read, that
every kind 0006 caches is servable that early, and that what cannot be served is
a list of calls rather than of entries. None of it was in the tree.
`src/cache/cold_start.rs` holds the part a match on a kind and a match on a call
settle.

The ordering is the sentence the record exists to make refusable, and it is a
case here rather than a paragraph. `what_a_start_serves` takes how the secret
read went and every path through it is decided by what the cache held, so the
four states include the two that tempt a start path into waiting and a case
names them. The one that matters is a device locked at a background start, where
0033 makes the secret read fail rather than answer: a start ordered the other way
shows nothing at all while a complete answer sits in the store, on the one device
where the person is also most likely to have no network.

The second list is of calls, and the pair a start path collapses is a read that
demands freshness beside an ordinary read. 0006 fixes that a demand for freshness
returns a fresh answer or a named failure and never a stale one, so before there
is a token the failure is what it returns, and answering it out of the cache
would be the one place a cold start turned into a promise the cache contract
refuses.

Nothing here carries a session state. A screen that is full because the cache
answered is not a signed-in screen, and a client that wants to know asks for that
on its own rather than inferring it from having received data.

The kind table is a total function rather than a list, so a sixth kind added to
0006 arrives here as a compile error rather than as an entry silently outside the
rule.

#46 stays open. Its condition starts the core with a populated cache and an
unreachable server, creating a core is #115, and nothing in this tree starts one.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex iderex added performance The speed budget and what measures it architecture Shape of the core: boundaries, interfaces, contracts labels Aug 31, 2026
@iderex iderex self-assigned this Aug 31, 2026
@iderex
iderex merged commit 4dec362 into main Aug 31, 2026
24 checks passed
@iderex
iderex deleted the what-a-cold-start-serves-and-what-it-does-not-46 branch August 31, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

architecture Shape of the core: boundaries, interfaces, contracts performance The speed budget and what measures it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant