Skip to content

Raise the version to 0.1.1.0 and read the floor on every install route - #349

Merged
iderex merged 1 commit into
masterfrom
release/334-cut-0-1-1-0
Sep 7, 2026
Merged

iderex merged 1 commit into
masterfrom
release/334-cut-0-1-1-0

Conversation

@iderex

@iderex iderex commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Part of issue #334: this is step 1 and step 5 of that issue, and the page reading step 2 asks for. Steps 3 and 4, the tag and the two catalogue installs, follow this merge and are written into the issue rather than here.

THIS LINE OPENED "Closes #334 in part" WHEN THE REQUEST WAS MERGED, AND THE QUALIFIER DID NOT REACH THE PARSER. The merge closed #334 with two of its done-conditions unmet, the issue was reopened, and this line is edited so the record does not keep asserting a closure it did not earn. The edit changes the pointer and nothing else in this body.

What changed

build.yaml carries 0.1.1.0 and one new sentence in changelog, above the 0.1.0.0 line. CHANGELOG.md gains a ## 0.1.1.0 heading and the Unreleased entries move under it. docs/support-matrix.md moves its plugin versions cell to 0.1.1.0. .github/workflows/reading-install-route.yml runs its reading once per server rather than once.

Why the support matrix is here, and it is outside the declared scope

Issue #334's Scope: line names build.yaml, CHANGELOG.md, docs/RELEASING.md, .github/workflows/reading-install-route.yml and the tag. docs/support-matrix.md is not on it, and it is in this change because the suite refuses the alternative: ThePluginVersionsColumnNamesTheNewestReleaseOfEachLine compares the cell against the newest ## X.Y.Z.W heading in CHANGELOG.md, so a heading that lands without the cell is a red suite. docs/RELEASING.md is on the scope line and is not touched: nothing in it was wrong.

That file's ## Plugin versions section also stopped pasting a release count and a tag list. Both move with the next tag, and the tag for this heading is pushed after this merge, so the paste would have been stale within the hour. What replaces it is the command that derives the answer and one paragraph naming the window between a heading and its tag, so a reader who meets the two disagreeing reads the window rather than a defect.

The floor leg, and why it did not exist

The image the reading pinned resolves to 10.11.11:

docker buildx imagetools inspect jellyfin/jellyfin:10.11.11 | grep -m1 '^Digest:'
Digest:    sha256:aefb67e6a7ff1debdd154a78a7bbb780fd0c873d8639210a7f6a2016ad2b35db

The comment above it read "A real server, on the oldest line this plugin declares support for". That names the line, 10.11 rather than 12.0, and not the oldest server on it. So the floor of the line was the one server the documented install route was never read on, and the floor is exactly where 0.1.0.0 failed. The matrix now has two legs, 10.11.0 and 10.11.11, fail-fast is off so a red leg leaves the other's answer readable, and the digest reaches the run block through env: rather than through an interpolation, which is what the workflow security gate asks of every run block here.

docker buildx imagetools inspect jellyfin/jellyfin:10.11.0 | grep -m1 '^Digest:'
Digest:    sha256:59417f441213e236a9f907d4e71a13472042409d85f9e9310dbdd87ee33d7bd4

Neither leg has been dispatched from this branch: the reading installs whatever the published address serves, which is still 0.1.0.0, so a dispatch now would read the previous release rather than this one. It is dispatched after the tag, and both readings go into #334.

The page reading

docs/RELEASING.md asks for the declared pages to be opened on a server built from the commit to be tagged, and issue #334 asks for it on 10.11.11 and on 10.11.0. What is declared is derived rather than listed, and the server is the thing asked:

GET /web/ConfigurationPages -> 200
  'Playback Statistics' EnableInMainMenu=False MenuSection=None

One page, the settings page, which is what #332 left declared.

The package was built from this branch at 80285a7 with jprm and installed into a fresh server of each version:

python -m jprm plugin build . --output=./artifacts --dotnet-framework=net9.0
Setting project version to 0.1.1.0
./artifacts/playback-statistics_0.1.1.0.zip

10.11.11

== the server
  version 10.11.11
== what the plugin says about itself
  Playback Statistics 0.1.1.0 status=Active
== the configuration pages this server offers
  GET /web/ConfigurationPages -> 200
  'Playback Statistics' EnableInMainMenu=False MenuSection=None
== opening 'Playback Statistics', the way the dashboard fetches it
  GET /web/ConfigurationPage?name=Playback Statistics -> 200, 18680 bytes
  headings:  ['Where this plugin keeps its data']
  controls:  ['CaptureEnabled', 'DailyAggregateRetentionDays', 'ExcludedItemTypes', 'ExcludedUserIds', 'MaximumRangeDays', 'MaximumRowsPerResponse', 'PlayRowRetentionDays', 'RollupTimeZone', 'StatsConfigForm', 'StatsConfigPage', 'StatsPluginState', 'StatsRejectedFields']
  buttons:   ['<span>Save</span>']
== whether the store opened, which is what this release is about
  GET /Stats/Users/{id}/Statistics/last30Days -> 200
  WhyTheStoreCouldNotBeOpened: ''
  OldestStoredPlay:            ''

10.11.0, the floor

== the server
  version 10.11.0
== what the plugin says about itself
  Playback Statistics 0.1.1.0 status=Active
== the configuration pages this server offers
  GET /web/ConfigurationPages -> 200
  'Playback Statistics' EnableInMainMenu=False MenuSection=None
