#73 puts #24 first in Phase 2 and hangs the rest of the phase off it, and its
own Direction asks for a design pass — so the first deliverable is a plan
document, not a patch. .planning/plans/active/018-supported-sizes-and-the-queue-model.md
is the decision; the code is the part of it that could land now.
Commits
commit
what
issue
cee43e5
the plan: size matrix, queue model, and the two scope decisions
On Playlists, against the running app, sweeping the viewport with the queue
open — five things that are not in the issue:
The header clips at the enforced minimum with the queue closed. 800×600 is
the only size this app promises, and "New Smart Playlist" loses 4px of 162
there. The queue makes it dramatic; it is not the cause.
900×600 is worse than 800×600. The sidebar collapses to icons below 900,
so the main panel is 843px at 899 and 700px at 900. The worst desktop case is
the top of the Compact band, not the enforced floor — so every viewport list
that stopped at "the minimum" was missing its own worst case.
At 320px the main panel was 0px. The panel is flex-shrink: 0 in the flow
of .content-area, so an open queue was paid for by the content. Not
degraded — gone. 69px at 390px.
Only Playlists overflows — all ten primary views swept at two widths.
Both reasons in MinWidth's comment had expired (the subtitle is display: none from 899 down; the sidebar host scrolls).
Main panel width with the queue open, before → after:
viewport
before
after
mode
1280×800
759
759
inline
1100×720 (default window)
579
579
inline
1024×768
503
503
inline
900×600
379
700
overlay
390×780
69
390
overlay
320×600
0
320
overlay
The decision worth reviewing
The mode is computed, not breakpointed — available - panelWidth < 480,
where available is .content-area's width. A media query cannot express it:
the panel is drag-resizable 200–500px and persisted, so a viewport breakpoint
assumes the default 320 and is wrong by up to 180px for a user who widened it,
in the direction that hurts. Widening the panel at a fixed window size must flip
it, and that is the component test that matters.
480 is a judgement and says so. There is no cliff — the track list rescales
continuously (213px → 124px columns, no row overflow) — so it is anchored to
keep the default 1100px window inline and put every measured-broken case on the
overlay side.
What this deliberately does not fix
#69 is still live, and the plan's first draft was wrong to claim otherwise.
At 900×600 open and closed are now identical (main 700, one action clipped)
where open used to be main 379 with all three clipped — so the queue's
contribution is gone, but the header still overflows on its own. It cannot be
fixed in page-header alone: actions arrive through <slot name="actions"> as
arbitrary light-DOM markup with their own handlers, so a "More actions" menu
needs an actions API (data, not markup) across all three hosts that slot
them. That is its own branch, next.
#55 is unblocked (Status/Blocked dropped, with the measurement on it). The
overlay is a presentation of the same component, not a fork, so its roving tab
stop, Alt+Arrow reorder, drag reorder and selection semantics are untouched —
which is what its "one component, two mount points" Direction asks for.
#12 is not coupled to this. A very small window becomes the phone layout,
which already exists and is already tested, rather than a mini-player: #12 is a
second always-on-top window, and making it a mode of the main window would
discard navigation state on a resize and put its own process-level MPRIS
question on a path a drag can trigger.
Verification actually run
make lint — 0 issues, all three build configurations.
make test — green, all three configurations.
make ui-test — 80 files, 904 tests (6 new).
frontend/node_modules/.bin/tsc --noEmit and e2etsc --noEmit — clean.
The frontend one caught four nullability errors in the new component test that
no test tier runs.
make e2e — 126 passed, 1 failed: view-lifecycle.spec.ts's autotag skip,
which is the documented state-spending flake. Verified pre-existing by
restarting the app and re-running that spec alone: 4/4 pass.
make css-check, make skill-check, make bindings-check — clean.
Screenshots read at each band, which is the half none of the above can
see: layout-overflow.spec.ts asserts the shell needs no sideways scrolling
and passes on a build whose header clips its own buttons. The scrim was
checked by sampling pixels (33,37,41 → 18,20,23) rather than by eye, because
it is subtle on a dark ramp by arithmetic.
New specs: e2e/specs/queue-overlay.spec.ts (11) and frontend/test/components/queue-overlay-mode.test.ts (6). The component ones
were checked against the old behaviour — 4 of 6 fail on it, including the drag
case; the 2 that pass are the inline ones, correctly.
Filed along the way
#130 — issue.sh claim is unusable: it needs read:user for one lookup
nothing else needs, so the one step required before the first edit is blocked
by its own tooling.
#131 — codegen-check fails on any unstaged change and blames the code
generators.
Commented on #128 with a pre-push sighting of the ui-test flake (it
rejected this push once, then passed unchanged).
#73 puts #24 first in Phase 2 and hangs the rest of the phase off it, and its
own Direction asks for a design pass — so the first deliverable is a plan
document, not a patch. `.planning/plans/active/018-supported-sizes-and-the-queue-model.md`
is the decision; the code is the part of it that could land now.
## Commits
| commit | what | issue |
|---|---|---|
| `cee43e5` | the plan: size matrix, queue model, and the two scope decisions | #24 |
| `637bb61` | the queue overlays the content instead of taking its width | #24 |
| `0f080ae` | CLAUDE.md gains the bands; NOTES.md gains the measurements | #24 |
| `d9d3b63` | 900×600 added to the shell specs; `MinWidth`'s stale comment replaced | #24 |
## What was measured
On Playlists, against the running app, sweeping the viewport with the queue
open — five things that are **not** in the issue:
- **The header clips at the enforced minimum with the queue closed.** 800×600 is
the only size this app promises, and "New Smart Playlist" loses 4px of 162
there. The queue makes it dramatic; it is not the cause.
- **900×600 is worse than 800×600.** The sidebar collapses to icons *below* 900,
so the main panel is 843px at 899 and 700px at 900. The worst desktop case is
the top of the Compact band, not the enforced floor — so every viewport list
that stopped at "the minimum" was missing its own worst case.
- **At 320px the main panel was 0px.** The panel is `flex-shrink: 0` in the flow
of `.content-area`, so an open queue was paid for by the content. Not
degraded — gone. 69px at 390px.
- **Only Playlists overflows** — all ten primary views swept at two widths.
- **Both reasons in `MinWidth`'s comment had expired** (the subtitle is
`display: none` from 899 down; the sidebar host scrolls).
Main panel width with the queue open, before → after:
| viewport | before | after | mode |
|---|---|---|---|
| 1280×800 | 759 | 759 | inline |
| 1100×720 (default window) | 579 | 579 | inline |
| 1024×768 | 503 | 503 | inline |
| 900×600 | **379** | **700** | overlay |
| 390×780 | **69** | **390** | overlay |
| 320×600 | **0** | **320** | overlay |
## The decision worth reviewing
**The mode is computed, not breakpointed** — `available - panelWidth < 480`,
where `available` is `.content-area`'s width. A media query cannot express it:
the panel is drag-resizable 200–500px and persisted, so a viewport breakpoint
assumes the default 320 and is wrong by up to 180px for a user who widened it,
in the direction that hurts. Widening the panel at a fixed window size must flip
it, and that is the component test that matters.
**480 is a judgement and says so.** There is no cliff — the track list rescales
continuously (213px → 124px columns, no row overflow) — so it is anchored to
keep the default 1100px window inline and put every measured-broken case on the
overlay side.
## What this deliberately does not fix
**#69 is still live**, and the plan's first draft was wrong to claim otherwise.
At 900×600 open and closed are now *identical* (main 700, one action clipped)
where open used to be main 379 with all three clipped — so the queue's
contribution is gone, but the header still overflows on its own. It cannot be
fixed in `page-header` alone: actions arrive through `<slot name="actions">` as
arbitrary light-DOM markup with their own handlers, so a "More actions" menu
needs an actions **API** (data, not markup) across all three hosts that slot
them. That is its own branch, next.
**#55 is unblocked** (`Status/Blocked` dropped, with the measurement on it). The
overlay is a presentation of the same component, not a fork, so its roving tab
stop, Alt+Arrow reorder, drag reorder and selection semantics are untouched —
which is what its "one component, two mount points" Direction asks for.
**#12 is not coupled to this.** A very small window becomes the phone layout,
which already exists and is already tested, rather than a mini-player: #12 is a
second always-on-top window, and making it a mode of the main window would
discard navigation state on a resize and put its own process-level MPRIS
question on a path a drag can trigger.
## Verification actually run
- `make lint` — 0 issues, all three build configurations.
- `make test` — green, all three configurations.
- `make ui-test` — 80 files, **904** tests (6 new).
- `frontend/node_modules/.bin/tsc --noEmit` and `e2e` `tsc --noEmit` — clean.
The frontend one caught four nullability errors in the new component test that
no test tier runs.
- `make e2e` — 126 passed, 1 failed: `view-lifecycle.spec.ts`'s autotag skip,
which is the documented state-spending flake. Verified pre-existing by
restarting the app and re-running that spec alone: 4/4 pass.
- `make css-check`, `make skill-check`, `make bindings-check` — clean.
- **Screenshots read at each band**, which is the half none of the above can
see: `layout-overflow.spec.ts` asserts the *shell* needs no sideways scrolling
and passes on a build whose header clips its own buttons. The scrim was
checked by sampling pixels (33,37,41 → 18,20,23) rather than by eye, because
it is subtle on a dark ramp by arithmetic.
New specs: `e2e/specs/queue-overlay.spec.ts` (11) and
`frontend/test/components/queue-overlay-mode.test.ts` (6). The component ones
were checked against the old behaviour — 4 of 6 fail on it, including the drag
case; the 2 that pass are the inline ones, correctly.
## Filed along the way
- **#130** — `issue.sh claim` is unusable: it needs `read:user` for one lookup
nothing else needs, so the one step required before the first edit is blocked
by its own tooling.
- **#131** — `codegen-check` fails on any unstaged change and blames the code
generators.
- Commented on **#128** with a pre-push sighting of the `ui-test` flake (it
rejected this push once, then passed unchanged).
Closes #24
#24 asks for a design pass, and #73 hangs the rest of Phase 2 off the
answer, so the decision is written down before any CSS moves.
Measured against the running app, and five things are not in the issue:
the Playlists header clips at 800x600 with the queue *closed* — the
minimum window is the only size this app promises; 900x600 is worse
than 800x600, because the sidebar expands at 900, so the worst desktop
case is not the minimum and every test that stops at the minimum misses
it; at 320px with the queue open the main panel is 0px wide, because
the panel is in the flow rather than over it; only Playlists overflows,
so #69 is one view's action set and not a systemic header failure; and
both reasons in MinWidth's comment describe mechanisms that no longer
exist.
The queue's mode cannot be a media query: its width is drag-resizable
between 200 and 500px and persisted, so a fixed breakpoint assumes the
default 320 and is wrong by 180px in the direction that hurts. It is
computed from the measured widths instead.
#69 stays its own PR on a finding rather than an estimate: page-header
cannot collapse actions that arrive as arbitrary light-DOM markup
through a slot, so the fix needs an actions API across all three hosts.
A very small window becomes the phone layout, which already exists and
is already tested, rather than the mini-player: #12 is a second
always-on-top window, and making it a mode of the main window would
discard navigation state on a resize and put the process-level MPRIS
question on a path a drag can trigger.
The panel is flex-shrink: 0 in the flow of .content-area, so an open
queue was paid for by the main panel rather than covering it. Measured
on Playlists: 379px of content left at 900x600 with all three of the
page header's actions clipped, 69px at 390px, and 0px at 320px — where
the content was not degraded but gone.
It goes to an overlay with a scrim when the content cannot spare the
width, and the rule is computed rather than breakpointed:
`available - panelWidth < 480`, where available is .content-area's
width and so already accounts for the sidebar's collapse at 900. A
media query cannot express this, which is the reason for the property:
the panel is drag-resizable between 200 and 500px and persisted, so a
viewport breakpoint silently assumes the default 320 and is wrong by up
to 180px for a user who widened it — in the direction that hurts, since
a wider queue is exactly when the content can least afford it.
480 is a judgement and the comment says so: there is no cliff to derive
it from (the track list rescales continuously, 213px to 124px columns
with no row overflow), so it is anchored to keep the default 1100px
window inline while putting every measured-broken case on the overlay
side.
The overlay is a presentation and not a fork — #55 asks for one
component with two mount points — so the roving tab stop, Alt+Arrow
reorder, drag reorder and selection semantics are untouched. Escape
closes it and returns focus, attached only while the overlay is up: it
is a dismissal rather than a shortcut, which is why it is not a
panel-scoped binding. The scrim covers the content area only, not the
sidebar or the transport, because the queue is not modal.
Refs #24
CLAUDE.md gains the three bands as a promise (Phone <600, Compact
600-899, Desktop >=900, and "no action is ever unreachable at any
supported size"), the computed queue rule and why it cannot be a media
query, and the correction that 900 — not the 800x600 minimum — is the
worst desktop width.
NOTES.md gets the measurements, including two things worth more than
the fix. My first probe for the sidebar's scroller searched
shadowRoot.querySelectorAll('*') and reported "no scroller, items are
unreachable", which reads exactly like a live Settings-unreachable bug;
the scroller is the host, and a host is not inside its own shadow root.
And the plan's first draft claimed the overlay "removes the desktop
half of #69", which the screenshot disproved: open and closed are now
identical at 900x600, so the queue's contribution is gone, but the
header's own overflow remains and is still a live defect.
Refs #24
The sidebar collapses to icons *below* 900, so the main panel is 843px
at 899 and 700px at 900: the narrowest content area any desktop width
produces is at the top of the Compact band, not at the enforced floor.
A viewport list that stopped at "the minimum" was missing its own worst
case.
MinWidth's comment loses both reasons it used to give, because neither
mechanism can happen any more — the subtitle is display:none from 899
down, and the sidebar host is overflow-y:auto (at 600x460 its
scrollHeight is 434 against a 332px client, and Settings is reachable
after scrolling). The value does not change: 800x600 is where desktop
chrome stops being comfortable, not where the app breaks, and below
600 the phone layout takes over. A floor defended by two expired
mechanisms is a number nobody can argue with, which is worse than
either answer.
Closes#24
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
#73 puts #24 first in Phase 2 and hangs the rest of the phase off it, and its
own Direction asks for a design pass — so the first deliverable is a plan
document, not a patch.
.planning/plans/active/018-supported-sizes-and-the-queue-model.mdis the decision; the code is the part of it that could land now.
Commits
cee43e5637bb610f080aed9d3b63MinWidth's stale comment replacedWhat was measured
On Playlists, against the running app, sweeping the viewport with the queue
open — five things that are not in the issue:
the only size this app promises, and "New Smart Playlist" loses 4px of 162
there. The queue makes it dramatic; it is not the cause.
so the main panel is 843px at 899 and 700px at 900. The worst desktop case is
the top of the Compact band, not the enforced floor — so every viewport list
that stopped at "the minimum" was missing its own worst case.
flex-shrink: 0in the flowof
.content-area, so an open queue was paid for by the content. Notdegraded — gone. 69px at 390px.
MinWidth's comment had expired (the subtitle isdisplay: nonefrom 899 down; the sidebar host scrolls).Main panel width with the queue open, before → after:
The decision worth reviewing
The mode is computed, not breakpointed —
available - panelWidth < 480,where
availableis.content-area's width. A media query cannot express it:the panel is drag-resizable 200–500px and persisted, so a viewport breakpoint
assumes the default 320 and is wrong by up to 180px for a user who widened it,
in the direction that hurts. Widening the panel at a fixed window size must flip
it, and that is the component test that matters.
480 is a judgement and says so. There is no cliff — the track list rescales
continuously (213px → 124px columns, no row overflow) — so it is anchored to
keep the default 1100px window inline and put every measured-broken case on the
overlay side.
What this deliberately does not fix
#69 is still live, and the plan's first draft was wrong to claim otherwise.
At 900×600 open and closed are now identical (main 700, one action clipped)
where open used to be main 379 with all three clipped — so the queue's
contribution is gone, but the header still overflows on its own. It cannot be
fixed in
page-headeralone: actions arrive through<slot name="actions">asarbitrary light-DOM markup with their own handlers, so a "More actions" menu
needs an actions API (data, not markup) across all three hosts that slot
them. That is its own branch, next.
#55 is unblocked (
Status/Blockeddropped, with the measurement on it). Theoverlay is a presentation of the same component, not a fork, so its roving tab
stop, Alt+Arrow reorder, drag reorder and selection semantics are untouched —
which is what its "one component, two mount points" Direction asks for.
#12 is not coupled to this. A very small window becomes the phone layout,
which already exists and is already tested, rather than a mini-player: #12 is a
second always-on-top window, and making it a mode of the main window would
discard navigation state on a resize and put its own process-level MPRIS
question on a path a drag can trigger.
Verification actually run
make lint— 0 issues, all three build configurations.make test— green, all three configurations.make ui-test— 80 files, 904 tests (6 new).frontend/node_modules/.bin/tsc --noEmitande2etsc --noEmit— clean.The frontend one caught four nullability errors in the new component test that
no test tier runs.
make e2e— 126 passed, 1 failed:view-lifecycle.spec.ts's autotag skip,which is the documented state-spending flake. Verified pre-existing by
restarting the app and re-running that spec alone: 4/4 pass.
make css-check,make skill-check,make bindings-check— clean.see:
layout-overflow.spec.tsasserts the shell needs no sideways scrollingand passes on a build whose header clips its own buttons. The scrim was
checked by sampling pixels (33,37,41 → 18,20,23) rather than by eye, because
it is subtle on a dark ramp by arithmetic.
New specs:
e2e/specs/queue-overlay.spec.ts(11) andfrontend/test/components/queue-overlay-mode.test.ts(6). The component oneswere checked against the old behaviour — 4 of 6 fail on it, including the drag
case; the 2 that pass are the inline ones, correctly.
Filed along the way
issue.sh claimis unusable: it needsread:userfor one lookupnothing else needs, so the one step required before the first edit is blocked
by its own tooling.
codegen-checkfails on any unstaged change and blames the codegenerators.
ui-testflake (itrejected this push once, then passed unchanged).
Closes #24
CLAUDE.md gains the three bands as a promise (Phone <600, Compact 600-899, Desktop >=900, and "no action is ever unreachable at any supported size"), the computed queue rule and why it cannot be a media query, and the correction that 900 — not the 800x600 minimum — is the worst desktop width. NOTES.md gets the measurements, including two things worth more than the fix. My first probe for the sidebar's scroller searched shadowRoot.querySelectorAll('*') and reported "no scroller, items are unreachable", which reads exactly like a live Settings-unreachable bug; the scroller is the host, and a host is not inside its own shadow root. And the plan's first draft claimed the overlay "removes the desktop half of #69", which the screenshot disproved: open and closed are now identical at 900x600, so the queue's contribution is gone, but the header's own overflow remains and is still a live defect. Refs #24d9d3b6370ftoede183d026