Skip to content

Latest commit

 

History

History
229 lines (180 loc) · 12.6 KB

File metadata and controls

229 lines (180 loc) · 12.6 KB

core

Every Flowfin client needs the same things and none of them should write those twice: talking to a Jellyfin server, holding a session, caching what was fetched, decoding artwork, tracking playback position, and measuring whether the speed budget was met. Eleven clients written independently drift in what they cache, in when they give up on a slow server, and in what they call fast. The speed budget is written as numbers a build can miss, and a number nothing measures is a wish, so this is where those numbers are instrumented. What shared means technically is decided: one Rust library reaching each client through a foreign function interface generated per platform, recorded with its costs in 0011. The core draws nothing: a core that knows about widgets stops being shared the first time two platforms disagree about a list.

Planning happens on the issue tracker first. Every decision that shapes the architecture is written down there with its reasons before the code that depends on it exists.

Building it

A fresh clone needs a Rust toolchain and a network. cargo, the formatter and the analyser all arrive with the toolchain, and what the manifest declares is fetched before the first build compiles.

THIS PARAGRAPH SAID THERE WAS NOTHING TO FETCH AND THAT THE MANIFEST DECLARED NONE. Both stopped being true when the cache key derivation landed: 0041 requires a cryptographic digest, 0011 measures that the toolchain offers none, and 0103 is the rule that admitted the first entry.

THE COUNT THAT REPLACED THE NONE WENT STALE ON THE NEXT ENTRY, WHICH IS WHY THERE IS NO NUMBER HERE NOW. It said one. A second entry arrived on 2026-09-04 with 0292, which decides the means the core speaks HTTP with and had no reason to open this paragraph, and the sentence above went on saying one until somebody read it against the manifest. A number in this file is read by nothing that would have said so, so the count is gone rather than corrected a second time. What is there, and what it reaches, is read rather than written here:

cargo tree -e normal

That record is still what may ever be added, and every entry carries the clause that admitted it and what would retire it beside it in Cargo.toml. The version is pinned in rust-toolchain.toml, which the toolchain manager reads by itself, so a fresh clone gets the right compiler without being told to install one. A compiler that arrived some other way is told which version this tree expects, by number, rather than meeting a compile error.

Two commands, and they are the two the gate runs rather than variants of them:

cargo build --locked --all-targets
cargo test --locked

--locked is there in both so that a build which would rewrite Cargo.lock fails instead of proceeding quietly. --all-targets is there so that the first command builds the tests as well as the library.

THIS PARAGRAPH SAID THAT MADE IT A BUILD OF EVERYTHING RATHER THAN OF HALF OF IT, AND IT IS NOT. --all-targets selects the test targets carrying test = true, so the two targets Cargo.toml declares with test = false are not compiled by it, and a file in either of them that stops compiling leaves this command green. Measured rather than reasoned about:

printf '\nthis is not rust and will not compile;\n' >> tests/needs_a_real_server_or_real_hardware.rs
cargo build --locked --all-targets ; echo "exit=$?"
exit=0
cargo build --locked --test needs_a_real_server_or_real_hardware ; echo "exit=$?"
exit=101

Both are compiled anyway, by the second step of the build check, which derives the excluded set from Cargo.toml and builds each one without running it. One of the two is also run, by .github/workflows/thread-detector.yml. So the paragraph above is about what that command reaches rather than about what is left uncovered:

bash .github/excluded-targets/excluded-targets.sh check | tail -1
Every target the ordinary command leaves out compiles.

How the tree is arranged

One directory under src/ per thing 0003 says the core owns, so that the boundary is visible in the tree and not only in a document: src/server/, src/session/, src/cache/, src/artwork/, src/playback/ and src/measurement/.

Every other directory under src/ is not a concern from that record, and each one says so in its own first paragraph with the reason it sits beside the six rather than inside one of them. Which directories those are is read out of the tree rather than counted here:

git grep -l 'not one of the six' -- src/

A reader who wants the reason opens the file the command names, where the sentence and the reason are in the same paragraph. Naming them here instead put one count in this file and a second one in src/lib.rs, and both of them were wrong the moment a directory landed without either paragraph being opened.

What each type is, and the statement about which thread a client may call it from, is written where a reader meets the type; tests/thread_statements.rs is what refuses a change that breaks one of those statements. What each directory holds is read rather than listed here, because a list of what has landed is wrong on the next landing:

git ls-tree --name-only origin/main src/

THIS PARAGRAPH COUNTED TWO DIRECTORIES AND SAID THERE WAS NO BEHAVIOUR IN ANY OF THEM. It was written when the tree held none; src/lib.rs carries the correction for the sentence it made about the same thing, and this file was not brought into step with it. Both errors ran in the direction that makes the tree look emptier than it is, in the first file anybody reads about this repository.

THE REPAIR THAT REPLACED TWO WITH THREE WENT STALE THE FOLLOWING WEEK, WHICH IS WHY THERE IS NO NUMBER HERE NOW. That repair landed on 2026-08-29 and src/lifecycle/ arrived on 2026-09-02, in a change about the core's own lifetime that had no reason to open this paragraph, and the count stood at three until somebody counted the tree by hand. A number in this file is read by nothing that would have said so, so the count is gone rather than corrected a second time.