== opening 'Playback Statistics', the way the dashboard fetches it
  GET /web/ConfigurationPage?name=Playback Statistics -> 200, 18680 bytes
  headings:  ['Where this plugin keeps its data']
  controls:  ['CaptureEnabled', 'DailyAggregateRetentionDays', 'ExcludedItemTypes', 'ExcludedUserIds', 'MaximumRangeDays', 'MaximumRowsPerResponse', 'PlayRowRetentionDays', 'RollupTimeZone', 'StatsConfigForm', 'StatsConfigPage', 'StatsPluginState', 'StatsRejectedFields']
  buttons:   ['<span>Save</span>']
== whether the store opened, which is what this release is about
  GET /Stats/Users/{id}/Statistics/last30Days -> 200
  WhyTheStoreCouldNotBeOpened: ''
  OldestStoredPlay:            ''

The same page, the same length, on both. The line that matters is the last block on the floor server: 0.1.0.0 loaded there and could not open its store, and this build opens it. The store file exists on both:

docker exec stats-af08-10110 ls -l /config/plugins/Jellyfin.Plugin.Stats/
-rw-r--r-- 1 root root 73728 Sep  7 02:22 plays.db

and both servers logged the load:

[INF] PluginManager: Loaded assembly Jellyfin.Plugin.Stats, Version=0.1.1.0, Culture=neutral, PublicKeyToken=null from /config/plugins/stats/Jellyfin.Plugin.Stats.dll
[INF] PluginManager: Loaded plugin: Playback Statistics 0.1.1.0

The assembly references of that archive carry the floor's stack, Microsoft.Data.Sqlite 9.0.10.0, read off the assembly in the built zip. The same reading is taken again on the published archive and pasted into #334, because an archive built here is not the archive a user installs.

Alongside it, tools/reading/settings-page-reading.py was run against both servers and passed on both: WhyTheStoreCouldNotBeOpened and OldestStoredPlay came back PRESENT in the answer before and after the save and absent from the stored XML, and CaptureEnabled came back PRESENT, on 10.11.11 and on 10.11.0 alike.

What the reading is not

No browser rendered the page. What is pasted is the HTML the server serves to the dashboard, parsed for its headings, its controls and its buttons. Nobody clicked anything, so nothing here says the page looks right; it says the server serves it, its controls are the ones the model declares, and the store behind it opens. The reading docs/RELEASING.md describes is a person's, and this is not a substitute for one.

The build was made with jprm 1.1.0 on this machine rather than by the pinned action, and jprm rewrites the version derivation in Directory.Build.props into a literal as a side effect. That edit was reverted and is not in this branch; the values it wrote were the same 0.1.1.0 the derivation produces.

The means

No new means was chosen. The version is YAML because build.yaml is the manifest a server reads, the changelog and the matrix are the tracked markdown the suite already reads, and the second leg is a matrix in the workflow file that already held the reading. Nothing here adds a language, a runtime or a dependency the tree does not carry.

The suite

dotnet test Jellyfin.Plugin.Stats.Tests/Jellyfin.Plugin.Stats.Tests.csproj -c Release -f net9.0
Failed: 0, passed: 1056, skipped: 0, total: 1056
| Jellyfin.Plugin.Stats | 98.96% | 100% | 96.27% |

Second reader

Nobody but its author has read this change. This board has no second reader tonight, and this paragraph stands in place of one rather than leaving the absence unsaid.

#334]

0.1.0.0 bound Microsoft.Data.Sqlite 9.0.11.0 and the archive ships one
assembly, so the stack comes from the server. A 10.11.0 server carries
9.0.10.0, a strong-named assembly found below the referenced version is not
found at all, and there the plugin loaded and then could not open its store.
That is repaired on master already; this change is the release that carries the
repair to a server, and the leg that would have caught it.

version in build.yaml moves to 0.1.1.0 and the Unreleased entries move under a
0.1.1.0 heading in CHANGELOG.md, which is the order issue #133 settled: the
number is raised first and the tag pushed second, because a release deleted to
correct its number burns that tag permanently. build.yaml gains the one
sentence a catalogue shows under the version, above the 0.1.0.0 line.

docs/support-matrix.md moves with the heading rather than with the number,
which is what SupportMatrixTests refuses otherwise: the plugin versions cell of
the 10.11 row names the newest release heading of its line. That file is not in
the Scope line issue #334 declares, and it is here because the suite goes red
without it. Its Plugin versions section also stopped pasting a release count
and a tag list, because both move with the next tag and a number written into a
document drifts against the thing it describes; the command that derives them
is handed to the reader instead, with the window between the heading and the
tag stated rather than left for somebody to read as a defect.

reading-install-route.yml runs once per server rather than once. The digest it
pinned was the newest patch of the 10.11 line, and the comment above it said
"the oldest line this plugin declares support for", which names the line and
not the oldest server on it. So the floor of that line was the one server this
route was never read on, and it is the server the failure above was visible on.
The matrix has two legs, the floor and the newest patch, fail-fast is off so a
red leg still leaves the other's answer readable, and the image reaches the run
block through the environment rather than through an interpolation.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex iderex added the area: release Versioning, manifest and catalogue label Sep 7, 2026
@iderex iderex self-assigned this Sep 7, 2026
@iderex iderex added this to the 0.1.1.0 The repair milestone Sep 7, 2026
@iderex
iderex merged commit a8c8d38 into master Sep 7, 2026
25 checks passed
@iderex
iderex deleted the release/334-cut-0-1-1-0 branch September 7, 2026 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: release Versioning, manifest and catalogue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cut 0.1.1.0 and prove the install on the floor and on the newest patch

1 participant