Skip to content

Write the operator quickstart and what an empty list means - #135

Merged
iderex merged 1 commit into
mainfrom
write-the-operator-quickstart
Aug 23, 2026
Merged

Write the operator quickstart and what an empty list means#135
iderex merged 1 commit into
mainfrom
write-the-operator-quickstart

Conversation

@iderex

@iderex iderex commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Closes #55.

Two operator-facing files said installation was not possible yet. The address
answers and is recorded, so both were withholding the one thing an operator comes
for, and the README's stated reason had stopped being true.

The three steps, and where their wording comes from

The field and tab names are quoted from the interface's own strings rather than
from memory:

curl -sS https://raw.githubusercontent.com/jellyfin/jellyfin-web/master/src/strings/en-us.json \
  | python3 -c "import json,sys; d=json.load(sys.stdin); [print(repr(k),'=',repr(d[k])) for k in ('TabDashboard','TabPlugins','TabRepositories','LabelRepositoryName','LabelRepositoryUrl','MessageRepositoryInstallDisclaimer')]"
'TabDashboard' = 'Dashboard'
'TabPlugins' = 'Plugins'
'TabRepositories' = 'Repositories'
'LabelRepositoryName' = 'Repository Name'
'LabelRepositoryUrl' = 'Repository URL'
'MessageRepositoryInstallDisclaimer' = 'WARNING: Installing a third party plugin repository carries risks. It may contain unstable or malicious code, and may change at any time. Only install repositories from authors that you trust.'

Run 2026-08-23. The third-party warning is repeated in the quickstart rather than
skipped past, because it is correct and it is about this repository as much as
any other.

No tab name is given for the step after the repository is added. That label is
not in the strings file above, and naming one from recollection is the class of
claim this tree refuses, so the step says to go back to the plugin list.

The three commands, each run

curl -sS -o /dev/null -w "%{http_code}\n" https://flowfin.dev/manifest.json
200

curl -sS https://flowfin.dev/manifest.json | python3 -m json.tool > /dev/null ; echo "exit=$?"
exit=0

curl -sS https://flowfin.dev/manifest.json \
  | python3 -c "import json,sys; [print(p['name'], v['version'], 'needs', v['targetAbi'], 'or newer') for p in json.load(sys.stdin) for v in p['versions']]"
Requests 0.1.0.0 needs 10.11.0.0 or newer

Run 2026-08-23. The outputs in the README are these, not paraphrases of them.

The third one is the reason the version-mismatch case is worth a section rather
than a sentence: the only entry the catalogue holds today wants 10.11.0.0 or
newer, so every older server sees an empty list and no error, which is the
catalogue working rather than failing.

The printed address is allowed only by the record, and here is that shown

With the recorded entry taken back out, on this branch:

sed -i 's#^var Answered = \[\]string{"https://flowfin.dev/manifest.json"}$#var Answered = []string{}#' internal/address/address.go
go run . gate install-address-is-answered

--- FAIL: TestNoTrackedFilePrintsAnUnansweredInstallAddress (0.31s)
    address_test.go:199: an install address is printed that nobody has read:
        README.md:17: https://flowfin.dev/manifest.json is printed here and is not recorded as answering, so an operator pasting it gets an empty repository and no error
        README.md:54: ... (same rule, same address)
        README.md:63: ... (same rule, same address)
        README.md:73: ... (same rule, same address)
        docs/index.html:31: ... (same rule, same address)

Five sites, all refused. The edit was reverted afterwards and
internal/address/address.go is not in this change:

git diff --name-only origin/main...HEAD
README.md
docs/index.html
internal/keyboard/keyboard_test.go

Why the keyboard expectation moved

The page gains one control, a link to the empty-list commands, and the gate
refused the change until the declared count matched:

--- FAIL: TestTheServedPagesDeclareTheControlsAKeyboardHasToReach (0.00s)
    keyboard_test.go:30: docs/index.html declares 2 control(s), want 1: a "Read it", a "The commands that tell those apart"

That number is the expectation the browser half is measured against, so a page
that grows a control nobody can reach reds rather than passing quietly in both
places. It is now 2.

What was not run, and it is the half that would prove the new control

go run . harness needs-browser was not run for this change. That job runs a
privileged command on its runner, by its own declaration in
.github/workflows/harness.yml, and it is not run on this machine for that
reason. It gates no merge and runs on no pull request.

So the render side of the new link is unproven here. What can be said is a claim
rather than a measurement: it is a plain anchor with an href, in a paragraph,
identical in kind to the "Read it" anchor already on the page that the same check
covers. Whether a real render agrees is what that harness job decides, and it has
not decided it.

The gate

go run . gate

gate examined 14 of 14 legs.
  build                            passed
  test                             passed
  format                           passed
  editorconfig                     passed
  tests-reach-nothing              passed
  no-hardcoded-names               passed
  site-fetches-nothing-outside     passed
  site-links-resolve               passed
  coverage                         passed
  site-declares-its-language       passed
  install-address-is-answered      passed
  colour-stands-off-every-surface  passed
  page-matches-the-token-file      passed
  pr-hygiene                       passed

What this does not do

It does not walk the three steps on a running Jellyfin server. Nothing here has
been installed into one, so the quickstart is checked against the interface's
published strings and against the catalogue's own bytes, and not against the
sequence an operator performs. #54 is the harness that decides that, and it is
open.

Review

No second person has read this. That is stated rather than implied, and the
evidence above stands in place of a second reader: every claim carries the
command that produced it, including the one run to watch the guard go red and the
one that refused the change before the control count was corrected.

Two operator-facing files said installation was not possible yet. The address
answers and is recorded, so both were refusing to tell an operator the one thing
they came for, and the README's reason for saying so had stopped being true.

The quickstart is three steps and says what to expect after them, including that
the single plugin in the catalogue declares itself unfinished. The failure it is
mostly written against is the quiet one: a Jellyfin server shows an empty list
for an address it cannot reach, for one that answers with bytes it cannot parse,
and for a catalogue whose entries all want a newer server, with no error message
in any of the three. Three commands separate them, each with the output it
produced, and they are ordered so that the cheapest and most common answer comes
first.

The delay a release takes to appear is stated in both halves it has: a day for
the catalogue to be rebuilt, and a publication step this project does not
control and gives no figure for. A single number there would promise something
nothing here can keep.

docs/index.html gains a link to the empty-list commands, so the page declares one
control more than it did. internal/keyboard carries the expectation the browser
half is measured against, and it refused the change until the number matched:
a page that grows a control nobody can reach is what that number exists to
catch.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit 1f88020 into main Aug 23, 2026
36 checks passed
@iderex
iderex deleted the write-the-operator-quickstart branch August 23, 2026 03:18
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.

Write the operator quickstart, including what an empty repository means

1 participant