docs(release): record the v26.15.0 release notes #898

Merged
timothy merged 1 commits from release/v26.15.0-notes into main 2026-08-30 17:25:59 +02:00
Owner

Docs-only, single commit. Adds the v26.15.0 row to the release table in docs/ci-cd.md.

The tag does NOT go on this commit

Unlike #739 (v26.14.0) and #716 (v26.13.0), the tag will be pushed onto 736649b3b, an ancestor of main — not onto this commit and not onto main's head.

main cannot build an image and has not been able to since e8f80c42c:

run / job commit Build & push image (amd64)
2459 / 10545 736649b3b (#882) success, 6m45s, published
2472 e8f80c42c (#883) failure
… 6 more … failure
2515 / 10843 cf5f42edf (#897) failure, 86s, died in web-build

e8f80c42c added web/src/api/completeAnnotations.guard.test.ts, a third importer of virtual:etv-tracked-source-files, without adding it to the hand-maintained --exclude list in the Dockerfile's web-build stage — and that stage has no git index by construction. The guard is behaving correctly: it refuses to fall back to a filesystem walk (testing.guard-derives-population-from-source). That is #887, priority: high, claimed and in progress in another session — this PR does not touch it.

A v* tag runs the same Dockerfile, so tagging main's head would fail at the image build and produce no release.

Two independent confirmations that 736649b3b is the newest valid tag point:

  • Structural — at 736649b3b the only test importing the virtual module is pageSizeCallSites.guard.test.ts, which is in the exclude list. completeAnnotations.guard.test.ts does not exist there (git cat-file -e → absent).
  • End-to-end — the container registry holds ersatztv:736649b3 and none of the eight shas after it.

Consequence, recorded in the row itself: #880 (scheduling recurrence — an absent array means unrestricted) merged after the break and therefore slips to the next release. The other seven excluded commits are hooks/scripts/CI/docs only, none of which ship in the image.

Release-boundary sweep

Per docs/ci-cd.md → "Before cutting a release":

Step Result
decisions_validate.py OK
build_decisions_catalog.py no drift
superseded/retired under archive/ validator-enforced, clean
legacy-unmigrated count 0
per-record ceiling 45/218 over 60 lines — fraction 0.21, inside the blocking 0.02–0.25 band
aggregate prose trend 10276 lines / 218 records (mean 47) + 680 scaffolding

The validator notes the 60-line ceiling has drifted below the tail boundary it was derived from (p90=104, p95=142) and asks for re-derivation when convenient. That is a maintenance signal about the constant, not a blocker — flagging it rather than silently re-deriving it inside a release PR.

Local gate on 736649b3b

Check Result
dotnet build ErsatzTV.sln -c Release 0 errors, 60 warnings
dotnet test -c Release --no-build 4556 passed, 7 skipped, 0 failed across 7 projects
dotnet list package --vulnerable --include-transitive no vulnerable packages, all 17 projects
SPA lint / typecheck / test / build 119/119 files, 1272/1272 tests

Verification of the row itself

Every claim was checked against the range rather than asserted: 8 paged handlers (GetPaged*Handler.cs), exactly one dual-provider migration (Add_FFmpegProfile_ReadRatePacing), SongMetadata.Artists in both ElasticSearchIndex and LuceneSearchIndex, and Scriban.Signed 7.2.6 as the only dependency change across Directory.Packages.props + .config/dotnet-tools.json.

Docs

docs/ci-cd.md is the only doc a release-notes row touches per the CLAUDE.md docs-update table. No route, endpoint, SPA convention or decision changed.

Docs-only, single commit. Adds the `v26.15.0` row to the release table in `docs/ci-cd.md`. ## The tag does NOT go on this commit Unlike #739 (v26.14.0) and #716 (v26.13.0), the tag will be pushed onto **`736649b3b`**, an ancestor of `main` — not onto this commit and not onto `main`'s head. `main` cannot build an image and has not been able to since `e8f80c42c`: | run / job | commit | `Build & push image (amd64)` | |---|---|---| | 2459 / 10545 | `736649b3b` (#882) | **success**, 6m45s, published | | 2472 | `e8f80c42c` (#883) | failure | | … 6 more … | | failure | | 2515 / 10843 | `cf5f42edf` (#897) | failure, 86s, died in `web-build` | `e8f80c42c` added `web/src/api/completeAnnotations.guard.test.ts`, a third importer of `virtual:etv-tracked-source-files`, without adding it to the hand-maintained `--exclude` list in the Dockerfile's `web-build` stage — and that stage has no git index by construction. The guard is behaving correctly: it refuses to fall back to a filesystem walk (`testing.guard-derives-population-from-source`). That is **#887**, `priority: high`, claimed and in progress in another session — this PR does not touch it. A `v*` tag runs the same Dockerfile, so tagging `main`'s head would fail at the image build and produce no release. Two independent confirmations that `736649b3b` is the newest valid tag point: - **Structural** — at `736649b3b` the only *test* importing the virtual module is `pageSizeCallSites.guard.test.ts`, which **is** in the exclude list. `completeAnnotations.guard.test.ts` does not exist there (`git cat-file -e` → absent). - **End-to-end** — the container registry holds `ersatztv:736649b3` and **none** of the eight shas after it. Consequence, recorded in the row itself: **#880** (scheduling recurrence — an absent array means unrestricted) merged after the break and therefore slips to the next release. The other seven excluded commits are hooks/scripts/CI/docs only, none of which ship in the image. ## Release-boundary sweep Per `docs/ci-cd.md` → "Before cutting a release": | Step | Result | |---|---| | `decisions_validate.py` | **OK** | | `build_decisions_catalog.py` | no drift | | superseded/retired under `archive/` | validator-enforced, clean | | legacy-unmigrated count | **0** | | per-record ceiling | 45/218 over 60 lines — fraction 0.21, inside the blocking 0.02–0.25 band | | aggregate prose trend | 10276 lines / 218 records (mean 47) + 680 scaffolding | The validator notes the 60-line ceiling has drifted below the tail boundary it was derived from (p90=104, p95=142) and asks for re-derivation when convenient. That is a maintenance signal about the constant, not a blocker — flagging it rather than silently re-deriving it inside a release PR. ## Local gate on `736649b3b` | Check | Result | |---|---| | `dotnet build ErsatzTV.sln -c Release` | 0 errors, 60 warnings | | `dotnet test -c Release --no-build` | **4556 passed, 7 skipped, 0 failed** across 7 projects | | `dotnet list package --vulnerable --include-transitive` | **no vulnerable packages**, all 17 projects | | SPA `lint` / `typecheck` / `test` / `build` | 119/119 files, 1272/1272 tests | ## Verification of the row itself Every claim was checked against the range rather than asserted: 8 paged handlers (`GetPaged*Handler.cs`), exactly one dual-provider migration (`Add_FFmpegProfile_ReadRatePacing`), `SongMetadata.Artists` in both `ElasticSearchIndex` and `LuceneSearchIndex`, and `Scriban.Signed` 7.2.6 as the only dependency change across `Directory.Packages.props` + `.config/dotnet-tools.json`. ## Docs `docs/ci-cd.md` is the only doc a release-notes row touches per the CLAUDE.md docs-update table. No route, endpoint, SPA convention or decision changed.
timothy added 1 commit 2026-08-30 16:56:58 +02:00
docs(release): record the v26.15.0 release notes
Build ErsatzTV Image / CI toolchain image resolves (pull_request) Successful in 6s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 14s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 14s
PR Gates / Docs update reminder (pull_request) Successful in 15s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 23s
PR Gates / decisions lifecycle (pull_request) Successful in 20s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 12s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 14s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 9s
review-verdict/h10 Exempt: docs-only change (no code, no protected path)
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 8s
Review verdict / Set review-verdict status (pull_request_target) Successful in 17s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 6s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 19m1s
4c44a13e3d
Adds the `v26.15.0` row to the release table in `docs/ci-cd.md`.

The tag goes on `736649b3b`, NOT on this commit and not on `main`'s head. Every
`Build & push image (amd64)` since `e8f80c42c` fails: that commit added
`web/src/api/completeAnnotations.guard.test.ts`, a third importer of
`virtual:etv-tracked-source-files`, without adding it to the hand-maintained
`--exclude` list in the Dockerfile's `web-build` stage — and that stage has no
git index, by construction (#887, claimed and in progress elsewhere). The guard
is behaving correctly; it refuses to fall back to a filesystem walk. Measured:
run 2459 on `736649b3b` ran the image job for 6m45s and published; run 2515 on
`cf5f42edf` died in web-build after 86s. `736649b3b` is therefore the newest
commit on `main` that can produce a release image.

Consequence recorded in the row itself: #880 (scheduling recurrence) slips to
the next release, since it merged after the break.

Release-boundary sweep (docs/ci-cd.md -> "Before cutting a release"):
- `decisions_validate.py` -> OK; 0 legacy-unmigrated records remain
- `build_decisions_catalog.py` -> no drift
- record ceiling: 45/218 over 60 lines (fraction 0.21, inside the blocking
  0.02-0.25 band). The validator notes the 60 has drifted below the tail
  boundary (p90=104, p95=142) and asks for re-derivation when convenient —
  a maintenance signal about the constant, not a blocker for this cut.
timothy merged commit 4b7ede80b8 into main 2026-08-30 17:25:59 +02:00
Sign in to join this conversation.