Commit Graph
2618 Commits
Author SHA1 Message Date
timothy 6bbf669403 Merge pull request 'feat: schedules editor full mutation depth + channel-editor gaps (#207, #212, #126)' (#229) from feat/207-212-schedules-channel-depth into main
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Has been cancelled
Build ErsatzTV Image / Build & test (.NET) (push) Has been cancelled
2026-07-11 10:05:53 +00:00
timothy c4b7babbe8 Merge pull request 'test(api): locked-path 409 guard tests for ReplaceAlternateSchedules + ReplaceTemplates (#215)' (#240) from fix/215-guard-tests into main
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 6m4s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Has been cancelled
2026-07-11 09:59:43 +00:00
timothyandClaude Fable 5 3c7ed5c2f8 test(spa): raise timeout on trash see-all paging test (CI VM flake, run 686)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 10m17s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 10m0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:51:11 +02:00
timothyandClaude Fable 5 67547d998a test(api): locked-path 409 guard tests for ReplaceAlternateSchedules + ReplaceTemplates (fixes #215)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m18s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 8m37s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Closes the reviewer-verification gap from adversarial-reviewer#18: the
locked-path 409 guard tests already existed for Delete, EraseItems,
EraseItemsAndHistory, Update, and UpdateDefaultDeco, but were missing for
PlayoutController.ReplaceAlternateSchedules and .ReplaceTemplates even
though their production guards (entityLocker.IsPlayoutLocked) were in
place. Added two tests mirroring the existing pattern exactly (409
ConflictObjectResult + ProblemDetails + DidNotReceive() on the mediator
command). ApiErrorResponseMetadataTests and OpenApiErrorResponseContractTests
already carried 409 rows for both PUT endpoints, so no changes were needed
there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:49:40 +02:00
timothyandClaude Fable 5 9467a373b8 docs(handoff): lore — Codex back for independent review passes when quota allows
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m19s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m34s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:46:10 +02:00
timothyandClaude Fable 5 b82ae0c906 merge: origin/main (review-gates batch #222/#239) into feat/207-212
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Failing after 3m12s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m46s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:44:58 +02:00
timothyandClaude Fable 5 5e2b428876 docs(handoff): kickoff prompt also surfaces pending adversarial-reviewer audits as pickup candidates
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Has been cancelled
Build ErsatzTV Image / Build & test (.NET) (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:40:48 +02:00
timothyandClaude Fable 5 1bef9c9076 ci: small-runner lane + per-ref concurrency (queue starvation fix)
- build & docs-reminder jobs -> runs-on: small (dedicated small-jobs runner,
  server-management#574). Gitea dispatches a job as a runner task even when
  its 'if' skips it; the PR-run skip of 'Build & push image' waited up to
  31 min for an ubuntu-latest slot, stalling every PR run.
- concurrency scoped per event+ref with cancel-in-progress for PRs: runs
  parallelize across PRs, superseded syncs auto-cancel. Previously one global
  group serialized ALL runs (single-runner relic). Main/tag builds still
  serialize within their ref; don't push main + v* tag simultaneously
  (shared :buildcache / smoke container) — tag after main is green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:40:30 +02:00
timothy c77ed43585 Merge pull request 'Integration: review-gates batch — #220/#215/#217/#219/#218 + #213 remainder (PRs #223–#228)' (#239) from integrate/review-gates into main
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 4m59s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 8m54s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 5m38s
2026-07-11 00:03:46 +00:00
timothyandClaude Fable 5 f0ada7e993 docs: sweep stale #213 gap-issue cells after integration (all #213 items closed)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 13s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m26s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m41s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:53:06 +02:00
timothy 6dc9c12d8c Merge remote-tracking branch 'origin/fix/213-logs-trash' into integrate/review-gates
# Conflicts:
#	docs/blazor-route-parity.md
2026-07-11 01:49:50 +02:00
timothy cf81f28118 Merge remote-tracking branch 'origin/fix/215-entitylocker' into integrate/review-gates
# Conflicts:
#	docs/blazor-route-parity.md
#	docs/decisions.md
2026-07-11 01:49:16 +02:00
timothy aee96a1788 Merge remote-tracking branch 'origin/fix/220-episode-nav' into integrate/review-gates
# Conflicts:
#	docs/blazor-route-parity.md
2026-07-11 01:48:48 +02:00
timothy ef4b64d57c Merge remote-tracking branch 'origin/fix/218-playouts-badge' into integrate/review-gates 2026-07-11 01:48:20 +02:00
timothy c846593aa3 Merge remote-tracking branch 'origin/fix/217-219-api-fixes' into integrate/review-gates 2026-07-11 01:48:20 +02:00
timothy a039d5230c Merge remote-tracking branch 'origin/fix/213-spa-nits' into integrate/review-gates 2026-07-11 01:48:19 +02:00
timothy 245b1a5889 Merge pull request 'fix(spa): gate mutation controls on stale result sets during refetch (#221)' (#222) from fix/221-stale-refetch into main
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 7m6s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 7m46s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
2026-07-10 23:47:36 +00:00
timothyandClaude Fable 5 e5189f2921 docs(handoff): RAM-based fan-out gating (user calibration) + 2026-07-11 lessons (CI port fix, dual runners, cross-session plumbing merge)
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Has been cancelled
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Build ErsatzTV Image / Docs update reminder (push) Has been cancelled
Build ErsatzTV Image / Build & test (.NET) (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:42:10 +02:00
timothy 7f248fd553 Merge branch 'feat/207-212-schedules-channel-depth' of ssh://192.168.1.95:22/timothy/ersatztv into feat/207-212-schedules-channel-depth
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 12s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m13s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m5s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 01:27:39 +02:00
timothyandClaude Fable 5 3d35aa5348 fix(spa): defensively sort schedule items by index on ingest (#229)
Bug 2 (client side): array position becomes the persisted index on the next
PUT-replace, so the schedules editor must ingest strictly by the server-provided
`index` rather than trusting response row order — otherwise a reload + re-save could
silently reshuffle the lineup. Applied at both ingest points (GET load and the
replace response). Pinned by a shuffled-response-order test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:26:25 +02:00
timothyandClaude Fable 5 794bb0d4bb fix(schedules): reload write-path response with read includes + order GET by index (#229)
Bug 1 (500 on watermark/graphics save): Replace/Add handlers projected the
freshly-built entity graph, whose ProgramScheduleItemWatermark / -GraphicsElement
join rows carry only foreign-key ids — the Watermark/GraphicsElement navs are null,
and Mapper.ProjectToViewModel dereferences them unguarded, throwing an NRE that the
controller surfaced as a 500 on PUT/POST. Both handlers now reload the persisted
item(s) through the read-side include chain before projecting. Extracted that chain
into ProgramScheduleItemQueryExtensions.IncludeScheduleItemDetails() so GET, Replace
and Add share one source of truth.

Masking: PersistItems returned a lazy LanguageExt Map, and the existing round-trip
test only checked .IsRight — never enumerating it, so the deferred NRE never fired.
The new ScheduleItemWriteProjectionTests force enumeration (as the controller's
.ToList()/serialization does) and seed watermark/graphics via a separate context so
the handler's fresh factory context has nothing pre-tracked.

Bug 2 (server side): GetProgramScheduleItemsHandler now .OrderBy(i => i.Index) —
it previously returned id order, which is not index order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:26:25 +02:00
timothyandClaude Fable 5 dfd2134cb4 docs: queue protocol v2 — state moves to pinned Gitea tracker #237 (parallel-session safe)
Build ErsatzTV Image / Build & test (.NET) (push) Has been cancelled
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Has been cancelled
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Build ErsatzTV Image / Docs update reminder (push) Has been cancelled
Handoff file reduced to static kickoff prompt + append-only lessons lore;
queue/arc/session log live in pinned tracker ersatztv#237 with in-progress
claim labels and end-of-session triage. Decision recorded in decisions.md;
docs index updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:17:26 +02:00
timothy ef615f8c69 Merge main: CI MySQL host-port unpin (collision fix, #236)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 6m56s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 7m50s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 01:10:45 +02:00
timothyandClaude Fable 5 5918e947d9 test(schedules): pin FixedStartTimeBehavior + FixDiscardToFillAttempts in round-trip (F7)
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Failing after 2s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 12s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m1s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Seed a non-null FixedStartTimeBehavior (Flexible) on the Fixed-start item and
assert it survives envelope A; assert the Marathon-order Duration item's
DiscardToFillAttempts is zeroed by the deliberate FixDiscardToFillAttempts
server normalization (Random/Shuffle keep the value, all else -> 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:00:34 +02:00
timothyandClaude Fable 5 4bc43893c1 fix(spa): guard schedule editor against destructive cross-save + lost updates (F1/F3/F4/F5)
F1: switching schedules synchronously clears items/baseline/selection/dirty
before setActiveId (applySwitch) and gates every mutation surface on a
successful items load for the CURRENT activeId (itemsLoaded) — a failed items
GET for schedule B can no longer leave B's header over A's dirty draft and PUT
A's lineup into B.
F3: key={selectedItem._key} on ScheduleItemInspector so per-item child state
(PlaylistPicker groupId, SearchPicker query) resets on selection change.
F4: mutate() no-ops and all edit surfaces disable while saving, so edits during
an in-flight Save can't be silently discarded by the Save .then.
F5: create-schedule auto-switch routes through guardedSwitch so a dirty draft
gets the same discard confirm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:00:34 +02:00
timothyandClaude Fable 5 8feb9a1367 fix(spa): reconcile playbackOrder + multipleMode on schedule collection-type change (F2)
After a collection-type change, snap playbackOrder to the new type's first
offered order when the current one is no longer valid (e.g. Collection+Marathon
-> TelevisionShow left a stale 'Marathon' while the native <select> displayed
'Chronological' and Marathon fields stayed visible), and reconcile multipleMode
into the valid set for the new (type, order) state (e.g. CollectionSize
surviving a switch into Playlist). Replaces the narrow MultiCollection/Playlist
special-cases with a general invariant. Adds repro + a from/to-pair invariant
test; updates the Playlist multipleMode test to the corrected behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:00:34 +02:00
timothy 0120d3ce5b merge: feat/212-spa-channel into feat/207-212-schedules-channel-depth
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m17s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 11m0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
# Conflicts:
#	docs/decisions.md
2026-07-11 00:40:50 +02:00
timothy ceb45e4926 merge: feat/207-spa-schedules into feat/207-212-schedules-channel-depth 2026-07-11 00:37:07 +02:00
timothyandClaude Fable 5 5054cd8228 style+docs(spa): schedules editor CSS + parity/decisions/conventions docs (#207)
- shell.css: picker/multiselect/fieldset/toolbar styles for the new editor
- spa-conventions.md §8: navigation-guard convention
- decisions.md: draft/explicit-Save, Copy-includes-refs, shuffled-GET lossiness
- blazor-route-parity.md: schedules cluster -> PARITY-OK (#207 DONE)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:35:05 +02:00
timothyandClaude Fable 5 2687d33637 feat(spa): rebuild schedules editor to full mutation parity (#207)
Extract ScheduleScreen from App.tsx into screens/SchedulesScreen.tsx +
schedules/ domain folder (itemRules, pickers, inspector, ScheduleForm).
Draft model with explicit Save (single destructive PUT), Discard, dirty
guard (navigationGuard + beforeunload), schedule CRUD, and all Blazor
item fields/gates/resets. Rewrite api/schedules.ts to the flat DTO +
CRUD + languages/filler-by-kind pickers. Live TopBar Add Schedule via a
window CustomEvent. Screen + nav-guard tests; App.test updated for the
extracted screen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:32:25 +02:00
timothy d0e431beff Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m8s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m17s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:12 +02:00
timothy 086319f200 Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 18s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m38s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 10m15s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:11 +02:00
timothy b70713fde8 Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 19s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Failing after 6m8s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 15m30s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:10 +02:00
timothy 83455fa42e Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 12s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m51s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 8m44s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:09 +02:00
timothy 9da582924a Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 9s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Failing after 5m46s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m17s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:06 +02:00
timothy 6b9d76f948 Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 12s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 10m2s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 10m8s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:04 +02:00
timothy 7a28e6ae9c Merge main: CI MySQL host-port unpin (collision fix)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 4s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m8s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m37s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
2026-07-11 00:31:03 +02:00
timothy 846452e28c docs: close channel-editor gaps in blazor-route-parity + record #212 decisions
Channel editor cluster moves from GAPS to PARITY-OK in the verdict table now
that external logo URL, bare-create, and enumerated pickers have landed.
Records the bare-create-on-list-screen and external-logo-wins decisions in
decisions.md.
2026-07-11 00:16:15 +02:00
timothy f459e74645 feat(spa): bare-channel create from the channels list (#212)
Adds a "New blank channel" action next to "Add Channel" on ChannelsScreen
(web/src/App.tsx) that POSTs CreateChannelRequest with Blazor's add-mode
defaults (ChannelEditor.razor's else branch) via the new createChannel client,
then navigates to the channel's editor. Distinct from "Add Channel", which
remains the library-to-lineup ChannelBuilder flow and is untouched.
2026-07-11 00:16:09 +02:00
timothy 5d0ad8b0d7 feat(api): add languages, music-video-credits-templates, stream-selectors, createChannel clients (#212)
New web/src/api/languages.ts module (getLanguages) plus channels.ts additions
(getMusicVideoCreditsTemplates, getChannelStreamSelectors, createChannel) for the
channel-editor gaps in #212. Each has URL-building tests.
2026-07-11 00:15:41 +02:00
timothyandClaude Fable 5 0a8c7b691b feat(spa): logs sort + page-size persistence, trash see-all paging (#213)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m23s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 28s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 10m14s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Blazor parity for the remaining #213 conveniences:

- GET /api/logs gains sortField (timestamp|level) and sortDirection
  (asc|desc) query params, allow-listed and normalized (unrecognized
  values fall back to the pre-existing timestamp-desc default) rather
  than rejected with a 422. LogsScreen.tsx renders clickable, sortable
  column headers with a chevron direction indicator.
- LogsScreen.tsx now persists the chosen page size to localStorage
  (ctv-logs-page-size) and restores it on mount, following the
  existing designSystem.ts localStorage-preference pattern. This is a
  client-local UI preference, not the Blazor ConfigElement-backed
  server setting — see docs/decisions.md.
- TrashScreen.tsx adds a per-kind "See all N ..." affordance that
  pages past the 100/kind /api/search cap using the already-paginated
  GET /api/library/browse (mediaType + pageNum), appending results
  client-side. No new API surface was needed since that endpoint
  already supports the paging the trash screen needed.

docs/decisions.md, docs/blazor-route-parity.md, docs/spa-conventions.md
and docs/api-conventions.md updated in this same commit. OpenAPI spec
regenerated (v1.d.ts unchanged: query params aren't part of the
generated components/schemas surface).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:10:20 +02:00
timothyandClaude Fable 5 5816c31136 feat(spa): pure schedule-item rules module (#207)
Blazor-parity gating, option lists and forced-reset transforms for the
schedules editor, exhaustively unit-tested (44 cases). No React/fetch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:09:49 +02:00
timothyandClaude Fable 5 ef8915f1ca ci: unpin MySQL service host port 3306 (concurrent-run collision)
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 6m48s
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 10m40s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
The migrations job connects via Server=mysql on the shared runner network;
the host-port publish was unused and made overlapping runs fail with
"Bind for 0.0.0.0:3306: port is already allocated" (bit PR #222 tonight,
backlogged since #216).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:09:26 +02:00
timothyandClaude Fable 5 caeabf2a2b fix(spa): block-history page-size persistence + History gating, blocks/templates list filter (#213)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m7s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m47s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Blazor parity conveniences: BlockPlayoutTroubleshootingScreen now persists the block-history
page-size selector to localStorage (ctv-block-history-page-size, same ctv- namespace as
ctv-theme) and restores it on mount, and gates the per-block History action on block.id >= 0
(mirrors BlockPlayoutTroubleshooting.razor, which hides it for synthesized/virtual blocks).
BlocksScreen and TemplatesScreen list screens gain a client-side name/group search filter box,
matching the filter already present on the troubleshooting blocks list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:04:15 +02:00
timothyandClaude Fable 5 35206b2199 test(api): drop stale WatermarkViewModel serializer-contract case (#126)
The flat ScheduleItemResponseModel removed the polymorphic ProgramScheduleItemViewModel
from the API surface, which was the only path exposing the Application VMs
(WatermarkViewModel, PlaylistViewModel, FillerPresetViewModel, collection VMs, etc.).
WatermarkViewModel is no longer in v1.json, so its serializer-contract guard case is moot.
ChannelViewModel still covers the schema transformer's VM path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:57:13 +02:00
timothyandClaude Fable 5 6823b42dbc fix(spa): remove hard-coded Playouts nav badge (fixes #218)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m49s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 12s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 10m43s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
The sidebar "Playouts 3" badge on a fresh empty DB was design-mock
scaffolding (badge: 3 hard-coded in the routes array) never wired to
live data; Blazor had no equivalent. Removed the value but kept the
nav-badge mechanism (ScreenRoute.badge, NavItem badge/badgeTone props)
in place since it's a plausible future home for a live warnings count.

The footer "1 failing" chip reported in the same issue is NOT a bug:
summarizeHealth renders live GET /api/health data, and on a fresh
local dev instance the genuinely failing check is FFmpeg Capabilities
(local Homebrew ffmpeg lacks the subtitles/zscale filters that prod's
ffmpeg image has). No code change for that half.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:55:07 +02:00
timothyandClaude Fable 5 223797a6cb docs+openapi: regenerate v1.json/endpoint-index/types + record flat schedule DTO decision (#126 #207 #212)
- Regenerated ErsatzTV/wwwroot/openapi/v1.json, docs/endpoint-index.md, and
  web/src/api/generated/v1.d.ts for the flat schedule-item DTO + discovery endpoints
- docs/decisions.md: flat ScheduleItemResponseModel + NamedIdResponseModel rationale
- docs/api-conventions.md: shared {id,name} embed, polymorphic-VM flattening, and
  optional enum query-filter conventions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:54:12 +02:00
timothyandClaude Fable 5 0156077e18 docs(e2e): add local TV library seeding recipe (#220)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m17s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Failing after 3s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Document the on-disk media + direct-SQLite LibraryPath + scan recipe for
E2E, since a local library is not API-seedable. Capture two gotchas hit
while verifying the episode-nav PR: deleting search-index/ leaves search
permanently empty (migration doesn't reindex from DB; rescan skips
unchanged files), and /api/search needs field/wildcard queries
(title:Alpha), not bare title words.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:52:29 +02:00
timothyandClaude Fable 5 b13fb0ffc7 test(api): lossless GET->PUT round-trip + EnforceProperties normalization (#126 #207 #212)
Fixed-point round-trip over all schedule-item subtypes (One/Flood/Multiple/
Duration) and field families (fixed-start, preferred audio/subtitle, custom
title, marathon, fillers x5, 2 watermarks, 2 graphics, rerun, search) proving
the flat ScheduleItemResponseModel reconstructs an identical PUT. Second test
documents the deliberate ShuffleScheduleItems normalization (Flood->One,
Fixed->Dynamic, Playlist->PlaybackOrder None).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:50:10 +02:00
timothyandClaude Fable 5 c5ebe29ce6 test(api): controller tests for flat schedule DTO + discovery endpoints (#126 #207 #212)
- ScheduleController GET/POST/PUT items now assert flat ScheduleItemResponseModel shapes
- LanguagesControllerTests (route + VM->DTO mapping)
- ChannelController tests for music-video-credits-templates + stream-selectors literal routes
- FillerPreset controller/handler tests for FillerKind field + ?fillerKind= filter

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:42:53 +02:00