Skip to content

MQ-R1 1/2 (T067): @media bands for native in the compiler, the band runtime reference and Chrome resize traces - #140

Merged
thejackshelton merged 64 commits into
masterfrom
mq-r1
Oct 6, 2026
Merged

thejackshelton merged 64 commits into
masterfrom
mq-r1

Conversation

@thejackshelton

@thejackshelton thejackshelton commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

MQ-R1 PR 1 of 2 (T067, binding spec docs/goals/milestone-2-proof/notes/T067-mq-r-spec.md §6.2, R2 to R5, R8, R13). Branched from master; lands alone. PR 2 (the Swift and Kotlin runtime glue, the resize device step, the environment record in the dump, the Android configChanges, the translated rt-band vectors and the device-env rotation lane) builds on this one once it is on master.

What changed

  • Native @media in every band (R4, R13). project.ts checks and lowers every @media band for every target, since a native root switches bands at run time as a browser does. A native target accepts a condition only where its profile proves at-rule:@media and each media-feature:<name> in the media context; otherwise the condition is refused on that target, naming the missing rows (DRAGON_UNSUPPORTED_AT_RULE [ios]/[android], with a profile field). This replaces the "until MQ-R" literal. The 17-band refusal now names MQ-R4, and environment features name MQ-R2 (the R9 set) or MQ-R3.
  • The band program (R4, R5). lower/band-program.ts writes each width and height feature as a typed atom and each band as its truth vector (bandTableOf), and folds every (app assignment, band) pair into one state program with the internal @env#band variable (bandStateProgram; the 64-assignment cap counts bands). MediaRuntime (packages/parity/src/media-runtime.ts, since the core imports the layout engine for types only) is the TypeScript reference of the runtime: a size change computes the new band, applies its delta through @env#band, then lays out once at the new size; app setters cannot set @env#band. The compile records every band's cases and lowering (InternalRecord.bands), exposed through nativeBands, nativeBandPrograms, nativeBandProgram and nativeBandOfViewport.
  • The device band lookup (R2, R3). packages/layout/src/rt-band.ts (exported as rtBand): the media size is fround(fround(px) * fround(1 / dpr)) of the root's whole device px; >=, <= and = take 1/64 px of slack, < and > are exact, negative queries follow Chrome, and orientation and aspect-ratio read the truncated size. It is written for the translator, which PR 2 runs.
  • R8. On native, a transitioned property whose computed value differs between two bands of an assignment, or reads vw/vh/vi/vb/vmin/vmax, is refused until MQ-Rt (DRAGON_UNSUPPORTED_VALUE [ios]/[android], at the transition). It is a support fact, so like the animation gate it applies in enforce mode, not in the derive-mode lane compiles. ANIM-b1 is on master, so the refusal itself appears (no transition declaration is UNSUPPORTED_PROPERTY any more).
  • Proof: the resize traces (R5, R7 (a)). Fixture group media-runtime (ltr and rtl): mqr-width-switch, mqr-height, mqr-state-band (a free state across three bands), mqr-vw-relayout (no @media: relayout only), mqr-nested (nested and comma-list @media over 5 bands) and mqr-music-shape (the north star's two breakpoints at half scale), plus reject-mqr-17-bands and reject-mqr-env-feature. Each has a resize script on the 8 css px grid within 400x400. resize-capture.ts runs every script in Chrome through Page.setViewportSize (state steps morph the DOM in place) at DPR 1, 2, 2.625 and 3, and in the compiled web rendering at DPR 1; captures are committed under packages/parity/expected-resize/ (regen step resize-capture). The host lanes run each script on MediaRuntime: after the start and every step the program must be the per-case program of (app assignment, the band the compile-time partition gives that size) at that size with one layout per step (the R5 oracle), its engine frames must equal Chrome's exactly in zoomed LU, its background colours Chrome's computed ones, and the compiled rendering the authored one (chrome-dual). A test checks every script reaches every band of its fixture.
  • Media rows (R13). profile:rows derives at-rule:@media, media-feature:width and media-feature:height rows (context media) for ios and android (layout, linux-dragon-layout) and web (computed-value, chrome-dual) from the resize cases that pass.
  • Plants, each failing the resize lanes on the host: bandBoundaryExclusive (rt-band), bandStale, resizeSkipsRelayout and bandDeltaDropped. The device-only plants (mediaSizeFromWindow, rotationLosesState, activityRecreated) come with PR 2's device code.

Review round 1 (precomputed review of 2dac097)

  • High, animations in non-fold bands: every band's animation analysis now reports (each diagnostic once), and a transition or animation declared in a rule that applies only in some bands is refused on ios and android (... inside @media is unsupported on <target> ... (package MQ-Rt)), as on web until ANIM-mq. Tests: the review's @media (min-width: 400px) { .a { animation: spin 1s infinite } } and a band-only transition are refused; a keyframe refusal reached only in a non-fold band blocks.
  • High, slack against the exact partition: until MQ-R0 makes the partition take Chrome's 1/64 px slack, a native output that switches bands at run time refuses a sheet whose atoms the slack combines in a way the exact partition has no band for (closeThresholds: both evaluations at every breakpoint, threshold +-1/64 and between them; DRAGON_UNSUPPORTED_AT_RULE [ios]/[android] naming MQ-R0). The review's (width <= 400px) + (width > 400px) is refused. A test sweeps every root of 0 to 2048 whole device px wide or high at DPR 1, 1.75, 2, 2.625, 3 and 3.5 over every media and mqr fixture: each maps to a band, and away from a threshold to the partition's band; of the committed fixtures only media-range is refused (it keeps its fold-band device cases, which never look a band up). One rule each side: rt-band.ts is Chrome's (checked against the committed Chrome corpus); when MQ-R0 lands, whichever lands second removes the refusal and runs the sweep on MQ-R0's partition.
  • Medium, android: the resize lanes run both backends' band programs (uikit and android-views) at every DPR and step, with the R5 oracle, frames and colours; a test plants a fault in the android-views program alone. android-profile.test.ts checks that every resize case proving an android media row compiles unblocked for android, enforced, and passes its android-views lanes.
  • Medium, the 64-assignment cap: (assignments x bands) over 64 is DRAGON_STATE_SPACE_LIMIT [ios]/[android] at the first @media.
  • Low, @env: a document id starting with '@' is invalid input (reserved for the environment states).
  • Low, rows wider than the scripts: new fixture mqr-forms with a resize script covering plain = (with its slack at 352), a strict < range, an em max-width and a <= height range, every width group in both height groups. The boolean form (width) stays proven only by the corpus test: its band at width 0 no resize can reach.

Not in this PR, and why

  • mqr-epsilon and mqr-orientation (and orientation and aspect-ratio bands generally) need MQ-R0's evaluator and partition (in flight on mq-r0). This PR does not touch media/**. rt-band already implements Chrome's rules for all four features, and band-program.test.ts checks its atoms against the whole committed Chrome media corpus (every query Dragon evaluates, at every captured viewport) and its band lookup against every captured band sheet.
  • reject-mqr-transition is a compiler test (media-runtime.test.ts), not a parity reject fixture: R8 blocks ios and android only, and a parity reject must block every output.
  • rt-band cites Chrome's evaluator by function name, not by file, so docs/ports.json does not get a second media_query_evaluator.cc entry beside the one MQ-R0 adds.
  • Device runs are the landing driver's.

Outside the spec's file map

  • packages/parity/src/cli/resize-capture.ts, packages/parity/src/cli/resize-report.ts: the CLIs of resize-capture.ts.
  • packages/parity/src/profile-rows.ts (deriveMediaRows), scripts/gen-profile-rows.ts: the media rows.
  • scripts/regen.ts, .gitattributes: the resize-capture regen step and its merge entry.
  • packages/layout/src/index.ts: the rtBand export.
  • packages/dragon/src/analysis/input.ts: '@' reserved at the start of a document id.
  • packages/parity/src/media-runtime.ts: the runtime reference (the spec put it beside the compiler; the core may not run the engine).
  • package.json: two script lines (parity:resize-capture, parity:resize-report), not one.
  • packages/parity/src/fixture-groups/media.ts: the two reject message prefixes (below).

Changed tests and pins, with reasons

  • packages/dragon/test/media-wiring.test.ts: the MQ-a pins that native is resolved in the fold's band only now pin MQ-R1's rule that native is checked in every band, because a native root switches to every band at run time. So a refusal raised only in a band outside the fold blocks native too, a rule in no band (@media print) still blocks nothing, and the unwrapped @supports rules are checked for ios as well as web. The public-entry test now pins acceptance with the committed media rows, and a second test pins the profile-driven refusal with the rows stripped (message, span, profile field). The refusal messages are retargeted to the MQ-R2, MQ-R3 and MQ-R4 texts, and an MQ-R3 case is added.
  • packages/parity/test/media-sweep.test.ts: media-overlap's native refusal through the public entry becomes native acceptance.
  • packages/parity/src/fixture-groups/media.ts: reject-media-prefers-color-scheme and reject-media-resolution message prefixes are retargeted to the MQ-R2 text. Each still expects the same code, span and blocked outputs.
  • packages/parity/test/parity.test.ts: layoutRows also leaves out the media context, as it already leaves out animation. Media rows are proven by resize cases, and media-runtime-resize.test.ts gives them the same checks (exactly what profile:rows derives; exactly the passing cases that use the key). The paint-classification loop reads layout rows, since a media row keys no property.
  • packages/parity/test/p6a-promotion.test.ts: a row whose feature keys no property (a media row) has no paint aspect, instead of throwing on the lookup.
  • packages/parity/test/state-cases.test.ts, state-lanes.test.ts: derived counts 126 to 130 scripts and 22 to 24 groups, because mqr-state-band adds two assignments in two directions.
  • packages/dragon/test/s4b.test.ts, s5.test.ts: their "unsupported at-rule" example was a width @media, which native now accepts; it is @container (refused on every target), as s5's next test already uses since MQ-a.
  • packages/parity/test/android-profile.test.ts: the proving cases checked as native layout cases are those of layout rows; media rows are proven by resize cases, which media-runtime-resize.test.ts checks.
  • packages/parity/test/hit-capture-identity.test.ts: files beyond the pointer-events base may also belong to MQ-R1's mqr-* fixtures (new fixtures, not changed captures); the identity of every base file is unchanged.
  • packages/parity/test/device-vectors.test.ts, packages/translate/test/translate.test.ts: derived count of the hit suite 2028 to 2092 (one case per layout vector at every DPR; the 16 new layout cases, mqr-forms included, at 4 DPR sets).
  • packages/parity/test/glyph-clearance-pins.json: two entries appended for mqr-music-shape (ltr, rtl) with DRAGON_PIN_WRITE=1; no existing pin changes.
  • packages/parity/test/media-runtime.test.ts (new) holds the runtime reference's tests: MediaRuntime moved from the core to packages/parity/src/media-runtime.ts, since the core imports @dragon/layout for types only (ua.test.ts, dist.test.ts).
  • packages/parity/test/anim-bands.test.ts: a transition declared inside @media was pinned as refused on web and not on ios, because native resolved one band. Native now switches bands, so ios refuses it too (MQ-Rt, the review round 1 fix); the web refusal is unchanged.
  • packages/parity/test/values.test.ts is unchanged: the new group sits before values, which stays last before states.

…runtime reference and the Chrome resize traces

Native targets are checked and lowered in every @media band, and accept @media where their profile proves at-rule:@media and
each media feature in the media context (R13, retiring the until-MQ-R refusal). The band table (typed atoms, truth vectors) and
the band state program fold every band into the state program as the internal env#band variable (R4, R5); MediaRuntime is the
TypeScript reference of the runtime (one size change, one band delta, one layout); rt-band.ts is the device band lookup with
Chrome's 1/64 px comparisons and float media size (R2, R3). Transitions a size change would start are refused on native until
MQ-Rt (R8). Six media-runtime fixtures with resize scripts run on the band runtime and in Chrome through setViewportSize at DPR
1, 2, 2.625 and 3 (resize-capture.ts), and their passing cases derive the media profile rows.
…t before any enforce-mode compile of a media fixture (dpr-vectors saw ios blocked)
…tted CSS of the media-runtime fixtures, DPR, pixel, break and hit captures and vectors, profiles with the media rows, north-star check, lanes.json)
…oves to parity); rt-band in the translator subset; .gitattributes in step order; pins the new fixtures move (hit suite 2084, state scripts, glyph clearance additions, s4b/s5 at-rule example, android-profile and hit identity scope)
…tted CSS of the media-runtime fixtures, DPR, pixel, break and hit captures and vectors, profiles with the media rows, north-star check, lanes.json)
… banded transitions and animations refused on native (MQ-Rt), near-threshold slack combinations refused at run-time switching until MQ-R0 (with the off-grid sweep), android-views band programs on the resize lanes, the (assignment, band) cap as a diagnostic, '@' reserved in document ids, mqr-forms for the other comparison forms
…tted CSS of the media-runtime fixtures, DPR, pixel, break and hit captures and vectors, profiles with the media rows, north-star check, lanes.json)
…; anim-bands: ios refuses a banded transition until MQ-Rt; the resize test names the backend in its step label)
@thejackshelton thejackshelton added the landing-failed The landing driver stopped this PR; see its comment label Oct 5, 2026
@thejackshelton

