Skip to content

Name a release by its version, so a per-line tag is not read as staleness - #168

Merged
iderex merged 1 commit into
mainfrom
work/af21-freshness-line-tags
Sep 5, 2026
Merged

iderex merged 1 commit into
mainfrom
work/af21-freshness-line-tags

Conversation

@iderex

@iderex iderex commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Closes nothing on its own. #165 is cleared by a later scheduled run of .github/workflows/freshness.yml that ends in success, and by nothing else, so this change is what should make that run green rather than the thing that clears the key.

What is wrong

internal/freshness asks whether the newest finished release of each declared plugin is listed under each target line the catalogue carries for it, and it asked that question about the whole release tag.

The requests declaration now admits a per-server-line tag segment, from the one-version-many-lines convention:

$ git show origin/main:sources/requests.json | grep stable_tags
    "stable_tags": "^v?[0-9]+\\.[0-9]+\\.[0-9]+(\\.[0-9]+)?(-jf[0-9]+)?(-stable)?$",

So one version is released once per live line, each release under its own tag:

$ gh api repos/Flowfin/jellyfin-plugin-requests/releases --jq '.[] | "\(.tag_name)\tpublished=\(.published_at)"'
0.3.0.0-stable	published=2026-09-03T10:26:17Z
0.3.0.0-jf12-stable	published=2026-09-03T10:26:30Z
0.2.0.0-stable	published=2026-08-27T06:51:59Z
0.1.0.0-stable	published=2026-08-08T09:39:39Z

and the published catalogue carries each of them on the line it was cut for, which is correct and current:

$ curl -sS https://flowfin.dev/manifest.json > live.json
$ python -c "import json; [print(v['version'], v['targetAbi'], v['sourceUrl'].rsplit('/',2)[1]) for p in json.load(open('live.json')) if p['name']=='Requests' for v in p['versions']]"
0.3.0.0 12.0.0.0 0.3.0.0-jf12-stable
0.3.0.0 10.11.0.0 0.3.0.0-stable
0.2.0.0 10.11.0.0 0.2.0.0-stable
0.1.0.0 10.11.0.0 0.1.0.0-stable

Run 2026-09-05. Comparing whole tags then asks the 12.0.0.0 line for 0.3.0.0-stable, a tag that was never cut for it, and refuses a catalogue nothing is wrong with. That is the failure the scheduled runs of 2026-09-04 and 2026-09-05 ended on:

$ gh run view 33958067106 --repo Flowfin/hub --log-failed | grep 'requests: the newest'
  requests: the newest finished release 0.3.0.0-stable is not listed under 12.0.0.0 (it carries 0.3.0.0-jf12-stable)

What changes

A release is named by the version its tag carries rather than by the whole tag. releaseVersion drops the leading v, the channel suffix and the line segment, and keeps the numeric run; carries asks whether a target line offers any tag naming that release. Nothing else moves.

The change can only stop refusals, never start them: equal tags have equal versions, so every catalogue the whole-tag comparison passed is passed here too. What it gives up is telling apart two finished releases that share a version and differ only in a suffix, which under the one-version-many-lines convention is exactly the pair that should not be told apart. That bound is written at the function.

The guards, refusing

Three near-misses, each one a mistake that is one edit away from the code as it stands.

The whole tag compared again, which is the state before this change:

$ go test ./internal/freshness/ -count=1
--- FAIL: TestOneVersionCutPerLineIsCurrent (0.00s)
    freshness_test.go:174: a catalogue carrying the newest release on both lines was refused, newest 0.3.0.0-stable: the published manifest is not current:
          widget: the newest finished release 0.3.0.0-stable is not listed under 12.0.0.0 (it carries 0.3.0.0-jf12-stable)
    freshness_test.go:174: a catalogue carrying the newest release on both lines was refused, newest 0.3.0.0-jf12-stable: the published manifest is not current:
          widget: the newest finished release 0.3.0.0-jf12-stable is not listed under 10.11.0.0 (it carries 0.2.0.0-stable, 0.3.0.0-stable)