What the gate builds for, and what nothing here covers

Read this before assuming a green tick covers the platform you are writing a client for.

The library is compiled on every pull request for every target triple a client links it on, which is 0113's set. The set is data rather than prose, so it is read rather than quoted:

grep -v '^#' .github/targets/targets | grep .

Each line carries the reason that platform is there, and a line carrying a triple and no reason is refused by the check itself. Why the set is shaped that way, and why the whole leg reports under one check-run name instead of one per platform, is 0113.

THIS PARAGRAPH RESTATED THAT RECORD'S SHAPE RULE AND LEFT OUT THE EXCEPTION THE RECORD STATES IN THE PARAGRAPH AFTER IT. It said this gate compiles one triple per client platform family, which reads as one architecture each for Android, iOS, tvOS, macOS, Windows and Linux, and the register holds seven entries. The one that exceeds it is the 32-bit Android ABI, which is the only 32-bit target in the set and the one 0113 says to keep if the set is ever cut, so this file made the narrowest part of what the leg reaches look absent - while the paragraph below it already told a family that has one entry from a family that does not. The shape belongs to that record and the count to the register, and a second declaration of either here is what went stale.

What that leg proves is that the core compiles, and nothing else. Not one line of the suite runs on any of those triples. The suite runs on the runner's own host and nowhere else, which is 0011's sentence that the core's own tests test the library rather than the binding.

Four things no run here touches, named rather than left as silence. A platform outside that register, including a television running webOS or Tizen and a desktop on Windows on ARM. The second architecture of a family that has one entry, so macOS on Intel, Linux on ARM and 32-bit Windows are not compiled. The binding layer, which does not exist in this tree, so a green run says nothing about the interface a client actually calls. And the optimised build, since each triple is compiled once, unoptimised.

One more, from a different leg. The thread detector reaches neither the Windows nor the Android target, so a race that appears only on one of those is outside every run this repository makes. Compiling for both here is not the detector reaching either.

What this core sends, and to whom

Nothing, other than to the server an operator configured. There is no telemetry, no analytics and no crash reporting here: no data about a person, a device or a failure leaves for anybody but that server, and there is no setting that turns such a route on, because there is no route to turn on.

That is the position in 0068 and it is checked rather than promised. The invariants check refuses a telemetry, analytics or crash-reporting package in the resolved dependency graph, which is the way one of them usually arrives - as a dependency rather than as a decision, so that the decision never gets made. The refused names are data rather than code:

git grep -A1 '^id: no-reporting-dependency' -- .github/invariants/rules

Two bounds on that, stated rather than left to be discovered. The check is a name list and not a purpose test, so a reporter published under a name nobody has written there is not refused by it. And it reads the dependency graph, so it cannot see a few lines written directly in this tree that kept something and sent it; what stands against that is no-network-outside-the-transport in the same register, which refuses a socket opened anywhere in src/ outside the one transport, and the review.

Sending a crash report by hand

The position is that nothing is sent automatically, not that nothing may ever be sent. If you want me to see a crash, open an issue with it. Strip it first: the server address, the account name, the token, the device identity, and any title or identifier out of a library are the fields 0068 lists as personal, and an issue here is public from the moment it is submitted.

Where the crash is a security problem, SECURITY.md is the route instead, and it says plainly whether that route is open today.

There is no private destination for an ordinary crash report. Entry 5 of #1 decided on 2026-09-04 that the reporting channel is GitHub and nothing else, with no mailbox named on this board or on any other, and #1 closed as completed the day after. So a public issue with the fields above removed is the whole of the by-hand route for a crash, and that is the decided arrangement rather than a placeholder waiting on one.

THIS PARAGRAPH SAID THE ADDRESS THIS REPOSITORY PUBLISHES WAS UNDECIDED, FOR A VULNERABILITY AND FOR ANYTHING ELSE, AND BOTH HALVES HAD MOVED. The vulnerability half is named in two files at the root of this tree, SECURITY.md for a vulnerability and CODE_OF_CONDUCT.md for a conduct report, and both point at the same private form; the sentence above this one already sends a reader to the first of them. The rest was answered by the entry itself. What has not moved is the sentence this paragraph opens with, and the answer is what makes it permanent rather than provisional.

See NOTICE.md for the intended-use notice.

See SECURITY.md for how to report a security problem, what this repository treats as one, and what a reporter gets back.

License

MIT OR Apache-2.0, at your choice, copyright 2026 Nils Lehnen.

The two texts are in LICENSE-MIT and LICENSE-APACHE. Either one on its own is enough; which of them you take is yours to pick.

This repository published under AGPL-3.0-or-later until 2026-09-05. A copy received under those terms keeps them, and what changed on that day is the terms the core is offered on from it. The answer that stands, the reason given for it, and the dependency set that follows from it are in 0303. The licence the core is offered under.