Copy link
Copy Markdown
Contributor Author

Landing stopped at step merge (pnpm land)

merge-train: merging mq-r1 onto c78674a614f39a3ed5ee30aca2f68051b45a059d failed; conflicts in .gitattributes, package.json, packages/layout/src/index.ts, packages/parity/src/fixtures.ts, packages/parity/test/device-vectors.test.ts, packages/translate/test/translate.test.ts

Fix the cause, then hand #140 back to the landing queue with the new clean head.

…ers): the resize-capture step moves to scripts/regen-steps/mq-r1.ts (after capture, so before profile-rows), the media-runtime group to one sorted GROUPS line, .gitattributes sorted; hit suite 2092 beside master's animator suite
@thejackshelton thejackshelton added the regen Run pnpm regen on CI (regen-on-ci.yml) and push the outputs back label Oct 5, 2026
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated
to a fixed point, then pnpm regen --only tw-sweep (macos-26).
Base: fed6f56
Run: https://github.com/compiled-run/dragoncss/actions/runs/37275478198
@github-actions github-actions Bot removed the regen Run pnpm regen on CI (regen-on-ci.yml) and push the outputs back label Oct 5, 2026
…e, as in Chrome

44 Chrome 145 alias_for entries whose property Dragon compiles (flex, box-sizing, logical
margins, paddings, borders and sizes), registered per family in css/aliases/<family>.ts.
Aliases Chrome parses with UseAliasParsing, and the -webkit-writing-mode surrogate, stay refused.
Fixture group aliases (alias-flex, alias-logical, reject-alias-legacy-parsing).
…lowering takes the image naturals and its programs the images and moving transforms; the hit suite checks move to master's p1-floor.json
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated
to a fixed point, then pnpm regen --only tw-sweep (macos-26).
Base: 4d4251d
Run: https://github.com/compiled-run/dragoncss/actions/runs/37326048481
@github-actions github-actions Bot removed the regen Run pnpm regen on CI (regen-on-ci.yml) and push the outputs back label Oct 5, 2026
thejackshelton and others added 3 commits October 5, 2026 10:42
… (the hit suite grows by the media-runtime layout vectors)
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated
to a fixed point, then pnpm regen --only tw-sweep (macos-26).
Base: bb32cfb
Run: https://github.com/compiled-run/dragoncss/actions/runs/37326021043
…, used by nativePrograms and nativeBandPrograms alike, so an img under a transform only a band change moves gets the direct draw in every band
@thejackshelton thejackshelton added landing-failed The landing driver stopped this PR; see its comment and removed landing-failed The landing driver stopped this PR; see its comment labels Oct 5, 2026
@thejackshelton

