From 7e4e60beb20c3520d3af3acd38be76bf2e58b7cc Mon Sep 17 00:00:00 2001 From: Bakhomious Basta Date: Fri, 30 Oct 2026 12:18:57 +0100 Subject: [PATCH] docs: mark homelab-games-covers done codedogapp/homelab#46 gave the laptop's games their covers, now that the user's Twitch app exists (decision 309), and IGDB has been checked live (decision 305). --- docs/plan.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plan.md b/docs/plan.md index ef851ca..4381ca9 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -191,7 +191,7 @@ The v1.2 design in §4 to §6 stays as reference. A piece of it is built only wh | `shared-page-status` | The PRs, Time, Nudge and Todos pages draw the line that takes their sections' place, such as "Bitbucket isn't set up.", from one global class, for the GitHub page's, its fifth user; on phones, the Nudge page's line now leaves a section's 48 px below it. The seventh of `github-widgets`' nine steps (decision 206) | Done (#187) | | `github-page` | The app shows the three lists on a page of their own at `/github`, as the user chose. The eighth of `github-widgets`' nine steps (decision 207) | Done (#191) | | `github-attention` | The `github` service answers the attention contract, so the Home's "Needs you" lists my open PRs, the PRs that wait for my review and the issues assigned to me, as the user chose; its new source, the first change to a contract in use, brings `proto:breaking` into `check`. The last of `github-widgets`' nine steps (decision 208) | Done (#194) | -| `games-exophase` | The games widgets from Exophase (§8.2 Phase 5), by a session of their own in `../bakhyard-games/`, which adds its steps' rows under this one (decision 195) | Done (#188); the laptop's covers wait for a Twitch app (decision 309) | +| `games-exophase` | The games widgets from Exophase (§8.2 Phase 5), by a session of their own in `../bakhyard-games/`, which adds its steps' rows under this one (decision 195) | Done (#188) | | `games-plan` | `games-exophase` splits in eleven steps: the Exophase client, the cache, the service, the Twitch token, the IGDB search, the covers, the laptop, the gateway, the page and its covers; the games list, the covers' matches and the Twitch token stay in memory. The first of `games-exophase`'s eleven steps (decision 300) | Done (#168) | | `exophase-client` | The `games` service's Exophase client: the games I last played since a given time, the last played first, each with its platforms, playtime and trophies, from the games list's pages until one ends before that time, four at most; a 403 from Cloudflare's challenge says so. The second of `games-exophase`'s eleven steps (decision 301) | Done (#172) | | `games-cache` | The `games` service polls Exophase only on request: the first request waits for the first poll, later ones get the latest list at once and start a poll in the background once the list is an hour old; after a failed poll the last good list stays, and the next poll waits 5 minutes, twice as long after each failure in a row, up to 6 hours. The third of `games-exophase`'s eleven steps (decision 302) | Done (#175) | @@ -1309,11 +1309,11 @@ Every item is pending unless it says done. The service an item lands in is in br - `twitch-token`: the service gets a Twitch app token for IGDB, keeps it and renews it before it expires (decision 304). Done (#181). - `igdb-search`: the service's IGDB client finds a title's cover with a filtered search and an exact-name fallback (decisions 68 and 305), within IGDB's 4 requests a second. Done (#183). - `games-covers`: each game in the answer carries its IGDB cover; each title is matched once and the match kept for a week (decision 306). Done (#186). - - `homelab-games`: done (codedogapp/homelab#44). In the homelab repo, `games` runs on the laptop with its setting, and the gateway's peers name it. Its games come without covers until there's a Twitch app (decision 309). + - `homelab-games`: done (codedogapp/homelab#44). In the homelab repo, `games` runs on the laptop with its setting, and the gateway's peers name it. Its games came without covers until `homelab-games-covers` (decision 309). - `games-gateway`: the gateway forwards `/api/games` to `games`. Done (#188). - `games-page`: the Games page lists the games, and marks them stale when the latest fetch failed (decisions 67, 307); the Games card's description in the app becomes §7's. Done (#190). - `games-page-covers`: the Games page shows each game's cover (decision 308). Done (#193). - - `homelab-games-covers`: in the homelab repo, `games` gets a Twitch app's client ID and secret, so the laptop's games come with their covers. Waits for the user's Twitch app (decision 309). + - `homelab-games-covers`: done (codedogapp/homelab#46). In the homelab repo, `games` gets the Twitch app's client ID and secret, so the laptop's games come with their covers (decision 309). **Phase 6: vault edits and Copilot** @@ -1872,7 +1872,7 @@ Decisions 300 to 399 are the `games-exophase` session's. - **IGDB's limits**: requests go one at a time, through a one-slot channel, and each starts at least 250 ms after the previous one began, so IGDB gets at most 4 a second and one open request, within its 4 a second and 8 open. A call whose context ends while it waits returns the context's error. - **A refused token**: when IGDB answers 401, the client drops the token and asks once more with a new one. A second 401 is an error, so a client ID that doesn't fit its token can't make the client ask Twitch without end. - **Failures**: errors start with `find the cover of "":`, then `ask IGDB:` and the status or the transport's error, `read IGDB's answer:`, or the token's error. The client retries no 429 and no 5xx: `games-covers` keeps no error, so a later fetch asks again. No error shows the token, which travels only in a header. - - **Not yet checked live**: the queries and headers follow the spike, IGDB's docs, and another IGDB client's working use of `name ~` without wildcards. IGDB itself waits for the user's Twitch app, which `games-covers` needs. + - **Checked live** (2026-10-30), once the user's Twitch app existed: the real Twitch and IGDB found a cover for each of the user's three games. The queries and headers follow the spike, IGDB's docs, and another IGDB client's working use of `name ~` without wildcards. - **Rejected**: the exact-name search first, which would take any record with that name, such as an edition or a bundle, before the filtered search's better match; the fallback only when the filtered search finds nothing, which would keep the spike's 15th title's wrong match; requests in parallel up to IGDB's 8 open, which would need a rate limiter to save a few seconds on a dozen titles, each matched once; `golang.org/x/time/rate`, a new module for one gap; stripping the quotes from a title rather than escaping them, which would change the exact name; covers that Bakhyard stores and serves, which IGDB already serves. 306. **The covers** (`games-covers`): the lead's choices (2026-10-30), for the user to review. @@ -1900,7 +1900,7 @@ Decisions 300 to 399 are the `games-exophase` session's. - **IGDB**: the browser loads the covers from IGDB's image host, which the gateway's Content Security Policy allows under `img-src https:`; the gateway's `Referrer-Policy: same-origin` keeps Bakhyard's address from IGDB. - **The demo**: the end-to-end tests and the screenshots show covers drawn as SVG, since IGDB's are third-party material and the repo is public. With the demo games, they live in `e2e/games.ts`, since `e2e/demo.ts` had reached its 200 lines. - **Rejected**: the cover before the day, where every other list starts its rows with the label; a bigger cover, such as 64 by 91, which would make every row taller than its text; leaving the column out when no game has a cover, as when IGDB isn't set up, which would change the rows' shape with the service's settings; greyscale covers, since §7's monochrome is for Bakhyard's own colours; an `<img>`, with its broken-image icon, or with an error handler that swaps in the blank, which adds state for what a background does alone; the title as the cover's `alt`, which a screen reader would read twice; IGDB's `cover_small`, 90 by 128, which is blurry at 2x and would have the page rewrite the service's address; `loading="lazy"`, which a background doesn't have and a list of 14 days doesn't need. -309. **The laptop without covers for now** (`homelab-games`): the user's choices (2026-10-30). The user has no Twitch app yet, so codedogapp/homelab#44 runs `games` with the Exophase profile alone, and the games come without covers, on the laptop as on the Mac. Once the app exists, `homelab-games-covers` adds its client ID to the Secret `games-settings`, beside the profile, rather than to `games.yaml`, and its secret to a Secret `games-secrets` mounted at `/secrets`. +309. **The laptop without covers for now** (`homelab-games`): the user's choices (2026-10-30). The user has no Twitch app yet, so codedogapp/homelab#44 runs `games` with the Exophase profile alone, and the games come without covers, on the laptop as on the Mac. Once the app exists, `homelab-games-covers` adds its client ID to the Secret `games-settings`, beside the profile, rather than to `games.yaml`, and its secret to a Secret `games-secrets` mounted at `/secrets`. The app came the same day, and codedogapp/homelab#46 added it. - **Rejected**: holding codedogapp/homelab#44 and #188 until the app exists, which would keep the games off the laptop for the sake of their covers. Decisions 400 to 499 are the vault session's: `vault-edit-sync`, then `copilot-planner`.