Repository navigation
iOS host app: generated case code as its own module at -Onone, engine and support at -O (app build 94-119 s -> 16 s, device results identical) - #166
Merged
Conversation
…ame as block-level boxes and flex items Route 2a (T051J): object-fit and object-position are real longhands (box family, after padding-left; paint aspect; webref grammar via gen-css-grammar.ts). object-position parses as Chrome 145 computes it (probed: 1, 2 and 4 values, keywords to percentages, an offset from right or bottom as 100% - p% or 100% for 0; calc and non-px lengths refused; 3 values invalid). img and iframe are supported tags (analysis/elements/replaced.ts) that read REPL-0's replaced keys through the new datasets.ts uaRows accessor; resolve.ts applies the keys' forced values (iframe overflow: clip) and the HTML width and height presentational hints (and img's auto w / h aspect-ratio hint). src, alt, width and height are handled attributes. The images option maps a src to a snapshot asset (images/compile.ts): every img src is a data: URL or a mapped asset, else DRAGON_REMOTE_IMAGE; an image REPL-a cannot draw is DRAGON_UNSUPPORTED_IMAGE naming its package; the manifest enters the digest. Inline-level and positioned replaced boxes are refused on every target (RF-INL; CSS 2.2 §10.3.8). The ios lowering writes replaced leaves (natural size from the manifest, overflow clip as visible). Fixture group replaced: block, flex row and column, intrinsic and the demo's cover, song image and video slot, ltr and rtl, plus 6 rejects. North star: the four cover URLs map to covers/*.png (stand-ins, R1). scripts/check-object-fit-migration.ts proves every existing capture, emitted body and UA entry differs only by the two initial values and no engine input changes, with 9 plants. replaced-identity.test.ts proves earlier cases resolve both longhands to their initial values and lower to their committed vector inputs and web bodies. Retargeted pins (reasons in the tests): seams LONGHANDS and paint role, s4b paint role, paint-seams longhand count, attributes (img rows now handled), block-elements tag table, reject-attr-img-src (now DRAGON_REMOTE_IMAGE), css-escapes twin count (+52 from the two grammars), glyph clearance (+4 per DPR, replaced-demo text).
…re, parity:capture, profile:rows, parity:capture, layout:vectors, parity:dpr-capture, layout:dpr-vectors, layout:break-vectors, parity:break-capture, parity:pixel-capture, layout:paint-vectors, native:gen, parity:lanes -- --run-host, node --conditions=dragon-internal examples/music-player/tools/check.ts, wpt:run -- --target web, parity:glyph-b3 -- --write-bottom-pins, tw:sweep. packages/wpt/expectations/web.json: only the 10 not-runnable reasons wpt:check reported changed (img entries now refused later, at their image, display or another declaration), rewritten by a /tmp one-off from the Chrome-free wpt:check output with every status and other field unchanged. node scripts/check-object-fit-migration.ts 33ea628: captures 1802 files, all changed only by 66212 initial object-fit/object-position keys; emitted 354 files, 15386 initial declarations; UA 2 files, 192 entries; engine inputs 4497 files unchanged; new files only from the 11 new fixtures. Profiles 1938 rows per native target (web 1944). Tailwind sweep web and ios 2229 supported (object-fit utilities).
… iframes as platform web view slots The image paint module (lower/paint/image.ts, emit/paint/image.ts) embeds each img's PNG bytes (the build read them, images/compile.ts) with its natural size and object-fit; the box view decodes them once at build (ImageIO, BitmapFactory: synchronous, so a capture never waits on a decode) and, in the image stage after the border, draws the bitmap into the destination rect clipped to the drawn part of the content box. DragonTree.apply computes the content box, destination and drawn rects after layout through a new engine paint root, paint.ts replacedPaint (translated). No UIImageView contentMode or ImageView ScaleType. The foreign-view module (lower/emit foreign-view.ts) puts a WKWebView (inline media, no gesture) or an android.webkit.WebView (JavaScript, no gesture, in a Dragon host group) over the content box; lane builds load about:blank only. Readbacks: the image's natural size, fit and destination rect; the web view's class, flags and frame; the expected dumps project the same from the engine (expected-dump replacedGeometries). Sample rules (paint-samples): image-flat points where the decoded source is uniform over every filter's support (ceil(1/scale) + 2 source px), edge scanlines across destination edges inside the content box, base rules on non-flat image content dropped, and every base rule inside a web view masked; image-flat is compared at GATE_CHANNEL_DELTA (no allowance). Raster plant image-offset-1 (every image drawn 1 device px right; native-devices refuses it as a glyph plant, it is judged by parity:lanes on a planted build). Fixture replaced-fit: every fit with keyword and length positions, letterboxed inside the viewport. replaced-paint.test.ts: at every image-flat point the committed Chrome screenshot shows exactly the source colour the engine maps there (DPR 2, 3, 2.625), every destination edge inside a content box is within 1 device px of Chrome's, no kept point lies on non-flat image content or in a web view, and the demo's dumps pin the cover and video slot geometry. check-object-fit-migration.ts also proves Chrome line breaks unchanged and the pixel manifest's base entries unchanged (two more plants). Retargeted pins (reasons in the tests): SAMPLE_RULES and the per-kind deltas gain image-flat; the EMS seam pins (engine paint.ts root, compiler image and foreign-view modules, support files, stage painters, plants); SUPPORT_PLANTS gains image-offset-1. Native support: DragonBoxView gains the replaced paint rects, the runtimes track replaced leaves.
…le:rows, parity:capture, profile:rows, parity:pixel-capture, then parity:capture, profile:rows, layout:vectors, parity:dpr-capture, layout:dpr-vectors, layout:break-vectors, parity:break-capture, parity:pixel-capture, layout:paint-vectors, native:gen (Paint.swift and Paint.kt: the replacedPaint root; extended digest d1ea5e56), parity:lanes -- --run-host, node --conditions=dragon-internal examples/music-player/tools/check.ts, parity:glyph-b3 -- --write-bottom-pins, wpt:check -- --target web (every entry matches), tw:sweep (web and ios 2230 supported). node scripts/check-object-fit-migration.ts 33ea628 exits 0: captures 1802 changed only by initial object-fit/object-position keys, emitted 354, UA 2, engine inputs 4497 and line breaks 1344 unchanged, pixel manifest base entries unchanged; new files only from the 12 new fixtures (the 7 replaced layout and rejects plus replaced-fit). Profiles 1940 rows per native target (web 1946).
…ed by intent: project.ts keeps master's MQ-a band passes and compiles REPL-a's images from every band's resolved cases (the manifest still enters the digest beside the band inputs); ios-layout.ts lowers through master's rootFontSizeOf with the image naturals; stylesheet.ts imports both <position> and <ratio> parsers with master's math checks; pins: paint-seams LONGHANDS 71 (aspect-ratio, object-fit, object-position), css-escapes twins 13834 (+4 SIZE-ar, +52 REPL-a), pixel-reference takes size-ar's (recomputed after regen); generated outputs take the merged side, rebuilt by pnpm regen
…ved by intent: image-offset-1 becomes a paint plant in master's P6a plant mechanism (PLANT_CASES replaced-block and replaced-fit, PLANT_RULES image-flat and edge; native-devices.ts is master's); the paint registries list the dash plants and the image plant and the image and foreign-view lowerings; native-program keeps master's rootFontSize with REPL-a's image bytes; expected-dump's NodeGeometry carries master's fontSize and REPL-a's replaced paint rects; the SELD-R state runtime refuses an image or web-view write by name; pins: paint-seams (plants, support files, the REPL-a paint root and index lines), device-run (plant lists); generated outputs take the merged side, rebuilt by pnpm regen
…gits overflow a double (Number() gives Infinity) is refused as DRAGON_UNSUPPORTED_ATTRIBUTE instead of reaching a presentational hint (the native emitter throws on a non-finite engine input); parseDimension returns null for it as a backstop. attributes.test covers parseDimension (white space, fraction, percentage, trailing text, non-digit starts, overflow), presentationalHints (img auto && ratio, percentage, iframe, non-replaced tag, overflow) and the compile refusal
…@media writes only the longhands that differ, so it gains no object-fit/object-position; count only rules outside @media (as check-aspect-ratio-migration does) and add the emitted-media plant (neutral declarations planted in an @media rule must fail). Against origin/master: 1898 captures, 378 emitted, 2 UA files additive only; engine inputs unchanged; all 10 plants fail
…ixed point after 3 passes) on repl-a merged with the REPL-a engine and master: captures, emitted CSS, UA-derived profiles, grammar, vectors, DPR outputs, media, wpt web expectations, tailwind sweep, north-star check, corpus-dpr, lanes.json (host). scripts/check-object-fit-migration.ts origin/master proves the object-fit/object-position additions neutral
…100 PNG compiles to DRAGON_UNSUPPORTED_IMAGE 'the PNG does not parse: zero image size' with blocked outputs. PNG IHDR and JPEG SOFn forbid a zero dimension, so no decoded image is ever 0xN in Chrome or Dragon and there is no Chrome layout to capture; the engine's empty-natural-size rule (Blink ComputeObjectFitAndPositionRect) is reachable only from a hand-written layout input and stays pinned in replaced.test.ts. Planted prefix fails parity.test's row
…a 2/3: device-pixels ios 555 (master 65), android 824 (master 94). Every failure outside the 11 replaced fixtures is line-identical to master's; the +490/+730 are all in replaced-* cases, where Phase A paints the replaced box (background, border) and Chrome shows the image content Phase B (repl-a-phase-b) paints. device-applied, device-lines and layout-vectors-device pass on both platforms
…rofile-rows, fixed point after 2 passes) from repl-a 2/3's device record
… +4 at DPR 2, 3 and 2.625 on both targets, all from the new replaced-* cases (every added dropped edge rule keeps clear colour points); with the replaced-* cases filtered out master's pins hold exactly
…foreign-view emitter threw an uncaught Error on a quote, backslash, $ or control character in it; srcLit now escapes as native-support.ts stringLit does (paint modules never import native-support), and paint-seams.test checks the two agree on quotes, backslashes, $, interpolation, controls, non-ASCII and astral characters. images.test checks base64Encode (the PNG bytes the image paint embeds) against Node's RFC 4648 encoder on every length remainder, all byte values, 64 seeded buffers and the 46 corpus PNGs
…roups keep master's order with replaced after inline; pixel-reference pins compose additively (master's inline-breaks terms plus REPL-a's +4 replaced-* terms); generated outputs keep this side and pnpm regen rebuilds them
…-a: device-failures-*.json take master's (device-run outputs; train 2's device run rewrites them); generated outputs rebuilt by pnpm regen next
…e.sh pnpm regen, fixed point after 3 passes): emitted CSS, captures, DPR and font captures, glyph and pixel references, profiles, corpus-dpr, lanes.json (host). Device lanes are left to train 2's own device run
…3920, 4164413940): - object-position edge keywords are decoded (css-syntax escapes) and matched ASCII case-insensitively, as aspect-ratio's auto is; aspect-ratio.test pins \6c eft top, \72ight b\6fttom and LEFT Top. - an iframe src is refused (DRAGON_UNSUPPORTED_ATTRIBUTE, owner REPL-a Phase B) instead of being accepted and dropped: Phase A lays out an empty slot and Phase B's web view loads src. - check-object-fit-migration strips the neutral emitted declarations only outside @media, so declarations moved into an @media rule fail the base comparison (plant emitted-moved-to-media), and requires exactly one object-fit/object-position pair in every row of every UA computed table (plant ua-row-missing). Clean against origin/master; all plants fail. - explain names a forced UA value (iframe overflow: clip) as what beat the author winner (ResolvedValue.forcedOver), keeping the cascade reason for the declarations that winner beat; block-elements.test pins both reasons.
…ads src from the element), where it loaded about:blank in every build. The emitted support declares dragonForeignViewLoadsSrc (true); both parity lane hosts clear it at launch, so lanes and tests still never load network content (about:blank). The compiler accepts only an absolute http or https src written in RFC 3986 characters (a native web view has no document URL for a relative one; Foundation URL(string:) rejects other characters) and refuses any other as DRAGON_UNSUPPORTED_ATTRIBUTE; lowering passes the white-space-stripped URL. Tests: iframeSrcUrl/iframeSrcRefusal cases and the compile refusal (attributes.test), the emitted load and both hosts clearing the flag before any case runs (replaced-paint.test)
Commands: pnpm regen
Commands: pnpm regen
tw-sweep: compile on every core; Chrome checks on 8 pages, each capture one JSON string (same snapshot)
Chrome captures: pixel, DPR and break captures take 8 cases at once (same bytes)
Commands: pnpm regen
Lanes verdict at the edge: lanes.json no longer invalidates every regen step
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
Commands: pnpm regen
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
DEVICE-SPEED a: boot the devices while the apps build and the host lanes run; only the vectors verdict waits for its host run
DEVICE-SPEED b: Android quickboot from a golden snapshot (same device results, ~25-30 s less per emulator boot)
COMPILE-SPEED 1: digest input sorted on keys serialised once, profile rows indexed by feature (outputs byte-identical; 506 parity compiles 19.4 -> 13.0 s)
COMPILE-SPEED 3: digest profiles and asset bytes by SHA-256 (digests change once, regen commit; 506 parity compiles 26.4 -> 7.6 s)
Commands: pnpm regen
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
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.
What changed (DEVICE-SPEED, from COMPILE-SPEED's design decision 1, approved by the PM): the iOS host app is now built as three Swift modules instead of one
swiftc -Ocall over 124 files.DragonLayout/) and the runtime support (Support/)-O, as before (the shipped code path)LayoutBox(...)construction)-Onone, with-enable-testingHost/*, the two case tables, and any planted file-O-import-module).-force_load, so every object is in the app as before.appstamp, is unchanged.String(describing: type(of:)), which the dump uses for native classes, is not module-qualified.IOS_BUILD) is part of the reuse stamp, so an app built the old way in a worktree is rebuilt, not reused.iosModulesassigns every Swift file to exactly one module, and throws if the case tables or main.swift are missing, or if any module would be empty.Measured:
swiftc -O -j 18; land logs; 104–118 s in this lane's baselines)The launch is 5–9 s slower, because the -Onone case construction runs on the device. The build saves 60–100 s.
Proof. A full local device run (
parity:devicesthrough/tmp/device-lease.sh, runonone), with the app built fresh inside the run, was compared with master's committed records (/tmp/dds/compare.mts):deviceRunProblems: no problems;device-failures-ios.jsonanddevice-failures-android.json: byte-identical (57 and 86);lanes.json: 0 differences outsideevidence.laneCode.The planted floor fault still fails the build:
native:build -- --target ios --plant ios-16gives "planted ios-16 caught by swiftc availability checking". All three modules build for the iOS 15 target. The raster plantglyph-offset-1builds.Tests:
vitest rundevice-lanes, lanes-concurrent and state-cases: pass.pnpm typecheck: pass.native:build -- --target ios: pass, 507 cases.Device step pending: lanes-records, p6a-promotion and device-failures fail only because native-host.ts is in
EVIDENCE_CODE, so the lane-code hash changed.Overlap: native-host.ts is not touched by #157, #159, #132 or #135.
Size: about 9 KB of reviewed diff.
🤖 Generated with Claude Code