From 425dd7c158017a0014036c68cef35c0d410c004f Mon Sep 17 00:00:00 2001 From: Logan Date: Wed, 12 Aug 2026 12:42:15 -0400 Subject: [PATCH] docs: record the third Phase 5 pass, and read the CI log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The e2e failure two sessions could not diagnose is the container's audio clock, on both engines — 48 specs pass under Chromium and 48 under WebKit, failing the same three. Nothing in last pass's dialog, focus or role work is WebKit-specific. Also records what got in the way of knowing that: gitea_ci's job-log endpoint 404s on this build while the REST API answers fine, and the WebKit step had been skipped on every red run. --- .pi/skills/yellowjacket-dev/SKILL.md | 30 ++++- .planning/NOTES.md | 92 ++++++++++++++ .../plans/active/007-ui-reconciliation.md | 114 ++++++++++++++++++ CLAUDE.md | 85 ++++++++++++- 4 files changed, 315 insertions(+), 6 deletions(-) diff --git a/.pi/skills/yellowjacket-dev/SKILL.md b/.pi/skills/yellowjacket-dev/SKILL.md index ee2ea14..63c26d2 100644 --- a/.pi/skills/yellowjacket-dev/SKILL.md +++ b/.pi/skills/yellowjacket-dev/SKILL.md @@ -39,8 +39,28 @@ reference, because you need them *before* the failure, not after. `config.toml` and DB rows — a hand-built `YJ_HOME` is a second description of a valid one and will drift. `make sandbox-seed` drives the real `AddLibrary` binding and waits for the real scan. +- **…and a seed freezes every default it has already persisted.** + Changing a default in `backend/config` (or `backend/tracklist`) is + invisible against an existing seed, whose `config.toml` holds the old + value — while CI builds its seed by running the app and therefore + tests the *new* one. Re-seed before believing either. +- **A `wa-dialog` is awkward to locate, in three ways.** The host is + `display: contents`, so the element carrying your testid always + reports hidden; the visible thing is the native `` in its + shadow root. The slotted content is in the *host's* shadow root, not + in that dialog's subtree, so `toContainText` on the dialog sees only + its chrome. And the dialog has **no accessible name** — Web Awesome + never wires `label` to `aria-labelledby` — so + `getByRole('dialog', {name})` matches nothing. - **Playwright's WebKit does not run on Arch** (Ubuntu-only libs). - `--browser=webkit` is CI-only; local work is Chromium. + `--browser=webkit` is CI-only; local work is Chromium. CI runs it + with `if: !cancelled()` so a chromium failure does not silently + skip it, which it did for two sessions. +- **CI's `e2e` job is red for a reason that is not yours.** Three + playback specs fail in the container on both engines (48 pass on + each) because the position never advances there — an audio-device + problem, not a renderer or app one. Read the per-step status before + assuming your change did it. - **`make e2e` needs `SEED=default`.** Its specs assert on fixture content — unicode tracks, the fixture artists, a known playable file. Run against the `bulk` seed a measurement session left behind and 13 @@ -66,6 +86,14 @@ reference, because you need them *before* the failure, not after. old behaviour. `make dev-headless` prints the esbuild error; a reload does not. One way to cause one is a stray backtick inside a comment in a `css` tagged template literal, which ends the literal. +- **A failing CI job's log is reachable even when `gitea_ci job_logs` + says it is not.** That endpoint 404s on this Gitea build. The REST + API answers, with the `GITEA_TOKEN` already in the environment: + `/api/v1/repos/yonlu/yellowjacket/actions/runs//jobs` for + per-step status (this is how "the WebKit step was *skipped*" was + found) and `/api/v1/repos/yonlu/yellowjacket/actions/jobs//logs` + for the whole log. Two sessions reasoned about the e2e failure from + the commit list because the first tool's 404 read as "out of reach". - **`npx tsc --noEmit` is part of the gate, and nothing else runs it.** CI does (`.gitea/workflows/ci.yml`), and it typechecks `frontend/test/` — which `make lint`, `make test`, `make ui-test` and diff --git a/.planning/NOTES.md b/.planning/NOTES.md index 2d157cf..5caa8cb 100644 --- a/.planning/NOTES.md +++ b/.planning/NOTES.md @@ -1437,3 +1437,95 @@ changed focus management, dialog modality and roles, which is exactly the area where the two engines differ. Treat the WebKit half as unverified rather than as the known audio-clock flake until someone reads the log. + +## "Out of reach" is a claim about a tool, not about the information + +Plan 007 phase 5, third pass: Settings' keyboard reach, the `?` overlay +and the arrows, an Album column, and the CI question two sessions had +recorded as unanswerable. + +The generalisation the pass adds: **when a tool says it cannot get +something, that is a fact about the tool.** `gitea_ci job_logs` returns +a 404 on this Gitea build and says so clearly, and two sessions read +that as "the log is out of reach from here" and reasoned from the +commits instead. The REST API on the same server answers fine, with the +token that was already in the environment: + +``` +GET /api/v1/repos/{owner}/{repo}/actions/runs/{run}/jobs # per-step status +GET /api/v1/repos/{owner}/{repo}/actions/jobs/{id}/logs # the whole log +``` + +Ten minutes, after a session and a half of careful hedging about what +the failure might be. The hedging was correct — it just cost more than +checking would have. + +What the log said, in two parts: + +- **The failure is the container's audio clock**, on both engines. Not + a regression in the dialog/focus/menu work, which was the live worry. + `playback.spec`'s elapsed time and two `player-truth.spec` cases: the + UI interpolates while the backend position stays at zero, 17–18 s + adrift. `ci.yml` says the ALSA null plugin advances at real time; it + was measured once and no longer does. +- **WebKit had never run.** The step had no `if:`, so a chromium + failure skipped it — `conclusion: skipped`, in the same JSON that + held the answer. The previous pass's "treat the WebKit half as + unverified" was more literally true than intended: the one place + WebKit gets any coverage had produced no signal at all for as long + as chromium had been red. With `if: !cancelled()` it runs, and both + engines pass 48 and fail the same three. + +Seven more things worth keeping: + +- **A reproduction of the *fix* can be as invalid as one of the bug.** + After making `←`/`→` reach the player again, the check measured zero + `Player.Seek` calls — the same answer as the broken build, because + nothing was playing and the dispatch records nothing with no track + loaded. Seventh costume of this plan's most-repeated trap, and the + first on the *after* side: "the fix did nothing" and "the probe + cannot see anything" produce identical output. +- **A shortcut a dialog swallows is a promise the shortcut layer + cannot keep.** The `?` overlay was written as a toggle. It cannot + be: `focusedControlOwnsKey` yields every unmodified key to anything + inside an open dialog, so the second `?` never reaches the service. + Escape closes it, as it does every dialog here. The rule that + protects focused controls is the rule that forbids the toggle, and + an e2e spec is what noticed. +- **Every `wa-dialog` in this app is an unnamed dialog.** `a11y.md` + lists them under "what is already correct" and says every one passes + a `label` — true, and the label never reaches the accessibility tree. + Web Awesome renders it into an `

` in the same shadow + root as the `` and never sets `aria-labelledby`. Found by + writing `getByRole('dialog', {name})` and getting nothing. Two more + facts about locating one, both costing a spec run: the host is + `display: contents` so it always reports hidden, and the slotted + content lives in the *host's* shadow root, not in the dialog's + subtree. +- **A fix can be right while the finding's stated benefit is wrong.** + `H-15` wants an Album column so the three `Tideline / Aurora Fields / + 00:06` rows can be told apart. They are duplicates of the same + album, so they still read identically; what distinguishes them is + the duplicate-detection feature or a path column. The column is + still the right default for every other row. Visible only in a + screenshot — nothing failed, and the finding's sentence would have + been ticked off without looking. +- **A section of controls that do nothing is worse than admitting the + section does not exist.** `H-22` asks for a Playback/Audio section; + `backend/config` has no output device, gapless, crossfade or replay + gain to expose. Same judgement as "Artists cannot have a sort + *select*" two passes ago, and the same tell: the audit describes the + UI it wants without checking what the model carries. +- **A default the seed has already persisted is not a default you can + see.** Changing `tracklist.DefaultColumns` changed nothing in the + running app, because `.dev/seeds/default.tar` carries a `config.toml` + from before it — while CI builds its seed by running the app and + would have exercised the *new* one. A local run and a CI run testing + different defaults is worse than either being wrong. `make + sandbox-seed NAME=default`. +- **`aria-controls` has to name an element that exists**, which decides + how a disclosure renders: `config-section`'s body is rendered + unconditionally and toggled with `hidden` rather than added and + removed. Nothing is paid for it — the slot's light-DOM children are + in the DOM either way; a conditional `` only stops projecting + them. diff --git a/.planning/plans/active/007-ui-reconciliation.md b/.planning/plans/active/007-ui-reconciliation.md index 3eab922..353d62e 100644 --- a/.planning/plans/active/007-ui-reconciliation.md +++ b/.planning/plans/active/007-ui-reconciliation.md @@ -1817,6 +1817,120 @@ and removing the file is a delete-your-music button one keystroke from a focused row. The honest interim is to stop advertising the binding in Settings; that is not done yet either. +--- + +### Phase 5 — the third pass: Settings, the key story, the small ones, and the CI answer + +Three independently landable pieces of item 4, plus the question that +was supposed to be first and turned out to be answerable in ten +minutes. + +- **`a11y.1` / `a11y.2` / `H-22` — Settings is reachable.** + Reproduced exactly as written: seven `config-section` headers, seven + bare `
`s, `role` and `tabindex` null on every one, all + collapsed. They are `