Repository navigation
L0: lower to the theme kit, and carry a tap through it - #3
Merged
Merged
Conversation
§1.1 says a card names roles and a theme answers them. `makepad::lower` does
neither: it emits a backend's own widget dialect with ten hardcoded colours and
a font-size ramp, so it decides what a theme decides and reaches one backend of
three. `kit::lower` emits role calls and lets the kit answer.
l0_panel([ l0_caption("LEAD"), l0_body("Rust 1.95 lands") ])
not RoundedView{ draw_bg.color: #ffffff12 draw_bg.border_radius: 14.0 … }
THE CONTRACT IS EXECUTED, NOT ASSERTED. Two earlier attempts at this were
reverted for asserting one nobody had run — five of twenty-three roles mapped to
tags that did not exist. This crate still cannot depend on `splash-render`, and
must not, so the check lives in `Splash-Makepad`: it dev-depends on this crate
and builds every reference card through the real evaluator. That dependency is
possible only because this crate was extracted from `splash-core` and needs
`serde_json` alone — the extraction paying for itself a second time.
The check found the same defect the reverted attempt shipped, immediately.
`Photo` WITH children is not an image, it is the page: the weather card wraps
the whole card in one, and lowering it as a leaf dropped all 62 nodes to 1.
`l0_surface_photo` composes image, scrim and content, which is what
`makepad::lower` already does and what a leaf cannot.
`hero_points` is now shared rather than duplicated. Both lowerings size a hero
by what it will DRAW, and two copies of that ramp would have been two ramps.
The presentation test asserts the emitted SOURCE, not the built tree: the tree
is full of colours by design, because the kit puts them there. That is the whole
point of the layer.
842 Splash tests, 32 splash-makepad tests, clippy clean.
news 25 nodes, stock 11, weather 62 — through the real renderer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An L0 event now reaches the renderer as `tapto: "l0:{…}"`. No VM change, no
scoped state: this renderer's own `set:` verbs are handled internally and
anything else falls through to the host, so an instance key survives intact.
The fork I described between "collapse L0 events into set: strings" and "build
scoped state in the VM" was not a fork — I had not read far enough.
THE WRAPPER IS THE LOAD-BEARING PART. A `card`, `chip` or `image` carrying
`tapto` renders and does nothing: the attribute is accepted by the node model
and then dropped, so the string never reaches the UI at all. Only a container
carries a tap. Measured, not assumed — card, chip and image all produced neither
an overlay nor an on_click, while row, column and text produced one. So a
tappable node is wrapped in a container, uniformly: deciding per role which
kinds carry a tap natively is a second rule that rots the next time this
renderer changes.
The target is JSON, not a delimited string. Every field is data — an instance
key contains colons (`w:list#0`) and slashes, a payload is whatever the card
bound — so every separator worth using has a data-dependent failure, and a
failure here routes a tap to the wrong row.
§8 said the fix "is to retarget it at the component kit", which assumed a kit
answering L0's roles existed. None did; writing it was most of the work. It now
records what is actually left: `makepad::lower` stays because five of the six
data visualisations lower to a marker, not because the kit path is incapable —
live backend calls already survive it, since both lowerings share one value
formatter. It also separates the two senses of "L1", which that paragraph
conflated.
842 Splash tests, 34 splash-makepad, 19 mutation rules held, clippy clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🤖 AI Code ReviewClaude CLI exited with code 1: ✅ No significant issues found. Tokens used: 0 | Powered by r9s.ai |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pairs with OctoSense-org/OctoScript-Makepad#3, which holds the kit and the tests that
execute this contract.
§1.1 says a card names roles and a theme answers them.
makepad::lowerdoesneither: it emits a backend's own widget dialect with ten hardcoded colours and a
font-size ramp, so it decides what a theme decides and reaches one backend of
three.
What lands
kit::loweremits role calls:A declared tap travels as
tapto: "l0:{…}". No VM change and no scopedstate: the renderer's own
set:verbs are handled internally and anything elsefalls through to the host, so an instance key survives intact. The fork I
described — "collapse L0 events into
set:strings" versus "build scoped statein the VM" — was not a fork. I had not read far enough.
The target is JSON rather than a delimited string, because every field is data:
an instance key contains colons (
w:list#0) and slashes, and a payload iswhatever the card bound. Every separator worth using has a data-dependent
failure, and a failure here routes a tap to the wrong row.
hero_pointsis shared rather than duplicated. Both lowerings size a hero bywhat it will DRAW — once a value lowers to a live backend call the drawn text is
not in the DSL at all — and two copies of that ramp would have been two ramps.
What the checks found
The contract is executed in the consumer's repository, and it caught the reverted
attempt's exact defect immediately:
Photowith children is the page, not animage. The weather card wraps the whole card in one, and lowering it as a leaf
collapsed 62 nodes to 1.
§8 brought current
It claimed the fix "is to retarget it at the component kit", assuming a kit
answering L0's roles existed. None did. It now records what is actually left:
makepad::lowerstays because five of the six data visualisations lower to amarker — not because the kit path is incapable, since live backend calls
already survive it (both lowerings share one value formatter).
It also separates the two senses of "L1" — the capability level this document's
§7 classifies, and the layer above — which that paragraph conflated.
Verification
842 workspace tests, 19 mutation rules held with none unprotected, clippy clean
under
--workspace --all-targets --all-features -D warnings.Not claimed: none of this is on device yet.
makepad::lowerstill drives thefour goldens and the tap loop on the OnePlus 6T, and swapping to the kit path is
the next step, with those goldens as the check.
🤖 Generated with Claude Code