tracker
All repositories: gitoria
10.1 KB
# Report 070 — tracker: t18 + t20 + t19 merged into main, migrated data kept, Hybriel 8efba065Repo: loreana:/media/STORAGE/projects/tracker.worldapi.org. Everything is committed on main (HEAD `8081350`). Not pushed, not deployed. The worktrees tracker-wt18, -wt20 and -wt19 and the branches t18, t20 and t19 are removed; they held nothing uncommitted (only `bin/` and `.scratch/`).## Commits (main)| Commit | What ||---|---|| `20e09d8` | merge t18 (#18) || `daf49fe` | merge t20 (#20/#21) || `749019b` | merge t19 (#19) || `46b2138` | migrated data is never destroyed || `1ad19c8` | Hybriel re-vendor, `&` on read-only lambda parameters, merge sort on /my/unwatched, deploy.sh runs all 3 gates || `8081350` | docs (README, STATUS, docs/kinds.md, docs/franchises.md), real-data scripts, tools |## Conflicts and how they were resolved (both sides kept everywhere)- **t18** conflicted in README, STATUS, show.hl, project.hl and browser.mjs.- `pageShowOf` (the small object from mission 018 (old 062)) now uses `summaryOf`.- Imports and boot steps are joined.- **t20** conflicted in README, STATUS, show.hl, project.hl, search.hl, components/search.hl, browser.mjs and faketmdb.mjs.- `slugInfoOf` sits beside 062's slug helpers.- The shared clock runs: adult backfill → repair → **kinds** → credits.- `withDetailsFields` also stores `tmdbType` and `kind`, so the delta light step and the #26 completion set them too.- The search import keeps both `path` and `details`.- browser.mjs: URLs changed to `/series/` and `/movies/`, h1 selectors to the typed `type-name`.- kinds.mjs: repair and credits switched off, and its fake TMDB name set to the seed's long name. Otherwise the #18 rename hit it.- **t19** conflicted in README, STATUS, show.hl, project.hl, browser.mjs and faketmdb.mjs.- The franchise/timeline pages get the typed headings "Franchises", "Franchise | …", "Timeline | …" (also the timeline editor).- Their title links go through `titlePath`.- The collection seed now waits for every other job, so it runs last.- franchises.mjs: URLs updated and 2 new checks (headings with their colours, mixed-timeline links).- deploy.sh now runs browser.mjs, kinds.mjs and franchises.mjs. The default ports of kinds and franchises moved to 8700–8710, because kinds' old defaults 8765/8766 are taken by other services on Loreana.## Step 2: migrated data is kept (conductor's change)- The one-time summary step now **moves** a copied summary to `migratedSummary` and empties `summary`. The marker is `summaries-moved.txt`.- On a migrated record (oldId not `tmdb-…`), the first time TMDB replaces a value the old one is kept, and only that first time:- shows: `migratedTitle`, `migratedGenres`, `migratedHomepage`, `migratedTagline`;- seasons and episodes (oldId not `tmdb-`/`tvmaze-`): `migratedTitle`, `migratedSummary`.- Not kept: status, counts, ids and the poster. They are TMDB's state and the sync has written them since #9.- **Gate**: 3 checks.- The first start moves the copied summary.- The renamed show, the renamed movie and episode 1x1 keep their old values.- A second rename keeps the first value.- **Real copy** (`tools/count-migrated.hl`):| Kept | Count ||---|---|| summaries | 9,647 || titles | 16 (e.g. "The Daily Show with Trevor Noah → The Daily Show") || genres | 71 || taglines | 16 || homepages | 4 || episode titles / summaries | 635 / 409 || season titles / summaries | 3 / 3 |## Hybriel- **Commit**: master `8efba065` (#126 f685f240, #48 4371b7aa).- `bin/hybriel` sha256 `50361e954e317a819aa58adfc2e3553f0b4b7adc82abd1fad79385d33b3d5b72`.- Plugins updated: core crypto data fetch fs http http1 mpackdb proc smtp time web.- The previous build is in `.scratch/pre-070/`.- **w068's `/shows/<slug>` route** still works: `page(m, s, host, hdrs)`, `hostOf`, `requestHeaders` and the sessions API are unchanged. The kinds gate (function-rendered show page: season toggle, Follow) passes.- **Lambda audit (#48)**, with `tools/lambda-audit.py`: 13 lambdas change a parameter without `&`.- details.hl: `withCredits` :236, `withDetailsFields` :265, `addSum` :359, `firstStep` :412.- franchises.hl: `storeOrder` :373.- people.hl: `startFill` :222, `fillStep` :269.- tmdbsync.hl: `mergeTvmaze` :279, `syncMovie` :442, `addTotals` :826.- Every caller uses the returned value or the stored record, so no fix was needed.- **Speed**: the copy per call was the real cost. A micro test passing a 20k-row list 2,000×: 15.5 s with the copy, 0.015 s with `&`.- All 319 read-only parameters got `&` (`tools/ref-params.py`).- /my/schedule went from 2.35 to 0.46 s, /my/unwatched from 13.7 to 5.7 s.- /my/unwatched also got one merge sort instead of n² inserts: 5.7 → 4.8 s.## Gate commands (final tree, new binary)```TRACKER_GATE_SHOTS=/tmp/w070/new-shots TRACKER_GATE_PORT=8751 TRACKER_GATE_IDENT_PORT=8752 TRACKER_GATE_CHROME=8753-8756 TRACKER_GATE_TMDB_PORT=8757 node tests/browser.mjs325 passed, 0 failedTRACKER_GATE_SHOTS=/tmp/w070/new-kinds TRACKER_GATE_PORT=8750 TRACKER_GATE_IDENT_PORT=8751 TRACKER_GATE_CHROME=8752-8756 TRACKER_GATE_TMDB_PORT=8757 node tests/kinds.mjs32 passed, 0 failedTRACKER_GATE_SHOTS=/tmp/w070/new-fr TRACKER_GATE_PORT=8750 TRACKER_GATE_IDENT_PORT=8751 TRACKER_GATE_CHROME=8752-8756 TRACKER_GATE_TMDB_PORT=8757 node tests/franchises.mjs50 passed, 0 failed```## Real data (copy of live storage/ 2026-10-02, real TMDB/TVmaze, all jobs, the daily run forced as a delta)**Jobs on the first start, about 50 min in all:**- The summary move: 16 s at boot.- Kind backfill: 1,789 titles in 16–21 min.- Collection seed: 4,774 movies in 32–37 min, giving 110 timelines.- Adult backfill, repair and credits: nothing to do.- One delta run: 261 titles in 6–10 min.- Without `sync-state.txt`, the first 04:00 run after the deploy is a full walk.**RSS old vs new** (controlled, one process at a time; "after jobs" = 200 page loads on a fresh process):| | after boot | jobs peak | 200 loads after the jobs | /my/unwatched ||---|---|---|---|---|| old 8590df63 | 8.0 GB | 15.2 GB | 8.0 → 12.2 GB | 1.15 s || new, final tree | 2.1 GB | 11.8 GB (median 2.7) | 2.1 → 2.8 GB | 4.8 s || new, `HL_GC_BYTES=256 MiB` | 2.7 GB | 12.4 GB at 24 min (run stopped) | 2.7 → 3.5 GB | 2.2 s || new, `HL_GC_BYTES=0` | 6.2 GB | — | 6.2 → 8.7 GB | 1.15 s |**Load times** (final tree, fresh process):- curl: `/` 0.02 s, lists 0.01–0.05 s, `/franchises` 0.04 s, a series 0.25–0.45 s, /my/series 0.4 s, /my/schedule 0.42 s, /my/unwatched 4.8 s.- Browser at 390/1280 (signed in as az5b2):| Page | Full load ||---|---|| lists | 39–146 ms || timeline | ~40 ms || First Contact with its widget | 136–346 ms || Picard (202 cast) | 192–368 ms || /my/series | 0.8–1.1 s || /my/unwatched | 5.6–6.1 s || the first `/` after boot | 15 s |Nothing scrolls sideways and there were 0 console problems.- I looked at the screenshots on Loreana: `/tmp/w070/real/*-{390,1280}.png` and the gate shots `/tmp/w070/new-*`.## Open points1. **Memory after the jobs (Hybriel, for the architect).** The process that ran the jobs keeps about 25 MB per page load: 3.0 → 8.1 → 13.6 → 18.9 GB over 600 loads, with /my/unwatched at 8.3 s. A fresh process keeps 3.5 MB per load; after one delta run, about 8 MB. The old binary kept about 21 MB per load from the start.- Recommendation: restart the container once after `collections done`. A daily restart after the 04:00 run is probably needed (not built). This is in README "Deploy".2. **GC by bytes is slow with a big heap (Hybriel).** With a 2+ GB live heap, every 64 MiB of plugin data triggers a full collection: /my/unwatched went from 1.2 to 4.8 s.- `HL_GC_BYTES` is not set. I tried 256 MiB (2.2 s), but that run reached 12.4 GB by 24 min and I stopped it. Its full peak was not measured. This is the creator's/architect's call.- Repro: `tests/realdata-070-bench.sh`.3. **systemd-oomd killed my first parallel run** (old + new at once) at 05:38. Loreana was above 90 % memory + swap, with other workers' tests running too. All numbers above come from later runs, one process at a time.4. **Port clash.** At the start, a tickets gate held 8720–8725. The lead moved me to 8750–8759.5. **No real "series page with a widget".** The seed only makes movie timelines. The gate covers a series with a widget; on real data I checked a movie with the widget and a series with its cast.6. Still open from earlier missions: TMDB type Video → Series? (#21), #18's 24 kept "own" summaries, #19's rename/delete not built.## Where I stopped (wrap-up, usage limit)The lead's messages about hybriel#127, the move to master d98926c6 and the port switch reached me only after this work was finished and committed. The tracker therefore runs on **8efba065**, not d98926c6.**Still to do after the reset:**1. Re-vendor to d98926c6 or a later HEAD: same procedure, `.scratch/pre-070` stays as the rollback copy.2. Re-run the 3 gates on 8750–8757.3. Run the big-page measurement, old vs new, 20 loads each, time and RSS:- /my/unwatched (~1,300 rows)- Picard with "Show all"- /series- a franchise index or timeline4. Re-run the RSS and job measurements: `tests/realdata-070-run.sh` and `tests/realdata-070-bench.sh` (STATUS "How to repeat"), real-data server on 8758.5. Check whether #127 explains the per-load growth and the slow /my/unwatched (open points 1 and 2).**Big-page numbers I already have.** Fresh process, curl, 10 loads per page, average:| Page | old 8590df63 | new 8efba065 (final tree, with `&`) ||---|---|---|| /my/unwatched (1,287 rows) | 1.15 s | 4.8 s || /series/Star-Trek-Picard (collapsed cast) | 0.055 s | ~0.25 s || /series | 0.014 s | 0.018 s || /my/series (126 rows) | 0.20 s | 0.40 s |- The process that had run the jobs got slower on every load, the #127 symptom: /my/unwatched 8.3 s, and RSS grew about 25 MB per load.- Not yet measured: Picard with "Show all" and a franchise index.## Leftovers- Nothing of mine is running. Ports 8720–8731 and 8750–8759 are free.- The data copies, the old-binary tree and its `.env` link are deleted. I never read `.env`.- Logs are in `.scratch/w070/`.
Branches
- mainmain branch
Latest commits
- e7305014tracker: report 032 (art + photos)mre
- fbb903cctracker#33/#37 (mission 032): a title without a TMDB poster gets its backdrop (w780, posterFromBackdrop, shown 2:3 centre-cropped); movies store runtime, the page shows release date + runtime; art backfill (public titles without poster file / movies without runtime) and person photo backfill (tmdbProfile / photoCheck) as the last start jobs (TRACKER_ART, TRACKER_PHOTOS; off in every gate start); gates 379/0, 32/0, 53/0, 229/0, 26/0, check-theme 0; live copy: art 4977 titles in 42 min (115 posters, 15 backdrops, 4609 runtimes), The Remaining shows its backdrop + 7 minmre
- 4ecc67b2tracker: STATUS/LOG for the t38 + t40 merge (gates 374/0, 32/0, 53/0, 229/0, 26/0, check-theme 0; live copy checks)mre
- e5945d2fMerge t40 (tracker#40 curated franchises, Franchises menu, superseded collections) into main: deploy.sh lists all six gates (browser, kinds, franchises, pager, franchiseseed, check-theme); search.hl keeps #37's personPhotoOf + #40's importWithCredits; pager gate runs with TRACKER_FRANCHISE_SEED=0; gates 374/0, 32/0, 53/0, 229/0, 26/0, check-theme 0mre
- b638e99dMerge t38 (tracker#38 pagination, #35 Returning/Airing label) into main: LOG/STATUS keep both sides; pager gate follows #37's /people (everyone, last updated first: seed updatedAt); gates pager 229/0, browser 374/0mre
- f8ffa4dbtracker: report 032 + The Remaining + #39mre
- 7565a863tracker: LOG timemre
- b10f00c8tracker#39: double episodes — migrated episodes whose TMDB id TMDB replaced are adopted by their number in the sync (old id -> migratedTmdbId); merge.hl step 3 merges each season's doubles at start (keeper: most watches > synced > first; watches moved/parked; tombstones into mergedEpisodes, nothing deleted); tools/count-duplicate-episodes.hl; gate fixture + paths-m039; live copy 850 -> 0 in 64 s; gates 373/0, 32/0, 52/0mre
- 8f1d4542tracker#40: superseded collections — a TMDB collection timeline whose titles are all in one curated timeline is hidden (supersededBy; kept: own page + editor finder), set by the collection seed when it makes one and by the curated build (lifted when the cover is gone); partly covered ones join that franchise; no second widget (First Contact: only Star Trek — Prime); gate franchiseseed 26/0, browser 365/0, kinds 32/0, franchises 53/0, check-theme 0; real copy 24 supersededmre
- 9448d643tracker#35 follow-up (mission 033): TVmaze 'Running' is labelled 'Returning', or 'Airing' while a non-special episode of the two newest seasons is released within today +-7 days (data unchanged); gate fixtures Running/Airing/Aired + a special; browser 366/0, kinds 32/0, franchises 52/0, pager 229/0, check-theme 0mre
- 7d4b293dtracker#40: "Franchises" in the main menu (desktop header after People, phone sidebar) → /franchises, marked on franchise and timeline pages; gates 365/0, 32/0, 53/0, 24/0, check-theme 0mre
- 8751adb8tracker: report 032mre
- 9bce1f65tracker mission 032: STATUS gate files + the hour-boundary flakemre
- 718bfb89tracker#37 (mission 032): /people = everyone, last updated first (updatedAt stamped by the person fill; view built at boot, touched people first at once), photo + name tiles (person colour) with the /movies pagination, /people/<letter> removed; photo = our file, tmdbProfile, a cast/crew entry's profile (in-memory map at boot), else the new 'no photo' placeholder; new cast/crew/created_by people keep tmdbProfile; search people rows with the photo; /settings = the heading only; util.hl sortDesc starts from sorted runs (same result, 105k: 1.6 s -> 0.15 s); gates 369/0, 32/0, 52/0, check-theme 0; README/STATUS/LOGmre
- 93dfb0batracker#40 (mission 034): the curated franchises — data/franchises.json (17 franchises, 31 timelines, 285 TMDB titles, movies + series, in-universe/release order, 12 TMDB collections attached); lib/franchiseseed.hl + jobs.hl franchiseSeedTick (last start job, imports missing titles via details.hl importWithCredits = the search's Add, one per step paced, then one build; franchiseseed.db: editor changes win, the creator's same-name franchise adopted / timeline left alone, 404 remembered, resumable, idempotent); timeline heads 'N titles · in-universe order' (orderKind) and wrap on a phone; series pages show the widget; new gate tests/franchiseseed.mjs (5th in deploy.sh), the others run with TRACKER_FRANCHISE_SEED=0; gates 365/0, 32/0, 52/0, 24/0, check-theme 0; real copy 196 imported, 0 failed, 7 min, restart unchanged=31mre
- 03ec792ftracker#38 (mission 033): pagination goes exactly to the clicked page — tilelist read the clicked button's text after pagination.hl's own handler had rebuilt the buttons (real clicks only); now li.current, else the button's own text; new gate tests/pager.mjs (5 lists x 11 pages, 390/1280, real + script clicks, Back/Forward) 229/0; browser 365/0, kinds 32/0, franchises 52/0, check-theme 0mre
- 96ba683adeploy.sh: a gate without a 'passed,' line (check-theme) no longer ends the scriptmre
- eb3b9205tracker: report 031mre
- 9b5d2e89tracker mission 031: README (What it does, Test: four gates + the #32 checks, Files: theme/, new pages), STATUS (real copy, A/B load, how to repeat, open points), LOGmre
- 39950e4ctracker#32 (mission 031): the WorldAPI theme (theme/ vendored verbatim from layouts.worldapi.org 85b5654; styles.hl inherits it: accent green-dark, type colours 1-6; own base/header rules, row lines, genre-pill and inverted-button frames removed, the season foldable keeps its line; check-theme 21 -> 0, 4th deploy gate; main actions class primary) and the #32 header (theme AppHeader/MainMenu/UserMenu/Sidebar/ContentFirst: desktop brand, search, Series|Shows|Movies|Genres|People, user icon with Unwatched..Settings, Logout; signed out the ident selector, phone the iD icon dropdown; phone menu in the sidebar overlay; marked entry by :has); /find -> /search/<q>, /genres, /people(/<letter>), /settings; main { ContentFirst { slot } } works around the hl:web one-line slot bug; gates 365/0, 32/0, 52/0, check-theme 0mre