# MEMORY ## 2026-08-07 - Completed runtime validation section from TODO. - Runtime video normalization tests executed in running `linearvoid-playout` container using ffmpeg/ffprobe. - Verified normalized outputs for MOV, MKV, VFR, and 5.1 inputs: `h264`, `yuv420p`, `30/1`, `aac`, `48000`, `2 channels`. - Concat continuity check passed with `CONCAT_OK`; output duration `25.344667` seconds. - Responsive viewport test on live viewer (`390x844`, `412x915`) detected 8px horizontal overflow from `100vw` usage in viewer container styles. - Fixed overflow in source by changing `.lv-body` and `.viewer-shell` width from `100vw` to `100%` in `frontend/src/style.css`. - Redis restart test: - Admin session endpoint returned 200 before and after Redis restart. - Presence key survived Redis restart in test-lab configuration. - Redis health returned to `healthy` post-restart. - Files changed: - `.github/instructions/TODO.md` - `.github/instructions/DONE.md` - `frontend/src/style.css` - `CHANGELOG.md` ## 2026-08-07 (continued) - Completed documentation half of recovery runbook TODO item. - Expanded `docs/incident-runbook.md` with quarterly DR drill: prerequisites, outage simulation, restore validation, pass/fail criteria, and evidence template. - Split TODO item into: - documented drill (`[x]`) - manual rehearsal execution (`[ ]`) - Updated `CHANGELOG.md` with incident runbook drill documentation entry. ## 2026-08-07 (continued 2) - Added manual operations checklist `docs/operations/cloudflare-uptimerobot-checklist.md` for Cloudflare + UptimeRobot task execution and evidence capture. - Linked checklist from `SETUP.md` Cloudflare section and TODO manual sections. - Did not mark manual dashboard items complete; checklist is preparation only. ## 2026-08-07 (continued 3) - Added `docs/operations/scaling-performance-playbook.md` covering manifest TTL tuning, TTFB baseline method, WebSocket/API benchmarking approach, cache ratio tracking, capacity triggers, and Phase 2/3 plans. - Updated TODO and BACKLOG to mark playbook creation done while keeping execution/measurement tasks pending. - Linked scaling playbook in `README.md` resources. ## 2026-08-09 - Added WebSocket benchmark summary helper `scripts/loadtest/summarize-artillery.ps1`. - Updated `scripts/loadtest/run-loadtests.ps1` to auto-generate `ws-chat-summary.txt` for `ws` and `all` scenarios. - Updated `scripts/loadtest/summarize-k6.ps1` to produce pipeline-friendly output and integrated automatic `admin-api-endpoint-summary.txt` generation. - Expanded `scripts/loadtest/README.md` with PowerShell-first artifact capture and helper usage for both ws and admin scenarios. - Updated `.gitignore` to ignore loadtest artifacts (`artifacts/` and `scripts/loadtest/artifacts/`). - Added artifact-to-worksheet field mapping section in `docs/operations/scaling-performance-playbook.md` so ws/admin worksheet entries map directly to generated summary files. - Updated `docs/DEVELOPMENT.md` and `.github/instructions/TODO.md` to mark ws/admin benchmark scaffolding complete while live benchmark execution remains pending. - Added `CHANGELOG.md` entry `1.0.10` summarizing loadtest helper automation and playbook mapping updates. ## 2026-08-09 (continued) - Completed Phase 1 (test fixtures): documented ffmpeg fixture-generation commands in `playlist_test.go` header comments (valid_720p30, invalid_h265, invalid_24fps). - Completed Phase 4 (R2 integration): - Enhanced `SyncToR2` in `playlist.go` to set CacheControl + ContentType based on file extension: - `.m4s`, `.ts`, `.mp4`, `.m4a` -> `public, max-age=31536000, immutable` + `video/MP2T` - `.m3u8` -> `public, max-age=2` + `application/vnd.apple.mpegurl` - unknown extension -> no cache headers - Added three tests: `TestSyncToR2` (segment upload with cache verification), `TestSyncToR2_ManifestCacheHeaders` (manifest upload), `TestSyncToR2_NoCacheHeadersForUnknownExt` (unknown extension). - All 17 playout tests pass (16 pass, 1 pre-existing skip). - Updated TODO.md: Phase 1 marked complete, Phase 4 partially complete (edge cache hit/miss remains manual). - Updated DEVELOPMENT.md: Test Fixtures marked complete, R2 Integration Test marked partially complete. ## 2026-08-09 (continued 2) - Completed Phase 2 chat tests in `frontend/src/main.test.ts`: - Presence updates: join/leave system messages add and remove users from presence list, sorted rendering. - Private DM flow: togglePrivateDM creates correct dm: room name from sorted usernames. - Message rendering: system messages, self messages (message-self), and other-user messages (message-other) all render correctly. - Total frontend tests: 27 passing (2 test files). - Marked Phase 4 "Document stubs/mocks" done (putObject injection pattern). - Updated TODO.md: Phase 2 chat tests checked, Phase 4 stubs checked. - Updated DEVELOPMENT.md: User Frontend Tests marked partially complete, R2 stubs checked. - Updated CHANGELOG.md with Phase 2 presence/DM/message tests. ## 2026-08-09 (continued 3) - Completed Phase 3 admin frontend tests in `frontend/src/admin.test.ts`: - Exported `savePlaylist` and `renderPlaylistSortable` from `admin.ts`. - Added playlist save test (verifies PUT /api/admin/playlist with JSON body). - Added playlist save error handling test (verifies failure status). - Added sortable rendering test (verifies index, paths, remove buttons, comment/blank line skip). - Total frontend tests: 31 passing (2 test files). - Updated TODO.md: Phase 3 playlist/dashboard/API integration all checked. - Updated DEVELOPMENT.md: Admin Frontend Tests marked partially complete. ## 2026-08-10 (continued 2) - Implemented STREAMING.md production-readiness gaps from plan `.hermes/plans/2026-08-10_164500-production-readiness.md`: - **Task 1-2**: Added `runID` (ISO timestamp format) and monotonic `segSequence` for globally unique segment naming (`r-{ISOTIME}/seg-{seq}.m4s`). Replaced `strftime` pattern with run ID-based path. - **Task 2**: Added `watchAndPublishSegments` using `fsnotify` for real-time per-segment R2 upload (~7s delay). Previously `syncLatestToR2()` only ran after FFmpeg exit. - **Task 3**: Added `publishManifest` with atomic `CopyObject` (temp key → final key) to prevent manifest referencing unconfirmed segments. - **Task 4**: Updated `manifestCacheControl` from `"public, max-age=2"` to `"public, max-age=1, s-maxage=2, must-revalidate"` per STREAMING.md. - **Task 5**: Added `hls.on(Hls.Events.ERROR)` handler in `main.ts` with bounded retries (5x), exponential backoff (2s→32s), reconnecting overlay (spinner + text). Added `showReconnecting`/`hideReconnecting` functions. - **Task 6**: Enriched `HealthHandler` with `run_id`, `active_item`, `playlist_revision`, `last_segment_seq`, `last_r2_pub`, `consecutive_failures`. Added "unhealthy" status when R2 publish is stale (>12s). - Files changed: `backend/playout/src/playlist.go`, `playlist_test.go`, `go.mod`, `frontend/src/main.ts`, `main.test.ts`, `style.css`, `index.html`. - Updated `.github/instructions/TODO.md`, `BACKLOG.md`, `MEMORY.md`, `DONE.md`. - Remaining: CORS on media.linearvoid.tv (Cloudflare R2 config, infrastructure). - Created `docs/operations/gitea-cloudflare.pages.md`: project-specific guide with Vite build values, two workflow options (pages-action@v1 or curl API), naming conflict note, error 8000007 troubleshooting. - Created `docs/operations/cloudflare-pages-setup.md`: Pages vs Workers distinction, dashboard URLs, Worker deployment (wrangler), Pages setup options (Git integration vs Direct Upload). - Updated `docs/SETUP.md` Cloudflare Pages section to reference the new guide. - Updated `docs/DEPLOYMENT.md` pipeline table to include `pages-deploy.yml` workflow. - Created `.gitea/workflows/pages-deploy.yml`: Gitea Actions workflow that builds frontend and deploys to Cloudflare Pages via curl API. - Updated `docs/STREAMING.md` (user edit). - All Go vet, Go tests, and frontend tests (31) passing.