Exercise composer placement at a real control collision - #101
Conversation
The floating bar is absolutely positioned, so it shrink-to-fits against the room left of the page's right edge. A wrapping list folded itself into that room instead of overflowing, so placePalette's edge test never saw the miss and the stacked placement never engaged: at 390px the list arrived as a 38px-wide column of six pills beside the comment icon. Hold the in-place list to one row. The bar then overflows when the list cannot fit beside it, which is the fact the edge test reads, and the stacked list keeps its own wrap and max-width for the rows below the bar. test_the_composer_opens_where_the_button_stood measured the same narrowing from the other side: with 💬 and one ellipsis the bar now fits in the gap between the column and the suggestion row hanging beyond it, so the clearance walk had nothing to step past and the test's own guard said so. Narrow the window to where that margin is tight again.
|
The same three failures came back on ci run 33230323772 ( Verification on top of
|
|
Main has landed this fix independently. All four node ids pass on Verification
Merge check against
This run was dispatched for ci run 33229420192 ( |
|
Correcting one thing in my note above: the test half of this PR is still worth taking, and I was wrong to call the whole thing redundant.
The I have not pulled this into #103 — that PR is about the sibling |
`test_the_comment_button_stands_on_no_control` stopped testing anything when the comment bar shrank, and said nothing. It asks whether floating chrome covers a page control, and read the answer only at that control's centre — a point today's compact bar cannot reach at any width, so both of its readings went quiet together. This opens the page where the row is genuinely in the bar's way, asserts the bar stepped past it, and reads each control at its corners as well as its centre, which is where a bar that stopped stepping actually lands. ## Problem The test's arrangement is the collision its docstring describes: a selection filling its lines puts the 💬 out in the margin, on the line where the suggestion hangs its Accept/Reject row. `placeClear` steps the bar down past that row, and the test checks nothing ended up covered. **The arrangement went stale.** The bar's width decides whether there is anything to step past. Carrying six reaction pills it measured 287.6px and reached 219px past `sug-refill`'s row. After [`f30a585`](f30a585) (*Simplify reaction controls*) it carries 💬 and one ellipsis, measures 65.5px, and stops 2.9px short of the row. Its sibling `test_the_composer_opens_where_the_button_stood` states its arrangement (`"the button never stepped aside, so where it stood proves nothing"`) and so failed loudly on that commit; this test slept through it. **And the reading could not have caught it either.** Both readings ask where the control's centre is — once through `elementFromPoint`, once by pressing Accept, which Playwright also does at the centre. The bar hangs 6px above the line it stands beside (`beside` returns `rect.top - 6`) and is the row's own height, so an unstepped bar spans y 157–178.5 against a row at 169–190.5: it covers the row's top edge and stops **1.25px short of its centre**. Measured with `placeClear`'s step disabled at every width where the row still hangs in the margin — `under` came back `[]` at all of them. So the walk could have been removed outright and this test stayed green, at any width; narrowing the window alone does not change that. ## Solution **Open the page where the collision is real.** At the default 1200 the bar clears the row and steps only through `placeClear`'s 6px sharing gutter — 3.1px of slack, which is the allowance [`38bef20`](38bef20) added saying *"a one-glyph difference between system fonts must not decide whether two controls almost touch or the float steps clear."* A precondition spending it would go red for a font and blame staleness. At 930 the bar (693.8–759.3) and the row (739–915) overlap by 20.3px and the step is the row's own doing; below 900 the row docks under its block and is out of the way again. **Read each control at its corners as well as its centre.** A press lands where the reader aimed, and the top of a pill is as much of it as the middle — a bar standing on it is a press stolen either way, which is what `placeClear` itself treats as sharing. Sampling a 3×3 grid inset 4px keeps the hit test rather than trading it for rectangles, and it lands on the part the bar does reach: ```python .filter(c => { const b = c.getBoundingClientRect(); const xs = [b.left + 4, (b.left + b.right) / 2, b.right - 4]; const ys = [b.top + 4, (b.top + b.bottom) / 2, b.bottom - 4]; return xs.some(x => ys.some(y => { const top = document.elementFromPoint(x, y); return top && !c.contains(top) && top.closest(".lf-chrome"); })); }) ``` The precondition stays in front of it as the staleness tripwire, and the docstring states both — what each reading holds and why the centre alone could not. **What this costs, stated plainly.** At 930 the pre-`f30a585` wide bar overlaps the row too, so the precondition alone would not have caught that shrink — it passes on `891a2d4`. The coverage reading is what now carries the regression, and it fails on a walk that stops stepping regardless of the bar's width. ## Testing The two assertions discriminate independently, measured on `501235c` with `placeClear`'s last line edited to `if (false && y !== box.top) place(node, left, y)`: | tree | result | |---|---| | current, walk intact | passes | | walk disabled | **fails** on the precondition — `156.95 > 190.5` | | walk disabled, precondition deleted | **fails** on the reading — `floating chrome is standing on controls: ['lf-sug-actions lf-ui', 'lf-pill lf-sug-accept lf-ui']` | The third row is the one the centre-only reading could not produce at any width. `uv run pytest tests/test_render_anchors.py --run-nightly` — 58 passed. `uv run pytest tests` — 700 passed, 6 skipped. `pre-commit run --files tests/test_render_anchors.py` — ruff check, ruff format, typos all pass. <details><summary>Geometry the diagnosis rests on</summary> `SUGGESTION_PAGE` with `#replace` selected, probed straight after the fab appears. The step moves y only, so the bar's left/right are the same stepped or not. `under` measured with the step disabled: | width | bar `[left, top, right]` | `sug-refill` row `[left, right]` | bar reaches Accept centre | `under` | |---|---|---|---|---| | 1200 | `[831.1, 157, 896.6]` | `[899.5, 1075.5]` | no | `[]` | | 1024 | `[743.1, 157, 808.6]` | `[811.5, 987.5]` | no | `[]` | | 970 | `[721.6, 157, 787.1]` | `[779, 955]` | no | `[]` | | 930 | `[693.8, 157, 759.3]` | `[739, 915]` | no | `[]` | | 900 | `[693.8, 157, 759.3]` | `[709, 885]` | yes | `[]` | | 895 | `[777.6, 157, 843.1]` | docked | — | `[]` | Row and pills sit at y 169–190.5 throughout, so their centre is 179.75 and the unstepped bar's bottom is 178.5 — 1.25px short at every width, including 900 where it does reach the Accept pill's centre horizontally. That is why the centre-only reading was unfalsifiable rather than merely narrow, and why the corners restore it without needing a different fixture. This came out of the `ci-fix` run for [ci run 33229420192](https://github.com/max-sixty/leaf/actions/runs/33229420192). The three failures that run reported are already fixed on `main` by `38bef20`. #101's CSS half landed there independently; its test half — the sibling's narrowed window — has not, and stays that PR's to carry. </details> --------- Co-authored-by: leaf-agent <318509791+leaf-agent@users.noreply.github.com>
The compact floating bar no longer overlaps the suggestion row at the test's old desktop width, so the composer-placement test could pass without exercising its clearance walk. Resize the fixture to 930×900, where the row still hangs in the margin and genuinely overlaps the bar.
The one-row reaction-list rule is already on
main; this PR now keeps only the non-vacuous test arrangement.Testing:
uv run pytest tests/test_render_anchors.py::test_the_composer_opens_where_the_button_stood -q -n0(1 passed).