Skip to content

T128: column flex automatic minimum size measures content with the item height as auto (Blink IntrinsicBlockSize) - #59

Merged
thejackshelton merged 29 commits into
masterfrom
flex-auto-min
Oct 3, 2026
Merged

thejackshelton merged 29 commits into
masterfrom
flex-auto-min

Conversation

@thejackshelton

@thejackshelton thejackshelton commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

What changed

T128: in a column flex container, an item's automatic minimum size (css-flexbox-1 §4.5 content size suggestion) is now measured with the item's own height treated as auto, as Blink does (flex_layout_algorithm.cc at 145.0.7632.6, BSD: lines 914-923 and 1117-1120, LayoutResult::IntrinsicBlockSize). Before, the engine measured content with the item's height applied, so an empty height: 11px item could not shrink below 11px where Chrome shrinks it to 0 (found by CALC-2).

  • packages/layout/src/flex.ts: columnIntrinsicBlockSize lays the item out with height: auto for the content suggestion. A percentage height, min-height, max-height (or flex-basis inside a column flex item) on a child of such an item is refused as percent-height-flex, since Blink resolves it against the item's set height, which an auto-height measurement cannot reproduce.
  • Blink's flex-shrink 0 shortcut (flex_layout_algorithm.cc lines 1078-1084): an item that cannot shrink takes its specified size without measuring content. The used size is the same; it avoids 4 needless percent-height-flex refusals.
  • New fixture values-calc-flex-column-auto-min (values group, ltr and rtl): fixed column containers shorter than their items, px and calc() heights, empty and non-empty content, padding/border, max-height, nested column flex, and a row control. Chrome captures from pnpm run parity:capture and pnpm run parity:dpr-capture.
  • Regenerated outputs in their own commit (bdec838), whose message names every command. Every existing vector and capture is byte-identical; emitted CSS changes only in the compilation-digest header.

What passed

