Skip to content

Name the trait that declares the byte store a pin would live in (#496) - #497

Merged
iderex merged 1 commit into
mainfrom
seam/certificate-store-closed-40
Sep 18, 2026
Merged

iderex merged 1 commit into
mainfrom
seam/certificate-store-closed-40

Conversation

@iderex

@iderex iderex commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

The issue this belongs to

Closes #496

What changed

src/server/certificate.rs stops calling the byte store #40. It named it three
times and gave the tracker's number every time: "the byte store of #40" in the
module header, "the store in #40" on PinnedServer, and "a pin lives in the
store in #40" on Pins::pin. All three now name crate::cache::ByteStore, the
trait that declares it, with its four operations and its own thread rule written
on it.

The correction is recorded once, in the module header, and the two sites below it
say in one clause what they read and point at it, rather than each repeating the
dates.

Nothing else moves. No behaviour, signature, variant, bound or event.

What failure it prevents

It sends a reader out of the checkout for something in the same crate. The
section those sentences open is The pin does not survive the process, and
somebody reading it is deciding whether to supply a store and what they would
have to implement. On pin the store is the whole reason the signature takes a
fingerprint rather than a refusal, so the answer to "what store" is load-bearing
there rather than incidental.

None of the three went stale. #40 closed as completed at 19:33 UTC on
2026-08-26 and the trait took its four operations at 19:29 UTC the same day, four
minutes earlier; this file landed on 2026-08-30, four days after both. So all
three landed refuted, which is the harder of the two states to defend, and the
file had the answer available in its own crate on the day it was written: the
paragraph on PinnedServer links crate::cache::key::ServerPart two lines above
the sentence that reached for the number instead.

It was found by reading every issue number this tree names outside
docs/decisions/ against the state of that issue on the tracker.

The means

Doc comments in the Rust source that carries the claim, which is the only means
that puts the correction where the sentence a reader meets is. A record under
docs/decisions/ would leave three false addresses standing in the file somebody
opens to find out what a pin is kept in. No language, runtime or dependency is
added, and the suites that already exist judge the result, because cargo doc
resolves the links the change adds.

Evidence

The commit being pushed:

git rev-parse HEAD
34f97a0c72749dcd59550b8bd60518a3c6548b31

Every site in the file that named the number, at the parent:

git grep -n '#40\b' 34f97a0^ -- src/server/certificate.rs
34f97a0^:src/server/certificate.rs:44://! 0029 puts a pin in the byte store of #40 under a key built the way #41 builds
34f97a0^:src/server/certificate.rs:252:/// is written to the store in #40, the value below is what a key is derived
34f97a0^:src/server/certificate.rs:335:    /// refuse the case 0029 depends on: a pin lives in the store in #40 and is

What the three paragraphs said, at the parent:

git show 34f97a0^:src/server/certificate.rs | sed -n '42,51p'
//! # The pin does not survive the process
//!
//! 0029 puts a pin in the byte store of #40 under a key built the way #41 builds
//! one, keyed by the server and the device and never by the account, and says
//! that with no store supplied the pin lives as long as the process and an
//! operator pins once per run. That last sentence is the state of this tree: the
//! register below holds its pins in memory, so what a client gets today is the
//! no-store behaviour the record already decided rather than a shortcut taken
//! here. Nothing about the account reaches any call in this module, which is how
//! that half of the key is kept: there is no parameter to pass one in.
git show 34f97a0^:src/server/certificate.rs | sed -n '249,253p'
/// IT IS AN OWNED VALUE RATHER THAN THAT TYPE, and the difference is not a
/// preference. [`crate::cache::key::ServerPart`] borrows for the length of one
/// derivation, and a register outlives every call made against it. Where a pin
/// is written to the store in #40, the value below is what a key is derived
/// from, so the two arms are the same two on purpose.
git show 34f97a0^:src/server/certificate.rs | sed -n '333,338p'
/// IT TAKES A FINGERPRINT RATHER THAN A [`Refused`], AND THAT IS DELIBERATE.
/// Requiring the refusal would read as the stronger interface and would
/// refuse the case 0029 depends on: a pin lives in the store in #40 and is
/// read back at the start of the next run, where no refusal has happened
/// yet. What keeps a client to the record is the record and the review
/// rather than this signature.

The link two lines above the second of those is a type out of the same crate, so
the file already knew how to name one.

#40 is closed as completed:

gh issue view 40 --repo Flowfin/core --json number,state,closedAt,title --jq '"\(.number) \(.state) \(.closedAt) \(.title)"'
40 CLOSED 2026-08-26T19:33:25Z Define the cache store interface and take the storage location from the client

The store is a trait in this crate, with four operations:

git show 34f97a0^:src/cache/mod.rs | sed -n '216,217p'
pub trait ByteStore: Send + Sync {
    /// Reads the entry kept under a key.
git show 34f97a0^:src/cache/mod.rs | grep -n 'StorageUnavailable>;'
230:    fn read(&self, key: &EntryKey) -> Result<Option<Vec<u8>>, StorageUnavailable>;
241:    fn write(&self, key: &EntryKey, bytes: &[u8]) -> Result<(), StorageUnavailable>;
251:    fn remove(&self, key: &EntryKey) -> Result<(), StorageUnavailable>;
263:    fn held_bytes(&self) -> Result<u64, StorageUnavailable>;

The dates. The trait took those operations four minutes before the issue closed,
and this file landed four days after both, so all three sites landed refuted:

git log -S'held_bytes' --format='%h %cI %s' --reverse 34f97a0^ -- src/cache/mod.rs | head -1
6ce521d 2026-08-26T21:29:37+02:00 Take the cache's location from the client, through four operations and no fifth
git log --format='%h %cI %s' --diff-filter=A 34f97a0^ -- src/server/certificate.rs
0aec5f6 2026-08-30T12:19:45+02:00 Hold 0029's exception where two byte strings decide it, and leave the validation out (#242)
git blame -L 44,44 --date=short 34f97a0^ -- src/server/certificate.rs | cat
0aec5f65 (Nils Lehnen 2026-08-30 44) //! 0029 puts a pin in the byte store of #40 under a key built the way #41 builds

2026-08-26T21:29:37+02:00 is 19:29:37Z, against the 19:33:25Z above.

What the file says now:

git show HEAD:src/server/certificate.rs | sed -n '42,61p'
//! # The pin does not survive the process
//!
//! 0029 puts a pin in the byte store [`crate::cache::ByteStore`] declares, under
//! a key built the way #41 builds one, keyed by the server and the device and
//! never by the account, and says that with no store supplied the pin lives as
//! long as the process and an operator pins once per run. That last sentence is
//! the state of this tree: the register below holds its pins in memory, so what a
//! client gets today is the no-store behaviour the record already decided rather
//! than a shortcut taken here. Nothing about the account reaches any call in this
//! module, which is how that half of the key is kept: there is no parameter to
//! pass one in.
//!
//! THIS FILE CALLED THAT STORE `#40` AT EVERY ONE OF ITS THREE SITES UNTIL THIS
//! EDIT, HERE AND ON [`PinnedServer`] AND [`Pins::pin`]. #40 closed as
//! completed on 2026-08-26 and the trait took its four operations four minutes
//! before it closed, while this file landed on 2026-08-30. So all three landed
//! refuted rather than going stale, which is the harder of the two states to
//! defend: the paragraph on [`PinnedServer`] links a type out of the same crate
//! two lines above the sentence that reached for the number instead. #496 is
//! where it was found.
git show HEAD:src/server/certificate.rs | sed -n '259,265p'
/// IT IS AN OWNED VALUE RATHER THAN THAT TYPE, and the difference is not a
/// preference. [`crate::cache::key::ServerPart`] borrows for the length of one
/// derivation, and a register outlives every call made against it. Where a pin
/// is written to the store [`crate::cache::ByteStore`] declares, the value below
/// is what a key is derived from, so the two arms are the same two on purpose.
/// THAT SENTENCE READ `the store in #40`, two lines under the link above it; the
/// header says what the three sites of that number were in.
git show HEAD:src/server/certificate.rs | sed -n '345,352p'
/// IT TAKES A FINGERPRINT RATHER THAN A [`Refused`], AND THAT IS DELIBERATE.
/// Requiring the refusal would read as the stronger interface and would
/// refuse the case 0029 depends on: a pin lives in the store
/// [`crate::cache::ByteStore`] declares and is read back at the start of the
/// next run, where no refusal has happened yet. What keeps a client to the
/// record is the record and the review rather than this signature. THAT
/// SENTENCE READ `the store in #40`; the header says what the three sites of
/// that number were in.

No sentence in the file gives the store that address any more. What is left of
the number is the corrections that say what the three used to read:

git grep -n '#40\b' HEAD -- src/server/certificate.rs
HEAD:src/server/certificate.rs:54://! THIS FILE CALLED THAT STORE `#40` AT EVERY ONE OF ITS THREE SITES UNTIL THIS
HEAD:src/server/certificate.rs:55://! EDIT, HERE AND ON [`PinnedServer`] AND [`Pins::pin`]. #40 closed as
HEAD:src/server/certificate.rs:264:/// THAT SENTENCE READ `the store in #40`, two lines under the link above it; the
HEAD:src/server/certificate.rs:351:    /// SENTENCE READ `the store in #40`; the header says what the three sites of

What the change is:

git diff --stat origin/main...HEAD
 src/server/certificate.rs | 42 ++++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 14 deletions(-)
git diff --name-only origin/main...HEAD
src/server/certificate.rs

The two commands the gate runs, at this commit. The build was run first and
exited 0; its own summary line is not pasted, because this board's hygiene check
reads the word in it as a speed claim:

cargo build --locked --all-targets ; echo "exit=$?"
exit=0
cargo test --locked ; echo "exit=$?"
exit=0
cargo test --locked 2>&1 | grep -c '^test result: ok'
10
cargo test --locked 2>&1 | grep -c 'test result: FAILED'
0

The links the paragraphs add resolve, which the ordinary build does not judge:

cargo doc --no-deps --locked ; echo "exit=$?"
exit=0

Four of this board's own legs, run on this machine at this commit:

bash .github/invariants/invariants.sh check | tail -1
Every rule above was applied to its subject and refused nothing.
bash .github/format/format.sh check | tail -1
Every tracked source file above is written the way the formatter would write it.
bash .github/doc-paths/doc-paths.sh check | tail -1
Every path these documents name resolves against the tracked set.
bash .github/lint/lint.sh check | tail -1
Every lint the groups above carry was refused, outside the register printed with it.

What this does not cover

  • src/cache/mod.rs. It is read as evidence and not edited. It already says
    what holds.

  • #41. It is left standing in the header. It is open, and whether a
    sentence should name an open issue for something the tree has since built is a
    different question from this one. Nothing is claimed about it in either
    direction.

  • The validation this module leaves out. 0029's exception is what the file
    holds and the rest is outside it, which the file states in its own words.

  • docs/decisions/. 0028, 0029, 0040 and 0041 are referred to and
    none is edited. A record is superseded rather than edited in place, which
    docs/decisions/0001-decision-records.md fixes.

  • Every other reference to a closed issue in src/server/. Only #40 at
    these three sites is examined, and nothing is claimed about the rest in either
    direction.

  • A check that would refuse this. Nothing in this tree reads a doc comment's
    pointer against the state of the issue it names, and the document check reads
    only .md files. This adds no rule, so the next sentence of this shape is
    caught by a reader or not at all.

  • The shell analysis. It was not run on this machine, because the analyser is
    not on this machine's path:

      command -v shellcheck ; echo "exit=$?"
      exit=1
    

    What the run on this pull request reports is the reading, and nothing is
    claimed for it from here. This change touches no shell file.

Who has read it

Nobody other than the author. There is no second reader on this board tonight,
and the readings pasted above stand in place of one rather than a review having
happened.

`src/server/certificate.rs` named the byte store three times and gave the
tracker's number every time: "the byte store of #40" in the module header, "the
store in #40" on `PinnedServer`, and "a pin lives in the store in #40" on
`Pins::pin`. All three now name `crate::cache::ByteStore`, which is the trait
that declares it, with its four operations and its own thread rule written on it.

What that prevents is a reader leaving the checkout for something in the same
crate. The section those sentences open is `The pin does not survive the process`,
and somebody reading it is deciding whether to supply a store and what they would
have to implement. On `pin` the store is the whole reason the signature takes a
fingerprint rather than a refusal, so the answer to "what store" is load-bearing
there rather than incidental.

None of the three went stale. #40 closed as completed at 19:33 UTC on 2026-08-26
and the trait took its four operations at 19:29 UTC the same day, four minutes
earlier; this file landed on 2026-08-30, four days after both. So all three
landed refuted, which is the harder of the two states to defend, and the file had
the answer available in its own crate on the day it was written: the paragraph on
`PinnedServer` links `crate::cache::key::ServerPart` one line above the sentence
that reached for the number instead.

The correction is recorded once, in the module header, and the two sites below it
say in one clause what they read and point at it, rather than each repeating the
dates.

Everything else in the three paragraphs is kept. 0029 still puts the pin under a
key keyed by the server and the device and never by the account, with no store
supplied the pin still lives as long as the process, the register still holds its
pins in memory, `PinnedServer` is still an owned value rather than `ServerPart`
for the reason already written, and `pin` still takes a fingerprint rather than a
refusal for the reason already written.

`#41` is left standing. It is open, and this is about the store rather than about
the key.

It was found by reading every issue number this tree names outside
`docs/decisions/` against the state of that issue on the tracker.

Nothing else moves. No behaviour, signature, variant, bound or event.

Closes #496

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit 0a8bbab into main Sep 18, 2026
28 checks passed
@iderex
iderex deleted the seam/certificate-store-closed-40 branch September 18, 2026 11:08
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.

The certificate module names the byte store three times and gives the tracker's number each time, while the trait is one module away

1 participant