Repository navigation
SVG-a1: inline <svg> (path, rect, circle; fill, stroke, stroke-width) on web, proven by a strict outline differential against Chrome; native refused as SVG-a2 - #206
Conversation
…ect> and <circle> with fill, stroke and stroke-width on web, proven by a strict outline differential against Chrome - The svg property family (fill, stroke, stroke-width; inherited), with Chrome's grammars, and the SVG presentation attributes as hints below author rules (they now beat inheritance too). - svg as a replaced key and the shapes as UA keys (the UA capture creates SVG-namespace elements); svg is a replaced element whose shapes are its content; tags, attributes, structure and values refused with named packages (SVG-arc, SVG-units, SVG-b, SVG-paint, SVG-dash, SVG-stroke, SVG-opacity, SVG-transform, SVG-ratio); native refuses svg as SVG-a2 (lane-only, like SELD-R2). - Path data, viewBox and number attributes parsed as Chrome builds them (analysis/elements/svg-path.ts); bounds as Skia's ComputeTightBounds and gfx::BoundingRect (packages/layout/src/svg-geometry.ts). - The parity layout lane compares every shape's getBBox, getScreenCTM, getBoundingClientRect and computed paint with Dragon's exactly (svg-compare.ts), with five plants; the fixture reader reads SVG foreign content; device samples inside an undrawn svg box are dropped until SVG-a2. - Fixture group svg: svg-basic, svg-viewbox, svg-paint, svg-flex (ltr and rtl) and ten rejects.
…kGeometry, SkPathPriv, rect_f.cc BoundingRect)
…t (it set fill on html, refusing every interaction case)
… parity lanes, as the svg element's are
…BBox values, the viewBox and client-rect arithmetic against captured CTMs and rects, the fixtures' strict differential and its five plants; retargeted pins for the svg family and keys (element table, replaced keys, paint-role pairs, the float32 exemption for svg-path.ts, the identity checks, stroke-width's number-or-length math grammar)
…n2: pnpm regen, fixed point; the svga1-regen runs that failed on lane checks were fixed in source and rerun): the grammar with fill, stroke and stroke-width, the Chrome UA dataset with the svg and shape keys, every capture and emitted rule with the svg family's keys, the svg fixtures' captures, vectors and break vectors, the web profile rows, NOTICES, the native lanes record, the hit facts, the translated unions and corpus, the tailwind sweep and the north-star check
…-a2; SVG paint attributes keep a stand-in declaration so the support profile checks them as the same CSS value; viewBoxTransform is Chrome's arithmetic, which the differential now uses
…en3: pnpm regen, fixed point after 3 passes): the hit facts without the svg cases, the web profile rows (stroke:none from svg-paint's attribute), the lanes record, the translated unions and corpus, and the tailwind sweep
…sform- cases (their reason) and the eight named svg cases (the SVG-a2 reason), from test/hit-refusals-svg.ts beside #91's hit-refusals.ts
|
Landing stopped at step Fix the cause, then hand #206 back to the landing queue with the new clean head. |
…losures, no Math.min/max/sqrt or DataView: subset helpers and sqrtF64, a power-of-two next-float); the colour-only plant test accepts exactly the colour longhands plus fill and stroke, which the plant moves too
…egen, fixed point after 2 passes): the translated unions and strings
…NDS beside master's MEDIA_CONTEXT)
…m regen, fixed point after 3 passes)
…: capture.ts records an svg shape's bbox and CTM beside INL1a's inline-box line fragments; hit-capture.ts hitRefusal refuses transforms, then an <svg> by name, then INL1a's inline box or <br> (rt-hit.ts); parity.test.ts imports COLOR_LONGHANDS beside iosLayoutProjection; hit-refusals-svg.ts folds into master's shared hit-refusals.ts (SVG_OUT, SVG_REASON beside INLINE_OUT), and hit-report.test.ts and lanes.test.ts judge the exact union of the three named refusals
…ed display inline, laid out by SVG as Chrome's LayoutSVGShape) records no <id>:line<j> fragments
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: 76f2a78 Run: https://github.com/compiled-run/dragoncss/actions/runs/37831539343
…> fragments (pins 2011c9b's capture.ts fix: a shape's computed display is inline, but SVG lays it out) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
…mputed-checks.ts walks with OVFL's scroller and checkPercentRelative and gives an svg shape only SVG-a1's checkSvg; replaced-identity.test.ts excludes OVFL's overflow-replaced and the svg fixtures as later fixtures with replaced leaves, and pins both REPLACED at 6 and the excluded set Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: 6c2fc83 Run: https://github.com/compiled-run/dragoncss/actions/runs/37840937873
…tual conflicts locally (GitHub's conflict is in generated outputs the dragon merge driver keeps; regen rebuilds them) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: d6b7a4e Run: https://github.com/compiled-run/dragoncss/actions/runs/37848611592
…e.svg) must be one of Dragon's scene shapes, and null svgScenes (no resolved case) with captured shapes fails instead of passing as []; pipeline.ts and svg.test.ts pass the scenes through without ?? []. svg.test: dropping one shape per case, every scene, or returning null scenes each fails the differential (review finding on 7787d4b) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
|
LAND-READY Lane receipt (PM session A): pnpm typecheck pass; platform-free dragon {block-elements,s4b,svg,ua-elb2,ua,registry-claims,profile-index} pass (local, at 205b6b3); ci:regen https://github.com/compiled-run/dragoncss/actions/runs/37856505325 (already at a fixed point at 205b6b3); ci:test-files https://github.com/compiled-run/dragoncss/actions/runs/37860530081 (tested 205b6b3 at 205b6b3: parity 532, svg 6, hit-report 9, replaced-identity 3, chrome-ports 13, parity registry-claims 8, android-profile 5, and the fixture-wide set p6a-dash-oracle 312, dist, env-engine, fixture-reader, fonts-fixtures, inline, interaction-forced, media-runtime, media-sweep, phrasing-blockified, platform, tree-faults, values all pass; lanes.test "every device lane ran" is device step pending); pr:review 206 --once exit 0 (UNREVIEWED: Macroscope spending limit). Independent Claude review at 205b6b3 (Medium or higher only). The first review at 7787d4b found that the SVG differential was one-sided; 205b6b3 fixes it with a test that fails without the fix, and the re-review of that fix is clean: {"pr":206,"head":"205b6b35eff8dc147fe9331a3e6fda6839e55403","findings":[]}Generated by Claude Code |
…into svg-a1. Conflicts: hit-capture.ts hitRefusal refuses transforms, then an <svg> by name (SVG-a2), then a rounded corner (PNT1), then INL1a's inline box; withoutPointerEvents uses master's KEYS_SINCE_BASE, which now lists the svg family (fill, stroke, stroke-width) beside the radii, with a new hit-capture-identity case; hit-report.test.ts and lanes.test.ts judge the exact union of the four named refusals (transform, radius, inline, svg) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: 653f1d6 Run: https://github.com/compiled-run/dragoncss/actions/runs/37871598420
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: 221e278 Run: https://github.com/compiled-run/dragoncss/actions/runs/37876508813
…conflicts locally (GitHub's conflict is in generated outputs; regen rebuilds them) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: 9fa89a5 Run: https://github.com/compiled-run/dragoncss/actions/runs/37880889006
…erty) into svg-a1. Conflicts: properties.ts keeps GEN-b's lists family, then SVG-a1's svg family last; gen-css-grammar.ts SUBSET keeps GEN-b's content and list-style entries, then SVG_LONGHANDS last; computed-checks.ts keeps checkSvg beside GEN-b's checkComputed(…, faults: GenBFaults) signature; s4b.test.ts and ua.test.ts keep both single-file rounding exemptions (CASC 2's css/chrome-number.ts and SVG-a1's analysis/elements/svg-path.ts) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: 563d475 Run: https://github.com/compiled-run/dragoncss/actions/runs/37889551569
…dth) and GEN-b's list-marker refusal both fire, so checkSvg and checkComputed's GEN-b checks stay side by side after the #218 merge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
…ly at their initial values (rgb(0, 0, 0), none, 1px, in LONGHANDS order), as GEN-b's neutral longhands are, not at any value; hit-capture-identity.test: each non-initial fill, stroke or stroke-width still differs from the base (review finding on 0c6ada6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
… layers, #232 GEN-c counter text) into svg-a1. Conflict: stylesheet.ts Declaration keeps SVG-a1's presentationHint beside CASC 3's layer (a hint applies only when no author declaration, layered or not, wins) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
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: 366f8c2 Run: https://github.com/compiled-run/dragoncss/actions/runs/37923589554
… a paint presentation attribute, which sits below every author layer (after the #233 merge) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
|
LAND-READY Lane receipt (PM session A): master merged through b97cf50 (#208, #198, #210, #101, #218, #216, #203, #102, #233, #232; resolutions in hit-capture.ts, hit-report/lanes tests, properties.ts FAMILIES, gen-css-grammar SUBSET, computed-checks.ts, s4b/ua exemptions, stylesheet.ts Declaration with both presentationHint and layer). pnpm typecheck pass; 16 platform-free files pass (local, at 565cdba); ci:regen https://github.com/compiled-run/dragoncss/actions/runs/37934126509 (already at a fixed point at 565cdba); ci:test-files https://github.com/compiled-run/dragoncss/actions/runs/37934142200 (tested 565cdba at 565cdba: 35 files incl. parity 564, svg, hit-capture-identity, hit-lanes, casc-layer, pixel-reference, native-host and the fixture-wide set, all pass; lanes.test "every device lane ran" is device step pending); pr:review 206 --once exit 0 (UNREVIEWED: Macroscope spending limit). Note for the driver: #206 conflicts with #196 (math.ts, s4b.test.ts, hit-capture.ts, hit-refusals.ts, hit-report.test.ts, lanes.test.ts; all additive) and #231 (layout/src/index.ts). Whichever lands later needs its lane's catch-up. Independent Claude review history (Medium or higher only): at 7787d4b (one-sided SVG differential) and 0c6ada6 (svg family stripped at any value in the identity hash), both fixed with tests that fail without the fix; re-reviews clean at 205b6b3 and 0633c38; the final merge with #233/#232/#203/#102 and the layer-vs-hint test are clean at 565cdba: {"pr":206,"head":"565cdbab1af58b7712c0d4f6a647240bdc93cfa1","findings":[]}Generated by Claude Code |
|
Landing stopped at step Fix the cause, then hand #206 back to the landing queue with the new clean head. |
This PR is SVG-a1, the compiler and web half of coverage-rank lane 16 (inline SVG, reach 395). The spec is /tmp/specs/svg-a.md, approved by the PM ruling of 2026-10-05: interior-sample pixel proof plus a strict, Chrome-proven outline differential, in two sequential unstacked PRs. Native drawing is SVG-a2, off master after this one lands.
It adds an inline
<svg>laid out as a block-level replaced box (REPL-a's model), drawing<path>,<rect>and<circle>withfill,strokeandstroke-widthfrom CSS or presentation attributes. It is proven on web against Chrome, in both directions. Native refuses<svg>as SVG-a2.What changed
The svg property family (
css/properties/svg.ts, one line in FAMILIES):fill,strokeandstroke-width, all inherited, with Chrome's grammars (gen-css-grammar overrides):<paint>takes<color>, which webref's grammar omits.stroke-widthis one non-negative length, percentage or (SVG quirk) number.thinand comma lists are invalid in Chrome (probed).A unitless stroke-width computes to px. Animation kind is UNADMITTED. The native hit test models the family, since it paints no box; without that, the UA
fillonhtmlrefused every interaction case.Elements and the UA dataset:
svgjoins REPLACED_TAGS;path,rectandcirclejoin SUPPORTED_TAGS.createElementNS). It capturessvg(overflow hidden) and the shapes (transform-origin: 0 0) into the replaced-key tables.<svg>'s content and never a box: the layout lowering already skips a replaced element's children, and the computed checks give shapes only the SVG checks.Attributes (
analysis/elements/svg.ts):d,x,y,width,height,cx,cy,r,viewBox.width/height, become presentational hints.Path data, viewBox and numbers (
analysis/elements/svg-path.ts) are parsed as Chrome builds them:-0.785is-0.7849999666213989, not the nearest float.Bounds (
packages/layout/src/svg-geometry.ts): Skia's ComputeTightBounds, its extrema and eval helpers, TrimmedBounds for paths of lines only, andgfx::BoundingRect's next-float growth. All are ported in float32 and registered in docs/ports.json (SkGeometry.cpp and .h, SkPathPriv.cpp and .h, rect_f.cc).The strict outline differential (
parity/src/svg-compare.ts, part of the host layout lane). Every shape'sgetBBox,getScreenCTM,getBoundingClientRectand computedfill/stroke/stroke-widthmust equal Dragon's as doubles or strings, with no allowance.getBBoxandgetScreenCTMfor SVG shapes only, so every other capture is byte-identical apart from the new longhands.Refusals, each with a reject fixture or a unit test naming its package:
<svg>: RF-INL, as for img.<g>, text, nesting, shapes outside<svg>, and CSS geometry on shapes: SVG-b.url()and context paints: SVG-paint.transformattribute andpreserveAspectRatio: SVG-transform.<svg>on native: SVG-a2.In the parity lanes, native lays out the svg box without its shapes. As with SELD-R2's lane-only interaction, its rows prove nothing for native, and device samples inside an undrawn svg box are dropped (
paint-samples/image.ts).Fixtures (group svg, ltr and rtl):
svg-basic: path with cubics, quads and smooth curves; rect; circle.svg-viewbox: meet on each axis, offset viewBoxes, padding and border, CSS size over the attributes, no viewBox, the 300x150 default, and float32-sensitive decimals with exponents.svg-paint: inheritance, currentcolor, attribute against CSS precedence, none, and a unitless stroke-width.svg-flex: svg as a flex item.Review round (precomputed review of 1f834fa)
hitRefusalnow refuses every case with an<svg>by name: "hit testing an svg's shapes comes with SVG-a2". Chrome hits the painted shapes (visiblePainted), which the hit test doesn't model yet.hit-report.test.tspins the refused set as exactly the transform cases plus the 8 svg cases.rt-vectors/hit/facts.jsonis regenerated without them.fill,stroke,stroke-width) now resolves with a stand-in declaration at its element's start tag (Declaration.presentationHint).usedKeystherefore keys it like a CSS declaration, and the same rows decide both.DRAGON_UNSUPPORTED_VALUEnaming the attribute, as checkValues reports the CSS value.fill="#ff0000",fill="red",fill="rgba(255, 0, 0, 0.5)",fill="transparent"andstroke="#00f"are each blocked with exactly the diagnostics their CSS equivalents give. Proven rgb() and number values compile from either.stroke:none(paint/ltr and rtl) from svg-paint'sstroke="none"attribute, and the tailwind sweep shows all 6 svg utilities compiling on web.viewBoxTransform(svg-geometry.ts) now uses Chrome's arithmetic: it branches on the ratio and centres in user units (with asliceflag for meetOrSlice). svg-compare uses it directly, so there is one implementation, pinned by the captured CTMs.pnpm typecheck.pnpm regenvia/tmp/job.sh svga1-regen3, fixed point after 3 passes.packages/parity/test/hit-report.test.ts.Rows promoted (web only, all
exact, each in paint/ltr and paint/rtl)fill:<rgb()>,fill:currentcolor,fill:nonestroke:<rgb()>,stroke:nonestroke-width:<length-px>,stroke-width:<number>No native rows: SVG-a2 adds them after the driver's device run.
The tailwind sweep shows 5 of its 6 svg utilities now compile on web.
Music-player north-star delta
Only the supported-tags list in the
<button>refusal messages changes (it now names svg, path, rect and circle). The music player has no SVG in its tree, so nothing new compiles or is refused.What passed
pnpm typecheck.pnpm regenvia/tmp/job.sh svga1-regenandsvga1-regen2, reaching a fixed point. Earlier attempts stopped on lane checks (hit-test facts, lane-only profile refusals and the native frames check); I fixed those in source, as the commits say.dragon/test/svg.test.tsandparity/test/svg.test.ts, chrome-ports, both registry-claims, the identity tests, the UA and paint-role tests and the android profile test.parity/test/svg.test.ts.pnpm testwas not run, per the lane contract. Device lanes are the driver's job;native-lanes.tsrecords them as not yet run (device step pending).Changed tests, and why
dragon/test/block-elements.test.ts: the element table excludes the shape tags, which read replaced keys as the replaced tags do.dragon/test/ua-elb2.test.ts: the replaced-key tables list svg and the shapes. A new pin checks their UA values.dragon/test/s4b.test.ts: stroke-width gets two width values instead of the colour pair. The "(iii) colour conversion stays in css/color.ts" check and the same scan indragon/test/ua.test.tsexemptanalysis/elements/svg-path.tsby path. That follows the fonts, forms and media/viewport.ts precedent: the file reproduces Chrome's float32 path-number arithmetic, and svg.test.ts pins it.dragon/src/css/math.ts: stroke-width takes the number-or-length-percentage math grammar, as its syntax gives. This is source, but math-validity.test checks it.parity/test/replaced-identity.test.ts: the svg fixtures postdate REPL-a and hold a replaced leaf on purpose, so they are excluded from "earlier" fixtures. The count of REPLACED fixtures is still pinned at 6.parity/src/hit-capture.ts, used by hit-capture-identity: the identity strip removes the svg family's keys as well as pointer-events. Every base file therefore still differs from the base only by keys a package added, and svg.test.ts proves the family's own values.Outside the spec
packages/parity/src/native-compare.ts: the native frames check skips SVG shapes.packages/parity/src/paint-samples/image.ts: samples inside an undrawn replaced box are dropped.packages/dragon/src/analysis/interaction.ts: HIT_MODELLED includes the svg family.project.tsandinternal.ts: OVFL A 2/2: scroll containers in the compiler, viewport propagation and Chrome scroll metrics #97, TXT1a-1 (v2): the text-latin registry against Chrome, engine-mode real faces and R3 vectors #103, TXT1a-2 (v2): native real faces and the text-latin cases in FIXTURES, restacked onto INL1a C2 #104, TXT-W1 (v2): font-weight and font-style, restacked onto the text stack #106, TXT-W2 (v2): the font shorthand and font-synthesis, restacked onto the text stack #107, MQ-R1 1/2 (T067): @media bands for native in the compiler, the band runtime reference and Chrome resize traces #140, OVFL A: scroll containers (overflow auto, scroll, clip), viewport propagation and Chrome scroll metrics, rebuilt on master (supersedes #96/#97) #194, CASC 1: @supports decided at build time as Chrome 145 decides it; revert and revert-layer; CSS-wide keyword rows #200resolve.ts: TXT-W1 (v2): font-weight and font-style, restacked onto the text stack #106, TDEC-a1 (v2): text-decoration in the compiler, restacked onto the text stack #108, INL2a 2/2: inline-block and inline-flex in the compiler, with Chrome fixtures #115, CASC 1: @supports decided at build time as Chrome 145 decides it; revert and revert-layer; CSS-wide keyword rows #200computed-checks.ts: OVFL A 2/2: scroll containers in the compiler, viewport propagation and Chrome scroll metrics #97, TXT1a-2 (v2): native real faces and the text-latin cases in FIXTURES, restacked onto INL1a C2 #104–TDEC-a1 (v2): text-decoration in the compiler, restacked onto the text stack #108, INL2a 2/2: inline-block and inline-flex in the compiler, with Chrome fixtures #115, OVFL A: scroll containers (overflow auto, scroll, clip), viewport propagation and Chrome scroll metrics, rebuilt on master (supersedes #96/#97) #194, PNT1-effects 1/2: opacity as a native group alpha and z-index with Appendix E stacking (supersedes the opacity and stacking parts of #84-#85) #196, PNT1-radius: border-radius, its corner longhands and -webkit-border-radius drawn natively on iOS and Android (supersedes #80, #81) #198capture-ua-defaults.ts: TXT-W1 (v2): font-weight and font-style, restacked onto the text stack #106, TXT-W2 (v2): the font shorthand and font-synthesis, restacked onto the text stack #107pipeline.ts: TXT1a-1a (v2): Ahem through HarfBuzz, and the zoomInput platform rule, restacked onto INL1a C2 #101, TXT1a-1 (v2): the text-latin registry against Chrome, engine-mode real faces and R3 vectors #103, TXT1a-2 (v2): native real faces and the text-latin cases in FIXTURES, restacked onto INL1a C2 #104, OVFL A: scroll containers (overflow auto, scroll, clip), viewport propagation and Chrome scroll metrics, rebuilt on master (supersedes #96/#97) #194compare.tsandnative-compare.ts: INL2a 2/2: inline-block and inline-flex in the compiler, with Chrome fixtures #115attributes.ts: TDEC-a1 (v2): text-decoration in the compiler, restacked onto the text stack #108, TDEC-a2 (v2): decoration geometry and the decoration capture, restacked onto the text stack #109properties.ts: TDEC-a1 (v2): text-decoration in the compiler, restacked onto the text stack #108Notes for the PM
element:svg-style rows, but Dragon has no element-level rows. The svg element is gated by its refusals and proven by its fixtures.Reviewed diff: about 151 KB. All regenerated output is under
.macroscope/ignore.mdshapes. The spec is at /tmp/specs/svg-a.md.Land-prep round (2026-10-08, cloud)
parity.test.ts:303, the colour-only plant:every problem matches /color/). It was fixed in 3fb061c: SVG-a1'sfillandstrokehave initial value black, so the colourOnly plant moves them as well. The check now requires every problem to name a colour longhand (COLOR_LONGHANDS) or fill or stroke. That is the exact set the plant can move, so the check is still judged on every problem and keys on the longhand name instead of a substring. parity.test.ts now passes on CI (532 tests).parity/test/svg.test.tschecks that no SVG shape's committed Chrome capture records an<id>:line<j>fragment, across all 8 svg cases, and that at least one shape exists. Without the fix, a shape's computed display isinline, so capture.ts would push one:linenode per client rect.computed-checks.ts: the walk takes OVFL'sscrollerandcheckPercentRelative, and still sends an svg shape only to SVG-a1'scheckSvg.replaced-identity.test.ts: OVFL'sLATER_WITH_REPLACEDnow also lists the svg layout fixtures, which replaces this branch's own exclusion. Both pins are kept: REPLACED is still 6, and the excluded set equals6 + LATER_WITH_REPLACED.length.Review round: independent review of 7787d4b
svg-compare.ts).compareSvgwalked only Dragon's scene shapes. Two callers also turned nullsvgScenesinto[], so a shape Chrome paints but Dragon drops passed.compareSvgnow takesreadonly SvgScene[] | null.svggeometry must be one of Dragon's scene shapes; otherwise the problem reads "Chrome captured an SVG shape that no Dragon svg scene has".pipeline.tsandsvg.test.tspass the scenes through without?? [].parity/test/svg.test.ts. It drops one shape from the first scene of each case (exactly one problem per case), empties every scene list, and returns null scenes. Each fails the differential. All three passed as [] before the fix.Catch-up merges (2026-10-09)
parity/src/hit-capture.ts:hitRefusalrefuses a transform, then an<svg>by name (SVG-a2), then a rounded corner (PNT1), then INL1a's inline box or<br>.withoutPointerEventsuses master'sKEYS_SINCE_BASE, which now also lists the svg family (fill,stroke,stroke-width) beside the four corner radii. This replaces this branch's inline regex.parity/test/hit-report.test.tsandparity/test/lanes.test.ts: both judge the exact union of the four named refusals (transform, PNT1 radius, INL1a inline, svg). Each refused case must carry its own reason. BothRADIUS_OUTandSVG_OUTare pinned as exact sets.parity/test/hit-capture-identity.test.ts. It checks that the svg family's keys are stripped beside the radii, whilefill-opacity,stroke-dasharrayand a changed value beside a stripped key still differ.@property). Five conflicts, each resolved by keeping both sides:dragon/src/css/properties.ts: FAMILIES keeps GEN-b'slistsfamily, then SVG-a1'ssvgfamily last. Both imports are kept.scripts/gen-css-grammar.ts: SUBSET keeps GEN-b'scontentandlist-style*entries, then...SVG_LONGHANDSlast. RADIUS and the other entries are unchanged.dragon/src/analysis/computed-checks.ts:checkSvgstays, and so does the walk's svg-shape early return.checkComputedtakes GEN-b's signature (faults: GenBFaults = GEN_B_FAULTS), which it passes tocheckUserAgentDefaults.dragon/test/s4b.test.tsanddragon/test/ua.test.ts: the rounding-boundary scans keep both single-file exemptions, CASC 2'scss/chrome-number.tsand SVG-a1'sanalysis/elements/svg-path.ts.dragon/test/svg.test.ts. One document holds a shape with a percentage stroke-width and a<ul><li>with a disc marker, and both refusals fire: SVG-a1's and GEN-b's GEN-c marker refusal.Review round: independent review of 0c6ada6
parity/src/hit-capture.ts): the identity strip removed the svg family at any value.withoutPointerEventshadfill,strokeandstroke-widthinKEYS_SINCE_BASE, so a base file that gained a non-initial value would still hash to the base.Fix: the family is now stripped only at its initial values,
fill: rgb(0, 0, 0),stroke: noneandstroke-width: 1px, in LONGHANDS order, as GEN-b's neutral longhands are (SVG_JSONandSVG_CSS).KEYS_SINCE_BASEis back to pointer-events and the radii.hit-capture-identity.test.ts: the svg case now checks two things.The old any-value strip fails this: it removed those values.
The base-hash case still passes on CI, so the 2471 base files gained only the neutral triple.
checkSvgcall is removed, and it fails when GEN-b's list-marker refusal is disabled. It passes when both are restored.Catch-up merge (2026-10-09, after #196 and #231 stalled)
dragon/src/css/stylesheet.ts:Declarationkeeps both SVG-a1'spresentationHintand CASC 3'slayer.resolve.ts), layered or not, so every author layer still ranks above it (css-cascade-5 §6.1).dragon/test/svg.test.ts:fill="rgb(9, 9, 9)"attribute gives fill (9, 9, 9).@layer baseoverrides it.What passed on the clean head 565cdba
pnpm typecheck(local).block-elements,casc-property,lists,s4b,s5,seams,svg,ua-elb2,ua,registry-claimsandprofile-index(11 files, 143 tests).casc-layer,markers-text,anim-runtime,media-wiringandstate-program(5 files, 118 tests).pnpm ci:regen svg-a1 --head 565cdbab1a: already at a fixed point. https://github.com/compiled-run/dragoncss/actions/runs/37934126509pnpm ci:test-filesat https://github.com/compiled-run/dragoncss/actions/runs/37934142200, all passing:parity: 564 testssvg: 6hit-report: 9hit-capture-identity: 9hit-lanes: 6pixel-reference: 12glyph-calibration: 8line-breaks: 11native-host: 347device-lanes: 62pnt2-quads: 5pnt2-samples: 7replaced-paint: 13p6a-dash-oracle: 330replaced-identity: 3chrome-ports: 13registry-claims: 8android-profile: 5casc-property: 3casc-layer: 3list-style-parse: 1ovfl-metrics: 14dist: 6env-engine: 8fixture-reader: 7fonts-fixtures: 26inline: 13interaction-forced: 3media-runtime: 8media-sweep: 19phrasing-blockified: 3platform: 12tree-faults: 3values: 72lanes.test.ts: 365 passed and 1 failed. The failure is "every device lane ran", which is device step pending.pnpm pr:review 206 --once: exit 0. It reports UNREVIEWED (Macroscope at its spending limit), with 0 unanswered findings. GitHub reports the PR asclean.🤖 Generated with Claude Code
Generated by Claude Code