--- FAIL: TestTagsThatNameDifferentReleasesAreNotConflated (0.00s)
    freshness_test.go:224: a leading v is spelling, not a different release: 1.2.3.4-stable against v1.2.3.4 was refused: the published manifest is not current:
          widget: the newest finished release 1.2.3.4-stable is not listed under 10.11.0.0 (it carries v1.2.3.4)
    freshness_test.go:224: two lines of one version: 1.2.3.4-jf12-stable against 1.2.3.4-jf13-stable was refused: the published manifest is not current:
          widget: the newest finished release 1.2.3.4-jf12-stable is not listed under 10.11.0.0 (it carries 1.2.3.4-jf13-stable)
FAIL

The refusal that first test reddens on is byte for byte the one the scheduled run failed on, which is what ties the fixture to the report.

The version truncated after five characters, so a fourth component stops counting:

$ go test ./internal/freshness/ -count=1
--- FAIL: TestTagsThatNameDifferentReleasesAreNotConflated (0.00s)
    freshness_test.go:227: a fourth component is part of the version: 1.2.3.4-stable against 1.2.3.0-stable was read as current
FAIL

The dot dropped from the numeric run, so only the first component is compared. This is the loose direction, the one that would quietly stop the check doing its job at all:

$ go test ./internal/freshness/ -count=1
--- FAIL: TestALineBehindTheNewestVersionIsStillRefused (0.00s)
    freshness_test.go:190: a target line a version behind was read as current
--- FAIL: TestTagsThatNameDifferentReleasesAreNotConflated (0.00s)
    freshness_test.go:227: a fourth component is part of the version: 1.2.3.4-stable against 1.2.3.0-stable was read as current
    freshness_test.go:227: a newer version is a different release: 1.2.4.0-stable against 1.2.3.4-stable was read as current
FAIL

What this branch reads green

The gate, whole:

$ 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

The network harness, which is the one that reads the real catalogue:

$ MANIFEST_ADDRESS=https://flowfin.dev/manifest.json go run . harness needs-network
ok  	flowfin.dev/hub/internal/freshness	10.479s

And the verb the failing workflow runs, against the world as it stands tonight:

$ go run . freshness ; echo "exit=$?"
what a release is refused for, and what this run read:
  catalogue-not-current  clear         https://flowfin.dev/manifest.json lists the newest finished release of all 8 declared plugin(s) that have one
                                       it refuses a published catalogue missing the newest release of a plugin, which every server reads as that version not existing

1 condition(s): 1 clear, 0 blocking, 0 not evaluated.
exit=0

That is the strongest evidence available before the next scheduled run: the same verb, the same address, the same release lists, exiting 0 where this morning's run exited 1. It is not the same thing as the scheduled run itself, which is why #165 stays open until one has gone green.

Means

Go, unchanged. The check being repaired is Go, the repair is a comparison inside it, and the proof is the suite that already judges this package against planted bodies. Nothing new arrives in the tree: no dependency, no runtime, and no second place where the shape of a tag is declared. The one alternative considered was teaching internal/freshness the line segment out of each declaration's stable_tags, which would put a tag's shape in two places and read it back out of a regexp by group position; comparing the numeric run needs neither.

No second reader

Nobody else has read this change. The evidence above stands in place of a second reader rather than beside one, and that is a statement about this branch and not about the rule.

…ness

The freshness watch compared the newest finished release's whole tag
against the tag every target line carries. Under the one-version-many-lines
tagging the requests declaration now admits, one version is released once
per live server line under its own tag, so 0.3.0.0 reaches the catalogue as
0.3.0.0-stable on 10.11.0.0 and as 0.3.0.0-jf12-stable on 12.0.0.0. The
comparison then asked the 12.0.0.0 line for a tag that was never cut for it
and refused a catalogue that is current, which is what the scheduled runs of
2026-09-04 and 2026-09-05 failed on and what #165 raised.

The comparison is now on the version the tag carries, with the leading v,
the channel suffix and the line segment dropped. It refuses nothing the
whole-tag comparison did not refuse, because equal tags have equal versions,
so a line that is genuinely a version behind is still refused and only the
false alarm goes away.

Towards #165, which its own body says is cleared by a later scheduled run
of the workflow ending in success and by nothing else, so this does not
close it.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit 7b2ed55 into main Sep 5, 2026
36 checks passed
@iderex
iderex deleted the work/af21-freshness-line-tags branch September 5, 2026 21:42
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.

1 participant