Copy link
Copy Markdown
Contributor Author

Landing stopped at step merge (pnpm land)

merge-train: merging mq-r1 onto 62e5af4628e721b0772622a84404b2996a5c5201 failed; conflicts in .gitattributes, package.json

Fix the cause, then hand #140 back to the landing queue with the new clean head.

… expected-quads and expected-resize, both sides' package.json scripts
BG2-a: gradient raster engine (paint-gradient.ts) on master, unstacked (supersedes #99's engine)
…laims and the native profile tests (PR CI skips them; chrome-ports failed #197 at landing)
…y-claims, api-floor, floor-merge, macroscope-ignore) on every PR
…ild already regenerated the tree); regen jobs beside the shards; 4 Chrome shards; durations from run 37399249352
…l), strict otherwise; a device failure is a judge-devices problem with a count per case and its first details, not a driver error (#91)
…s; MQ-PREF is MQ-R2 and waits for MQ-R1 runtime and PNT1
… Chrome-proven outline geometry; a1 web, a2 native, unstacked)
…grew 1 MiB: spawnSync git ENOBUFS failed the landing proof)
@thejackshelton
thejackshelton merged commit 2ba6984 into master Oct 6, 2026
5 checks passed
@thejackshelton
thejackshelton deleted the mq-r1 branch October 6, 2026 04:58
@thejackshelton thejackshelton removed the landing-failed The landing driver stopped this PR; see its comment label Oct 6, 2026
thejackshelton added a commit that referenced this pull request Oct 6, 2026
… keeps expected-resize and expected-scroll (sorted); profile-rows.ts keeps MQ-R1's deriveMediaRows and MEDIA_CONTEXT beside OVFL's PROFILE_NOTES note writer
thejackshelton added a commit that referenced this pull request Oct 6, 2026
…-wiring.test.ts keeps both sides: MQ-R1's every-band expectation (native and web both analyse the unwrapped rules) with CASC's @layer as the refused enclosing at-rule, since @supports is now decided
thejackshelton added a commit that referenced this pull request Oct 6, 2026
…and the rest) into inl1a-lowering. Conflicts keep both sides: LayoutStyle carries INL1a's verticalAlign and GRID's grid and gridItem (input.ts, validate.ts schema and anonymous initials, environment.ts zoom, harness.ts decoders, STYLE_FIELDS, corpus and test style literals); Display is block, flex, grid or inline; unsupported.ts holds INL1a's inline codes and grid-layout; context.ts has INL1a's text-in-inline and text-beside-inline beside GRID's text-in-grid-item and text-as-anonymous-grid-item, and an inline item base before the flex and grid ones; ios-layout lowerBox takes the Lowerer and the grid parent: an inline-level run in a flex or grid container is an anonymous item (auto-placed in a grid), and a grid item is blockified so never an inline box; the hand-frozen calc goldens and vectors README gain the grid fields beside the inline ones (each file equals INL1a's without the grid keys and master's without the inline keys). Composition: validate.ts refuses a grid style or placement on an inline box, and text-in-flex covers inline content in a grid container; corpus-dpr INLINE_STYLE and two MQ-R1 tests gain the fields of the other side. Tests: grid.test (layout) and inline-lowering.test (dragon) cover inline content in grid containers
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