Scope the chrome's own keycap rules and read one box statement from both sides - #152
Conversation
|
The split does not have to copy the geometry, so the rule's comment may not rule it out. The declarations can be one shared string in the module and two selectors reading it — I built it to check rather than to propose it, and it measures as a no-op: computed style plus rendered width and height for It is a runtime file rather than a test file, so it is the more expensive of the two — The diff, against 521dfec--- a/skills/leaf/assets/runtime/chrome-style.js
+++ b/skills/leaf/assets/runtime/chrome-style.js
@@
+/* One sequential step's box, stated once and read from both sides of the scope line.
+ The step is the same shape wherever it stands, and it stands in an option's corner as
+ well as in the chrome, so the declarations are shared text rather than a shared
+ selector: naming the chrome's own key classes beside .lf-address put lf-key-sequence
+ and lf-key-more into the document-level vocabulary, where a page coining one of those
+ names would have been dressed by it. */
+const KEY_BOX = `box-sizing: border-box;
+ min-width: var(--lf-key-box); height: var(--lf-key-box); padding: 0 4px;
+ border: 1px solid var(--border-2); border-radius: 4px; background: var(--chip);
+ color: var(--ink-2); font-family: var(--mono); font-size: var(--t-6);
+ line-height: 1.478; text-align: center; white-space: nowrap;`;
+
/* The private comment-layer stylesheet. The public runtime supplies the
declaration-derived names and layout queries interpolated into it. */
export function chromeStyle({
@@
- /* One sequential step keeps one geometry in options, the key line, page addresses and
- the reference. A sequence composes these fixed boxes instead of making spaces inside
- one keycap carry time. A compact choice label such as g / G remains one decision point. */
- .lf-address, .lf-key-sequence > kbd, .lf-key-more kbd { box-sizing: border-box;
- min-width: var(--lf-key-box); height: var(--lf-key-box); padding: 0 4px;
- border: 1px solid var(--border-2); border-radius: 4px; background: var(--chip);
- color: var(--ink-2); font-family: var(--mono); font-size: var(--t-6);
- line-height: 1.478; text-align: center; white-space: nowrap; }
- .lf-address { display: none; border-color: var(--accent); background: var(--card);
- color: var(--accent); z-index: 1; }
- .lf-key-sequence { display: inline-flex; align-items: center; gap: 3px;
- white-space: nowrap; }
- .lf-key-sequence > kbd, .lf-key-more kbd { display: inline-flex; align-items: center;
- justify-content: center; }
- .lf-key-sequence > kbd[data-lf-key-state="pressed"] { border-color: var(--accent);
- background: var(--accent); color: var(--card); }
+ /* An address chip is the one step box the page also wears — in an option's corner —
+ so it is the one that belongs to the shared vocabulary. The chrome's own sequences
+ take the same box from KEY_BOX inside the @scope block below. */
+ .lf-address { ${KEY_BOX}
+ display: none; border-color: var(--accent); background: var(--card);
+ color: var(--accent); z-index: 1; }
@@ inside @scope (.lf-chrome), beside the key line's other rules
.lf-keyline .lf-chord-control { margin-inline-start: 4px;
padding-inline-start: 12px; border-inline-start: 1px solid var(--rule); }
+ /* The chrome's own step boxes: the key line's sequences and its More key, the
+ reference's routes, and the sequence inside an address chip. A sequence composes
+ these fixed boxes instead of making spaces inside one keycap carry time; a
+ compact choice label such as g / G remains one decision point. Every element
+ wearing these stands inside the runtime's container, so the rules do too — the
+ box itself is KEY_BOX, which .lf-address states at document level. */
+ .lf-key-sequence > kbd, .lf-key-more kbd { ${KEY_BOX}
+ display: inline-flex; align-items: center; justify-content: center; }
+ .lf-key-sequence { display: inline-flex; align-items: center; gap: 3px;
+ white-space: nowrap; }
+ .lf-key-sequence > kbd[data-lf-key-state="pressed"] { border-color: var(--accent);
+ background: var(--accent); color: var(--card); }
.lf-key-more { display: inline-flex; gap: 5px; align-items: baseline; flex: none;Measured on 2d46d4a, where |
leaf-agent
left a comment
There was a problem hiding this comment.
The widening itself checks out: .lf-address, .lf-key-sequence > kbd, .lf-key-more kbd and the three rules under it sit above the @scope (.lf-chrome) block in chrome-style.js, the three keySequence call sites (keyline.js, reference.js, address.js) all build into keylineEl / helpEl / addressLayer, and all three are children of chromeRoot. The test passes on the merged tree.
One claim in the new comment is the wrong way round, though, and it is the one doing the safety work — worth fixing because it tells the next reader the pin is redundant.
The comment justifying lf-key-sequence and lf-key-more in the shared vocabulary claimed the moved-property assertion above already holds that a document-level name touches nothing in the page. It holds the opposite side: its probe is `[...scoped].filter(c => !global_.has(c))`, so every name in the document-level set is dropped from it by construction — including the two this change adds. The names are not inert either; an element in the page coining them would wear the whole keycap box. What makes the widening safe is that nothing in the page wears them, and this pin is the only check on that.
|
Taken, and both points hold. The correction is what decided it. My comment claimed the moved-property assertion already held that a document-level name touches nothing in the page; it cannot, for exactly the reason given — Measured that the box is unchanged rather than describing it: on |
## Problem The nightly leg of `ci` failed on [run 33735071949](https://github.com/max-sixty/leaf/actions/runs/33735071949) (`a57ae29`) with seven cases. Six are already owned by open PRs: `test_a_widgets_label_takes_a_comment_inside_the_control_it_labels`, `test_a_closed_leaf_clears_itself_off_the_tray` and `test_the_leaves_tray_takes_the_keyboard` by #236; the ring walk by #239's `ship-review` precondition standing ahead of #240's `lf-shotframe` fault; and both of `test_page_fixture_renders[pr-walkthrough]` (the 4px sideways scroll on `pr-scale-groups`) and `test_nested_command_projections_stop_at_their_own_boundary` (`§ inner-worker`) by #243. The seventh is new with `a57ae29` and nobody's yet: ``` FAILED tests/test_render_conversations.py::test_a_coined_class_cannot_reach_the_chromes_rules AssertionError: the document-level class surface changed: widen the shared vocabulary on purpose Extra items in the left set: 'lf-workspace' ``` #242 wrote the open workspace's tint as `.lf-btn.on, .lf-btn.lf-workspace[aria-expanded="true"]` in `chrome-style.js`, at document level. `lf-workspace` is worn by three controls and all three are the chrome's own — the Threads toggle built at [`leaf.js:817`](https://github.com/max-sixty/leaf/blob/064e67d5/skills/leaf/assets/leaf.js#L817), and All leaves and Asks, which `trayIs` marks at [`trays.js:194`](https://github.com/max-sixty/leaf/blob/064e67d5/skills/leaf/assets/runtime/trays.js#L194). Every one of them is inside `chromeRoot`, the `.lf-chrome` container the private stylesheet is scoped to. So the name reached document level without being shared vocabulary, which is the seam the pinned set exists to catch — the same one #152 answered for the keycap rules. ## Solution Move the selector into the `@scope (.lf-chrome)` block, beside `.lf-banner-more[data-lf-news]`, which paints the same accent face for the same kind of banner state. `.lf-btn.on` keeps its document-level rule, unchanged and now on its own: `on` is worn out in the page and is the reason that line was there before #242. Nothing about the paint moves. Specificity is unchanged, and the one rule that could contend — `.lf-banner-menu > .lf-btn { border-color: transparent }`, for a workspace control folded into the overflow menu — is `(0,2,0)` against this selector's `(0,3,0)` on both sides of the move, so scope proximity never gets a say. Fixing it at the pinned set instead would have widened the shared vocabulary by a class no widget can wear, which is what the assertion's own message asks you not to do. ## Testing On this branch, rebased on `fdba9e1d`: - `uv run pytest tests` — 808 passed, 6 skipped - `test_a_coined_class_cannot_reach_the_chromes_rules` and both parameters of #242's `test_workspaces_replace_each_other_and_name_the_open_one` pass - `uv run pytest tests/test_render_conversations.py tests/test_render_controls.py --run-nightly` — 141 passed, and the three failures are #236's two tray cases and the ring walk, all reproducing identically on `main` Not vacuous: deleting the scoped rule fails the workspace test at both 500 and 1200 with the resting face (`rgb(238, 234, 222)` where the active face is `rgb(255, 254, 251)` under `--chip`) rather than passing by construction. `chrome-style.js` is served rather than bundled, so there is nothing to re-vendor, and no user-visible pixel changes, so there is no before/after shot to hand over. --- Automated fix for [failed run](https://github.com/max-sixty/leaf/actions/runs/33735071949) Co-authored-by: leaf-agent <318509791+leaf-agent@users.noreply.github.com>
Problem
test_a_coined_class_cannot_reach_the_chromes_rulespins the set oflf-classes the chrome styles at document level, and asks that widening it be a decision rather than a side effect. Two names entered it unremarked and it has been red on every run since, 33340110090 included:They arrived with 360c40a "Clarify keyboard chord progress", through one rule:
.lf-address, .lf-key-sequence > kbd, .lf-key-more kbdstated the keycap geometry for all of them at once, and.lf-addressis worn in the page as well as the chrome, so that rule cannot go inside the@scopeblock. Its two chrome-only companions came out to document level with it.Solution
Lift the box into one
KEY_BOXstatement the module interpolates twice:.lf-addressreads it at document level, where it has to be, and.lf-key-sequence > kbd, .lf-key-more kbdreads the same statement from inside@scope (.lf-chrome), along with.lf-key-sequenceand the pressed-state rule. "One sequential step keeps one geometry" stays literally true — there is still exactly one statement of the box — and the pin closes with no names added.That is better than widening the pin, which is what this PR did first. The pin is the only thing standing between a page coining
lf-key-sequenceand the whole keycap box landing on it; the test's other half, the probe wearing every scoped class, drops document-level names by construction and so cannot cover a widened set. Scoped, those two names are on that probe, and it reports no moved property — the coin is now inert for a reason the suite checks rather than for a reason the list asserts.Nothing in the layer renders differently.
Testing
corpusexample with the chord up:box-sizing,min-width,height,padding,border,border-radius,background-color,color,font-family,font-size,line-height,text-align,white-space,display,align-itemsandjustify-contentread the same on.lf-key-sequence > kbd,.lf-key-more kbdand.lf-address, and the sequence keycap'sgetBoundingClientRectis unchanged to the pixel. That is why there is no before/after still: the change is a no-op on screen by measurement.uv run pytest tests/test_render_conversations.py tests/test_render_navigation.py tests/test_render_controls.py tests/test_render_anchors.py --run-nightly -n4— the gate passes; the 11 that stay red are the standing set and each is somebody's: Give the versions menu back its way in, its way out, and the reader's place #137's four, Update the option-group tests for the removed seat, and ring the add field #148's ring walk and digits, Retarget the seated-decision tests onto a widget that declares the seat #151's two seat tests, Keep the compact shelf's display rule off the controls the page has hidden #150's shelf, andtest_coarse_pointer_resize_reach_stays_reachable_without_trapping_scroll, which Show the thread panel over the page instead of modally over it #144's body hands on to Keep the root's bar standing rather than reserving a gutter it never draws in #121'soverflow-y: scroll.uv run pytest tests -n4— 740 passed, 6 skipped.prettier --checkandeslinton the module,ruff checkontests/.Why these two names are the chrome's own, measured
Checked rather than assumed, on the
corpusexample served through the ordinary fixture:gg hg f?open.lf-key-sequence.lf-chrome.lf-chrome.lf-chrome.lf-chrome.lf-key-more.lf-chrome.lf-addressWhich matches the code:
keylineElis appended tochromeRoot(leaf.js), andaddressChip— the one place akeySequencegoes inside an.lf-addresschip — puts its chips inaddressLayer, whichruntime/keyboard/address.jscalls "the chrome's layer" at the line that draws them. The page-side.lf-addresselements are an option's own corner address, which carries no sequence. With the reference open, everykbdunder those classes still computesheight: 19pxand a1pxborder, which isKEY_BOXreaching them from inside the scope.After the move, the test's own probe reads
lf-key-sequenceandlf-key-moreas scoped-and-not-global, so both are on the element it plants in the page, andmovedis empty.What this leaves red, and one note for #134
That run's other 29 failures are all owned; the map is in a comment on #133, measured on
mainand on #148's head. #148 takes 19, #137 four, #147 (now #151) two, #134 the catalog digest, and two did not reproduce at-n0. The one still without an owner is the coarse-pointer resize test above.This branch edits
assets/runtime/chrome-style.js, which is one of the 142 filesexample-previews.pydigests, so it re-stales the manifest and belongs before #134 in the merge order that issue describes.Automated fix for failed run