Skip to content

feat(version): one app-version provider, schema journal, version markers (F211) - #876

Merged
genwave-radio merged 8 commits into
mainfrom
host/app-version-markers-868
Sep 28, 2026
Merged

genwave-radio merged 8 commits into
mainfrom
host/app-version-markers-868

Conversation

@genwave-radio

Copy link
Copy Markdown
Collaborator

🏷️ What

One app-version provider, and version markers you can read from the outside.

  • IAppVersion (T588–T590) is the only reader of the build stamp. About, spectator About, the ad re-render marker and every User-Agent read it, and an architecture law enforces that. UA = GenWave/v<semver> (+https://github.com/GenWave-Org/genwave).
  • Schema journal (T591–T592): migrate.sh records one station.schema_migration row per applied script, with app_version from $GW_VERSION or null. SchemaVersion.Expected = 49. db/06 mirrors the table for fresh init (gh-db/06 fresh-init mirror is missing station.schedule_special (db/36) #618), with a text-equality pin.
  • Status + drift WARN (T593): /api/status gains version {app, build, schema {expected, applied}}. If the applied schema is behind, boot logs exactly one WARN telling you to run ./migrate.sh, and the api keeps serving.
  • Engine (T594): /internal/engine-config adds GW_APP_VERSION as a fourth key. The entrypoint checks it against an allowlist, logs it on one boot line, and never passes it to Liquidsoap.

Closes #868.

🔬 T595 wire transcript (dev stack, images built at v5.13.3-8-gd5b10c5)

  1. GW_VERSION=v5.14.0-dev ./migrate.sh → exit 0; 48 journal rows (02…49) for 48 db/*-migration.sh scripts, all app_version = v5.14.0-dev.
  2. /api/status .version → {app: v5.13.3-8-gd5b10c5, build: 5.13.3-8-gd5b10c5, schema: {expected: 49, applied: 49}}.
  3. Deleted the 49 row, then docker compose restart api:
    • exactly 1 WARN: Schema drift: database has applied 48 but this build expects 49 — run ./migrate.sh;
    • /api/status 200 with applied: 48;
    • track-started rows kept landing (polled, not slept);
    • re-ran migrate.sh → 48 rows back, and the next restart logged 0 drift WARNs.
  4. Engine log: [engine-entrypoint] control-plane version: GW_APP_VERSION=v5.13.3-8-gd5b10c5.
  5. /api/about → version: v5.13.3-8-gd5b10c5. Spectator mode is off on the dev station, so /spectator/api/about returns 404 there by design. Its read of IAppVersion.Display is covered in-process by Story483.

✅ Tests

dotnet test GenWave.sln --filter "Category!=Integration" -- xUnit.MaxParallelThreads=3: 0 failed across 9 projects (Host 3231 passed / 13 skipped).

📝 Notes / follow-ups

  • If api and engine are recreated together, the engine can boot before the api answers and fall back to its env defaults, so there is no version line until the next engine restart. This is not new behaviour.
  • The StoryF4_EngineConfigEndpoint private mirror is stale; it asserts 2 lines. It predates this PR.
  • Move the DatabaseFixture/EphemeralStationDatabase/Kokoro compose plumbing onto ComposeProcess.
  • SPEC F211.1 "entry assembly" wording needs a fix: the provider reads typeof(Program).Assembly.

One version provider, the migrate.sh schema journal and the status/engine
markers (gh-#9, gh-#868). Skipped facts until T588-T595 turn them green.
One parser turns the entry assembly's InformationalVersion into Display
(v<semver>), Semver and Build (+sha kept for debugging); anything
unparseable reads unknown. Registered once as a singleton in Program.cs.
Consumers move onto it in T589/T590 (F211.1-F211.2, gh-#868).
… IAppVersion

HostVersion and AdAppVersion are gone; the About endpoints and the ad
re-render marker take IAppVersion.Display, so every surface spells the
version the same way (v<semver>). The provider now reads the Host
assembly's stamp explicitly: GetEntryAssembly() resolved to the VSTest
host under WebApplicationFactory, which the specs now pin against the
real stamp. Un-skips STORY-483 AC5-AC7.
EtiquetteUserAgent now owns the project URL and builds from IAppVersion;
MusicBrainz, history and the catalog fetcher inject it, so every UA reads
GenWave/v<semver> (+https://github.com/GenWave-Org/genwave).
CatalogHttpFetcher becomes a DI singleton holding the version and the
client factory. An architecture law pins AppVersion as the only reader of
AssemblyInformationalVersionAttribute (FileVersionInfo forbidden too), the
old HostVersion/AdAppVersion stay gone, and the Abstractions surface is
unchanged. PublicSurface gains the shared baseline reader and diff.
Un-skips STORY-483 AC8-AC11.
migrate.sh now creates station.schema_migration in its preamble and
upserts one row per successfully applied script (file name, now(),
GW_VERSION or null). A failed script writes nothing; --dry-run is
unchanged; no existing migration is edited. db/06 mirrors the table
for fresh init (gh-#618), with an arch pin keeping both DDL copies
identical and an AC11 law that fails on any edit, rename or deletion
of an existing migration.
SchemaVersion.Expected (49) is the highest migration this build knows;
an architecture law pins it to the highest db/NN-*-migration.sh so a
migration PR that forgets the bump is red. ISchemaJournal reads the
highest journalled NN from station.schema_migration: null when the
journal is empty (raw compose up) or the table is missing (42P01,
pre-F211 box). Registered in DI; /api/status consumes it in T593.
GET /api/status gains version {app, build, schema {expected, applied}}.
A background boot check reads the schema journal once and logs exactly
one WARN when applied is behind Expected or unknown, naming both
numbers and ./migrate.sh (a journal fault rides on that WARN). It never
throws and never blocks boot; drift is reported, not enforced (F211.6).
…ogs it once

/internal/engine-config appends GW_APP_VERSION=<IAppVersion.Display> as the
fourth and last key. engine/entrypoint.sh validates it against a whole-string
allowlist (^(unknown|v[0-9A-Za-z.+-]+)$, else "invalid"), logs one boot line,
and never exports it or passes it to liquidsoap.

Story485 AC4/AC5 un-skipped: the endpoint via WebApplicationFactory, the real
entrypoint with stubbed curl and a recording liquidsoap stub, plus CR-forged
and ANSI-escape sad paths. Story099/108/444 never pinned the key list, so no
pin moved; no entrypoint byte/sha pins exist.
@genwave-radio
genwave-radio merged commit fbb10df into main Sep 28, 2026
11 checks passed
@genwave-radio
genwave-radio deleted the host/app-version-markers-868 branch September 28, 2026 11:12
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

One app-version provider for the About page and ads

1 participant