diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index d60a2ac..e42aed7 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -200,15 +200,15 @@ glyphs do not follow a shortened entry. `Painter::region()`, `SetSize`, `desired_width`, `apply_rest`, `Len::dp`, `Aligned` and `MaxSize`, none of which exist. Do not restore `OnResize::Translate` or `OrthoSize`. -- `SizeRule::{Min, Max, Clamp}` is written and pushed as `layout/bounds` - (`76aaf06`), and **is not ready to land**: every hand-written test passes, - including a capped scroll taking its viewport from the cap, but the - 400-seed scan does not, and the reason is a design question Bryan has to - settle -- see `docs/LAYOUT_LOG.md` under "Bounds are a rule that reads its - box". Bryan settled two things already: `Max` narrows the child's drawing - box (2026-09-20), and a rule gives a length or bounds one but never both, - since a capped share is said with two widgets. A cap may not contain - `leftover`. +- **`layout/bounds` (`de1eb7e`) is green and ready to review**, kept off #19 + so that branch stays one subject. A rule holds what a widget answers + (`SizeRule::{Min, Max, Clamp}`); a widget holds the box (`MaxSize`, which + `.max_width`/`.max_height` build). Bryan settled the split on 2026-09-20 + after four readings were measured; the reasoning and the one remaining hole + -- a retained answer re-placed under a different rel base, which is older + than bounds -- are in `docs/LAYOUT_LOG.md`. A bound may not contain + `leftover`, and the generated trees grow bounds in pixels until that hole is + closed. - `LazySpan`. - `Scroll` taking a direction rather than one axis. diff --git a/docs/LAYOUT_LOG.md b/docs/LAYOUT_LOG.md index cac5bf5..0bdc6e2 100644 --- a/docs/LAYOUT_LOG.md +++ b/docs/LAYOUT_LOG.md @@ -70,6 +70,25 @@ to it: a rule that is a fraction must pin its rel base, which `Exact` was already missing for bounds-shaped reasons; and `widget_trait!` dropped attributes, so no method it defines could carry a doc comment. +**Settled (Bryan, 2026-09-20): a rule holds the answer, a widget holds the +box.** `de1eb7e`. `SizeRule::{Min, Max, Clamp}` holds the length a widget +answers and leaves its box alone, which is stable because an answer is a +function of what the widget drew. `MaxSize` is the box version and is a widget +because a widget is drawn again whenever its own box changes, so the +comparison is made where the answer can be kept. `.max_width`/`.max_height` +are that widget; `.min_width`/`.min_height` stay a rule. All three seed scans +pass. The capped scroll -- 400 px of content under a 100 px cap, a 100 px +viewport and 300 to scroll -- is the app's `MaxSize` capability, and it comes +back through the widget. + +One hole is left and is **older than bounds**: `place_at` hands a parent a +retained answer without checking that the answer still holds for the rel base +that place gives, so a fraction resolved against one rel base survives into +another. A fraction in a bound is the first thing to reach it (seeds 4 and 196 +at depth 5), which is why the generated trees grow bounds in pixels only, said +where the tree is grown. An `Exact` rule that is a fraction can reach it too. +The fix is a holds check at the re-place site, not anything about bounds. + ## Images in the generated trees (2026-09-20) `Image` is the only widget here whose size hint is a length in pixels, so it is