docs: record the audio clock, and that CI is green
The e2e job passes on both engines for the first time, so the three files that describe it as red are wrong. Also records the two things that made it findable: the CI container is reproducible under Docker, and the app's own audio stack had to be the thing measured.
This commit is contained in:
@@ -56,11 +56,12 @@ reference, because you need them *before* the failure, not after.
|
||||
`--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.
|
||||
- **CI's `e2e` job is green on both engines** (54 specs each) since the
|
||||
container got an audio device that keeps time. If playback specs
|
||||
start failing there again, check the **`The sink plays at real time`**
|
||||
step first: ALSA's `null` plugin consumes 3000 ms of audio in 2.96 ms,
|
||||
so every track finishes instantly and the clock never moves — which
|
||||
reads as an app bug and cost two sessions of that suspicion.
|
||||
- **`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
|
||||
|
||||
@@ -1529,3 +1529,57 @@ Seven more things worth keeping:
|
||||
removed. Nothing is paid for it — the slot's light-DOM children are
|
||||
in the DOM either way; a conditional `<slot>` only stops projecting
|
||||
them.
|
||||
|
||||
## A dependency with a rate has to be checked at its rate
|
||||
|
||||
Same pass, after the plan's three landings: the `e2e` job's red history
|
||||
turned out to be one measurement being wrong, and the fix was worth the
|
||||
generalisation.
|
||||
|
||||
`ci.yml` had made ALSA's `null` plugin the container's default device,
|
||||
with a comment saying it "advances its pointer on a timer, so playback
|
||||
is consumed at real-time rate". It does not. Measured in the CI image
|
||||
under Docker, through beep and oto with the same `speaker.Init`
|
||||
arguments `player.InitSpeaker` uses:
|
||||
|
||||
| default device | 3000 ms of audio consumed in |
|
||||
|---|---|
|
||||
| `type null` | **2.96 ms** |
|
||||
| PulseAudio null sink | **3762 ms** |
|
||||
|
||||
A thousand times too fast. Every track finished instantly, so the
|
||||
position reset to zero while the UI kept interpolating, and three specs
|
||||
failed on a clock that never moved — 17–19 s adrift, which reads
|
||||
exactly like the `H-3` bug Phase 2 fixed. `check` and `e2e` are both
|
||||
green now, 54 specs on Chromium and 54 on WebKit.
|
||||
|
||||
Five things worth keeping:
|
||||
|
||||
- **A dependency with a *rate* needs a check at its rate.** Installing
|
||||
a sound device and asserting it exists is not the same as asserting
|
||||
it plays. The job now plays three seconds and fails if they take
|
||||
under two, in a step called "The sink plays at real time" — so the
|
||||
next regression names itself instead of surfacing three steps later
|
||||
as an app bug.
|
||||
- **A failure that succeeds quietly is the expensive kind.**
|
||||
`InitSpeaker` returns nil in ~3 ms against both devices. Nothing
|
||||
logged, nothing errored; the only symptom was arithmetic in three
|
||||
specs. Two sessions read that as a flake and one as a possible
|
||||
WebKit regression.
|
||||
- **The CI container is reproducible locally, and nobody had tried.**
|
||||
`docker run --rm ubuntu:24.04` reproduced the whole thing in four
|
||||
minutes and let the fix be verified — including under the private
|
||||
session bus and Xvfb `dev-headless.sh` runs the app in — before it
|
||||
was pushed. Every previous attempt to reason about this job reasoned
|
||||
from the *commits* instead, because the log looked unreachable
|
||||
(which it was not either).
|
||||
- **Test the stack you ship, not one that resembles it.** `aplay`
|
||||
showed the same 1000× gap and would have been enough to *diagnose*.
|
||||
It would not have shown that oto opens the pulse-backed device at
|
||||
all, which is the thing that had to be true for the fix to work; a
|
||||
fifteen-line Go program using the app's own `speaker.Init` did.
|
||||
- **The comment was the bug's hiding place.** "Measured: InitSpeaker
|
||||
succeeds in ~36 ms and all six playback specs pass" was true when
|
||||
written and had been carried forward through every subsequent read of
|
||||
that file, including two this session. A measurement in a comment
|
||||
needs the same expiry as one in a plan.
|
||||
|
||||
@@ -1924,12 +1924,26 @@ route from the albums grid to `track-details`.
|
||||
And two things this pass found rather than inherited:
|
||||
|
||||
- **Name the dialogs.** One helper, eight call sites.
|
||||
- **CI's e2e job cannot go green until the container's audio clock
|
||||
does.** Three specs assert on a position that does not advance
|
||||
there. Either the container gets a sink that really consumes, or
|
||||
those three specs learn to skip when it does not — but silently
|
||||
loosening a tolerance would delete the only assertions this repo has
|
||||
that the player tells the truth.
|
||||
|
||||
**CI is green, and the audio clock was the last thing between it and
|
||||
green.** Fixed the same pass: `ci.yml` used ALSA's `null` plugin on the
|
||||
belief that it paces, and it does not — measured in the CI image
|
||||
through beep and oto with `player.InitSpeaker`'s own arguments,
|
||||
**3000 ms of audio consumed in 2.96 ms**, against **3762 ms** through a
|
||||
PulseAudio null sink. Every track finished instantly, so the position
|
||||
reset to zero and three specs failed on a clock that never moved. It
|
||||
looked like a flake because `InitSpeaker` succeeds either way, in ~3 ms
|
||||
either way. `check` and `e2e` now both pass, **54 specs on Chromium and
|
||||
54 on WebKit** — the first fully green run this plan has had.
|
||||
|
||||
Two things about how that was found are worth carrying forward. The fix
|
||||
was **verified in `ubuntu:24.04` under Docker before it was pushed**,
|
||||
including under the private session bus and Xvfb `dev-headless.sh` uses
|
||||
— the CI container is reproducible locally, which nothing had tried.
|
||||
And the sink is now **checked like the dependency-with-a-rate that it
|
||||
is**: a step plays three seconds and fails if they take under two,
|
||||
because otherwise the failure surfaces three steps later as "the
|
||||
elapsed clock is 19 s adrift" and reads as an app bug.
|
||||
|
||||
## Phase 6 — Explore starts the conversation
|
||||
|
||||
|
||||
@@ -834,20 +834,18 @@ per-step status (which is how "WebKit was skipped" was found) and
|
||||
`GET /api/v1/repos/{owner}/{repo}/actions/jobs/{job_id}/logs` returns
|
||||
the whole log, with `Authorization: token $GITEA_TOKEN`.
|
||||
|
||||
**The `e2e` job is currently red on both engines, for one reason.**
|
||||
48 specs pass under Chromium and 48 under WebKit; the same three fail
|
||||
— `playback.spec`'s elapsed clock and two in `player-truth.spec` —
|
||||
because playback does not advance in the container: the UI
|
||||
interpolates while the backend position stays at zero, 17–18 s adrift.
|
||||
It is the audio device, not the renderer and not the app. Which means
|
||||
the paragraph below was measured once and is no longer true.
|
||||
|
||||
Two things the container needs that a developer machine does not. It
|
||||
has no PulseAudio socket, so `/etc/asound.conf` makes ALSA's `null`
|
||||
plugin the default device — that plugin is *supposed* to advance its
|
||||
pointer on a timer, so playback is consumed at real-time rate and the
|
||||
elapsed clock moves, which `e2e/specs/playback.spec.ts` asserts; it no
|
||||
longer does. And
|
||||
Two things the container needs that a developer machine does not.
|
||||
**It needs an audio device that keeps time**, because the player's
|
||||
position is derived from what has been consumed — so a device that
|
||||
accepts audio instantly makes every track finish instantly and the
|
||||
clock never move. That is what ALSA's `null` plugin does, contrary to
|
||||
a year of this file and `ci.yml` saying it paces on a timer: measured
|
||||
through beep and oto with `player.InitSpeaker`'s own arguments,
|
||||
**3000 ms of audio consumed in 2.96 ms**. It is a PulseAudio null sink
|
||||
now (the same 3000 ms takes 3762 ms), started in system mode because
|
||||
the job runs as root, with a step that plays three seconds and fails
|
||||
if they take under two — a dependency with a rate, checked like one.
|
||||
And
|
||||
`YJ_CORE_INDEX_URL` points at a dead address so no run fetches the real
|
||||
explore artifact, matching what `scripts/seed-sandbox.sh` already does.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user