Closes out #158 items 4–5 (do not auto-close; manual close after verification). Part of #145 / phase (b) gates on #91.
Endpoints
GET /api/playouts/{id}/blocks — blocks used by a block playout (wraps GetAllBlocksForPlayout; 404 unknown playout).
GET /api/playouts/{id}/blocks/{blockId}/history?pageNum&pageSize — paged playout history (clamped paging; 404 unknown playout).
GET /api/playouts/history/{id} — decoded history details by row id (server-side lookup; 404 unknown row, 422 malformed Key/Details JSON). Decode core extracted into shared PlayoutHistoryDecoder, reused by the existing Blazor-path handler.
POST /api/troubleshoot/validate-schedule — {yaml, isImport} → {isValid, messages, json}; 400 empty yaml; validator/parse exceptions become messages, never 500 (Blazor parity).
Block-playout list reuses existing GET /api/playouts (scheduleKind filter client-side) — no new endpoint.
SPA: /app/troubleshooting/blocks (playout select → grouped blocks table with name filter → paged history → row-click decode panel) and /app/troubleshooting/yaml (textarea + import toggle + messages/JSON output), both in the System nav group. Internal drill-down state (no sub-paths). OpenAPI v1.json + v1.d.ts regenerated.
Tests: ErsatzTV.Tests 806 green (+14 controller/handler), Core.Tests 493 green, web 318 green (+9), lint clean. Post-#181 merge reconciled conflict-free, artifacts regen byte-identical.
Closes out #158 items 4–5 (do not auto-close; manual close after verification). Part of #145 / phase (b) gates on #91.
**Endpoints**
- `GET /api/playouts/{id}/blocks` — blocks used by a block playout (wraps GetAllBlocksForPlayout; 404 unknown playout).
- `GET /api/playouts/{id}/blocks/{blockId}/history?pageNum&pageSize` — paged playout history (clamped paging; 404 unknown playout).
- `GET /api/playouts/history/{id}` — decoded history details by row id (server-side lookup; 404 unknown row, 422 malformed Key/Details JSON). Decode core extracted into shared `PlayoutHistoryDecoder`, reused by the existing Blazor-path handler.
- `POST /api/troubleshoot/validate-schedule` — `{yaml, isImport}` → `{isValid, messages, json}`; 400 empty yaml; validator/parse exceptions become messages, never 500 (Blazor parity).
- Block-playout list reuses existing `GET /api/playouts` (scheduleKind filter client-side) — no new endpoint.
**SPA**: `/app/troubleshooting/blocks` (playout select → grouped blocks table with name filter → paged history → row-click decode panel) and `/app/troubleshooting/yaml` (textarea + import toggle + messages/JSON output), both in the System nav group. Internal drill-down state (no sub-paths). OpenAPI v1.json + v1.d.ts regenerated.
**Tests**: ErsatzTV.Tests 806 green (+14 controller/handler), Core.Tests 493 green, web 318 green (+9), lint clean. Post-#181 merge reconciled conflict-free, artifacts regen byte-identical.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds the REST surface for the #145 troubleshooting leftovers (#158 items 4-5):
- GET /api/playouts/{id}/blocks - blocks a block playout schedules
- GET /api/playouts/{id}/blocks/{blockId}/history - paged block history
- GET /api/playouts/history/{id} - decode a history row by id
- POST /api/troubleshoot/validate-schedule - validate sequential YAML
New MediatR queries GetPlayoutHistoryDetails (Either, 404 unknown row /
422 malformed JSON) and ValidateSequentialSchedule (wraps
ISequentialScheduleValidator, never throws). DecodePlayoutHistoryHandler
and the new by-id handler now share PlayoutHistoryDecoder. Regenerated
openapi/v1.json.
Refs #145#158
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Route assertions, paging clamp, 404/422/400 paths and mediator interaction
for the new PlayoutController/TroubleshootController endpoints; handler tests
for ValidateSequentialSchedule (valid/invalid/throwing) and
GetPlayoutHistoryDetails (found/not-found/malformed JSON via in-memory SQLite).
Refs #145#158
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two new System-area screens over the new endpoints:
- /app/troubleshooting/blocks: pick a Block playout, browse its blocks
(grouped, name filter), drill into paged block history, click a row to
decode its details.
- /app/troubleshooting/yaml: paste YAML, toggle import schema, validate;
shows messages + JSON conversion.
Adds api/playoutHistory client + validateSequentialSchedule; regenerated
generated/v1.d.ts. Async loads follow the LogsScreen seq-guard pattern
(no synchronous setState inside effects).
Refs #145#158
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes out #158 items 4–5 (do not auto-close; manual close after verification). Part of #145 / phase (b) gates on #91.
Endpoints
GET /api/playouts/{id}/blocks— blocks used by a block playout (wraps GetAllBlocksForPlayout; 404 unknown playout).GET /api/playouts/{id}/blocks/{blockId}/history?pageNum&pageSize— paged playout history (clamped paging; 404 unknown playout).GET /api/playouts/history/{id}— decoded history details by row id (server-side lookup; 404 unknown row, 422 malformed Key/Details JSON). Decode core extracted into sharedPlayoutHistoryDecoder, reused by the existing Blazor-path handler.POST /api/troubleshoot/validate-schedule—{yaml, isImport}→{isValid, messages, json}; 400 empty yaml; validator/parse exceptions become messages, never 500 (Blazor parity).GET /api/playouts(scheduleKind filter client-side) — no new endpoint.SPA:
/app/troubleshooting/blocks(playout select → grouped blocks table with name filter → paged history → row-click decode panel) and/app/troubleshooting/yaml(textarea + import toggle + messages/JSON output), both in the System nav group. Internal drill-down state (no sub-paths). OpenAPI v1.json + v1.d.ts regenerated.Tests: ErsatzTV.Tests 806 green (+14 controller/handler), Core.Tests 493 green, web 318 green (+9), lint clean. Post-#181 merge reconciled conflict-free, artifacts regen byte-identical.
🤖 Generated with Claude Code