Caught up with master before review: merges of origin/master up to the train 1 freeze base 1f17b6e (#64 SIZE-ar, #65, #66 INL1a breaks, #67 REPL-a engine, #68 T116). The REPL-a merge conflicted in flex.ts buildItem: master's ratio and replaced-item branches stay, and T128's column suggestion (columnIntrinsicBlockSize) applies to a sized box item; a replaced item keeps contentMain. docs/ports.json's flex_layout_algorithm.cc entry lists master's ratio.ts port and T128's two flex.ts ports. /tmp/heavy-lease.sh pnpm regen rebuilt the generated outputs in their own commit (ca22af3, fixed point after 3 passes).

On ca22af3:

  • pnpm typecheck: pass.
  • Targeted: engine.test.ts, vectors.test.ts, values.test.ts, chrome-ports.test.ts, regen.test.ts: 590 pass, 1 skipped (the DRAGON_REGEN_CHECK suite).
  • /tmp/heavy-lease.sh pnpm test on ca22af3: queued behind the other members' regens; the result follows in a comment.
  • Pre-PR audit (AGENTS.md step 3) of flex.ts, engine.test.ts, the fixture and values.ts: no instance found. The percentage check covers only the item's direct children by design: a deeper descendant's percentage resolves against an intermediate box, and a stretched-size basis is already refused as percent-height-flex by the real layout pass.

Train 1 (freeze base f78f198 / 1f17b6e)

This PR is a member of merge train 1 (AGENTS.md step 8), in this order: #59 T128, #60 CALC-2, #61 T130, T129, seld-r1. The train merges each member onto the previous position, so members that touch the same lines are stacked, with their overlaps resolved and reviewed in the member branches rather than in the train: CALC-2 merges T128, T130 merges CALC-2, and T129 merges T130. Until an earlier member lands, GitHub shows its changes in this diff too. seld-r1 sits on master alone; its merges onto the earlier positions were simulated clean, and every position's reviewed-path patch id equals its member's clean head (git merge-tree chain plus patchIdOver), so each position should be vouched at landing.

The device lanes, and the regen of each position, run in the train itself: one device run per position. Master now has T116 (#68), so device-pixels is iOS 57 / Android 86 on master; each position's device run is compared against that.

Random corpus: 136 geometry moves and 35 new percent-height-flex refusals, all on cases without a Chrome reference; refusing is accepted (follow-up T136).

Changed tests and checks

  • packages/layout/test/engine.test.ts: new describe block. It pins the c1 and c2 fixture cases in LU, the percent-height-flex refusal, and the fact that a row item's percentage flex-basis child is not a height.
  • packages/parity/src/fixture-groups/values.ts: adds both('values-calc-flex-column-auto-min').
  • No tolerance, check or test is loosened or removed.

🤖 Generated with Claude Code

Note

Add column flex automatic minimum size support via columnIntrinsicBlockSize

  • Adds columnIntrinsicBlockSize in flex.ts: for column flex items with a specified height, it clones the item with an auto height, lays out contents, and uses the resulting content-box height as the content size suggestion.
  • Updates buildItem in flex.ts: non-shrinkable column items with a specified main size now use that size directly as the minimum.
  • Rejects percentage height, min/max height, and applicable percentage flex-basis inputs inside column intrinsic measurement with the percent-height-flex unsupported code.
  • Adds engine tests in engine.test.ts and a parity fixture with generated snapshots, break vectors, and expected pixels in LTR and RTL at multiple DPRs; regenerates Swift and Kotlin layout artifacts.
  • Registers the values-calc-flex-column-auto-min case in the iOS, Android, and web support profiles.
  • Behavioral Change: column flex items with specified heights now size differently than before — content-based minimum sizing replaces the generic content measurement path in buildItem; percentage-height configurations return percent-height-flex unsupported results.

Macroscope summarized 2d47e5d.

…h its own height treated as auto (T128)

css-flexbox-1 §4.5 content size suggestion; ported from Blink third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc at 145.0.7632.6 (BSD, The Chromium Authors; sha256 b0ea68654c62d2ca1d73d801ffca395901aa37e51569281266fc9ef87a9e892c) lines 914-923 and 1117-1120 (LayoutResult::IntrinsicBlockSize). A percentage height child of such an item is refused as percent-height-flex, since Blink resolves it against the item's set height.
…ontainer shorter than its items, px and calc() heights, empty and non-empty content, ltr and rtl; Chrome captures from pnpm run parity:capture and pnpm run parity:dpr-capture
…ize (flex_layout_algorithm.cc lines 1078-1084 at 145.0.7632.6): an item that cannot shrink takes its specified size without measuring its content, which gives the same used size and avoids 4 percent-height-flex refusals
…ure values-calc-flex-column-auto-min): pnpm run grammar:gen; pnpm run parity:capture and pnpm run profile:rows twice (fixed point); pnpm run parity:dpr-capture; pnpm run layout:vectors; pnpm run layout:dpr-vectors; pnpm run layout:break-vectors; pnpm run parity:break-capture; pnpm run parity:pixel-capture; pnpm run native:gen; node --conditions=dragon-internal examples/music-player/tools/check.ts; pnpm run tw:sweep; pnpm run wpt:run -- --target web; pnpm run wpt:update-expectations -- --target web; pnpm run parity:glyph-b3 -- --write-bottom-pins; node --conditions=dragon-internal packages/parity/src/cli/media-sweep.ts (then --check); pnpm run parity:lanes -- --run-host. Every existing vector and capture is byte-identical; emitted CSS changes only in the compilation-digest header; the new fixture adds its vectors, captures, pixel and break records; corpus.json and corpus-dpr.json carry the new engine digests
thejackshelton added a commit that referenced this pull request Oct 1, 2026
…in amendment 1 (catch up before review: GitHub can't use the merge driver)
…catch up before review): no source conflicts; generated outputs keep this side (master's .gitattributes merge=dragon-generated) and pnpm regen rebuilds them in the next commit
@macroscopeapp

macroscopeapp Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes existing column-flex sizing in the production layout engine and adds a new unsupported outcome for percentage-height descendants, with an additional intrinsic layout pass. These compatibility and runtime effects extend beyond a simple isolated fix and merit human review.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

…npm regen: fixed point after 3 passes, 34 steps run): emitted CSS (compilation digests), the translated Swift and Kotlin engines and harnesses, corpus.json and corpus-dpr.json, the values-calc-flex-column-auto-min vectors, profiles and expected-fonts, and the host-only lanes.json (device lanes not run; the train's device run supplies them)
… buildItem (the flex-shrink 0 shortcut, lines 1078-1084) and columnIntrinsicBlockSize (IntrinsicBlockSize, 914-923 and 1117-1120), now that PORT-0 (#52) is in the base; chrome-ports.test.ts 13/13
…tHub cannot apply the dragon-generated merge driver, so the PR was conflicting on generated files; no source conflicts; generated outputs keep this side and pnpm regen rebuilds them next
…npm regen: fixed point after 2 passes, 19 steps run): the translated engines and harnesses with master's EMS-b paint roots, corpus files and the host-only lanes.json (device lanes not run; the train's device run supplies them)
…REPL-a engine and board) into flex-auto-min for train 1: flex.ts buildItem keeps master's ratio and replaced-item branches and T128's column suggestion for a sized box item (columnIntrinsicBlockSize; a replaced item keeps contentMain); percentMainHeight takes master's LayoutNode; docs/ports.json flex_layout_algorithm.cc lists master's ratio.ts port and T128's two flex.ts ports; generated outputs keep this side and pnpm regen rebuilds them next
…-min: no source conflicts; generated outputs keep this side and pnpm regen rebuilds them next
…pm regen: fixed point after 3 passes, 38 steps run, 2639.2 s): host-only lanes.json (device lanes run in the train)
Comment thread packages/layout/src/flex.ts Outdated
…rcentage check covers replaced children too (REPL-a's leaves carry height, min-height, max-height and flex-basis); a replaced child with height 50% of a sized column item now returns percent-height-flex instead of being measured at its natural size. engine.test.ts pins it (fails on the previous source)
…d point after 2 passes, 19 steps run): the translated engines (the replaced child in the percentage check) and corpus digests; no vector, capture or lanes verdict moves
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 2, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 2, 2026 23:58

Dismissing prior approval to re-evaluate 2d47e5d

…ng stop (LAND-3 ruling); PNT1 split; FORM-a restack
- train build judges each position's device run against the device evidence committed on the train's base (lanes.json and device-failures-<target>.json), not by the lanes command's exit code: every lane must pass or fail as on the base, a failing lane may list no failure the base does not, and lane parity must pass with no stale lane (deviceRunProblems). It also checks the run rewrote lanes.json and the lanes commands exited 0 or 1.
- train build runs pnpm regen again after the device run (POSITION_STEPS), so native-lanes.ts follows the run's lanes.json in the position's regen commit.
- pr:review vouches for Macroscope's 'No code objects were reviewed.' skip under the 'already reviewed' guard: the head's patch id over reviewed paths must equal an earlier reviewed commit's.
- A member whose PR head is a position from an earlier build is merged at that head (memberTip walks its train-made commits down to the clean head), so land's push fast-forwards it; check still predicts against the clean head's patch id.
- land stops on a review/* base with the exact 'gh pr edit <n> --base master'.
…review passes a commit whose every Macroscope check was skipped with exactly 'Monthly spending limit reached (workspace setting).', prints UNREVIEWED, and still requires CI to pass and every finding to be answered (reviewExit); a near-miss title or a mixed result fails. AGENTS.md step 4 records the rule. pr-review.test.ts pins each case; the outcome pins gain unreviewed: false
thejackshelton and others added 6 commits October 2, 2026 23:47
LAND-3: merge-train fixes from train 1 (device run judged on evidence, regen after devices, no-code skip vouch, rebuild on an earlier position)
…ication time against the run's start, not by a content change: train 1's rebuilt position 1 merged #59's earlier position, whose lanes.json already held this tree's device run, so the new run wrote identical bytes and the build stopped with 'the device run did not rewrite'. deviceRunWrote is pinned in merge-train.test.ts
thejackshelton and others added 3 commits October 3, 2026 00:16
LAND-3b: train build tells the device run wrote lanes.json by its file time, not a content change
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
@thejackshelton
thejackshelton merged commit 3b2a849 into master Oct 3, 2026
4 checks passed
@thejackshelton
thejackshelton deleted the flex-auto-min branch October 3, 2026 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant