Two schema-skill clarifications for shapes models keep getting wrong:
layout:none is overlay stacking only — a row or column of cards belongs
to horizontal/vertical (one corpus document authored a carousel as a
none frame and depended on the old engine bug to display) — and a ring's
track and progress arc are never flex siblings but same-origin layers in
one fixed wrapper.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
strip_wrapper_double_inset has always known how to strip a transparent
wrapper's duplicate side padding, but it runs before the mobile rail
pass installs the rail gutter it deduplicates against; the later rerun
used the single-child collapse whose contract cannot see a wrapper with
siblings. A padded sheet wrapper inside a freshly railed section thus
kept a second 24px inset and its card measured 279 against 327 rail
siblings. The dedupe now reruns after rail installation, and gutter
ownership is inherited along transparent chains — resetting at any
painting surface — so nested wrappers converge on one gutter owner
instead of reproducing the bug one level deeper. The rail skill's
wrapper rule is sharpened to name the shape models actually emit.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
fix_deck_front_card_transparency saw a photo card's transparent content
layer over its alpha gradient scrim as a deck front card leaking a
painted sibling, and lidded it with an opaque surface fill — hiding the
photo and the scrim the model had deliberately composed (three theme
cards in one measured document). An image sibling anywhere in the stack
now marks the see-through front as the composition itself, the same
reasoning as the existing ellipse exemption.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
A detail screen without a bottom tab bar that ends flush against the
device edge reads as clipped, and the corpus had no rule for it. The
geometry diagnostics now echo a mobile-bottom-flush fact when a mobile
root's lowest resolved child edge sits within 12px of the root bottom
and the trailing child is not nav-shaped — nav detection reads the
authored role or pure row geometry (full-width band in the nav height
range with evenly split targets), never node names. Repair stays with
the model: whether the fix is padding or a spacer is an intent call.
The mobile skill gains the matching breathing-room rule.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
The per-skill budget guard measures skill files as they sit on disk, but
style-guide-selector grows at resolve time when the available-style-guide
catalog replaces its placeholder — 819 tokens against a 500 budget, so
the catalog tail was silently cut from every planning prompt. Worse, the
three base planning skills alone already exceeded the 4000-token phase
ceiling, which made the only domain skill of the phase undeliverable on
any prompt, with no warning anywhere. The skill budget now covers its
worst-case injection, the planning ceiling rises to 6000, and three new
guards keep the hole shut: augmented skills must fit their own budget,
every augmentation placeholder must declare a worst case, and the end-to-
end resolver must deliver the full phase without drops or truncation.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
ShadowBody deserializes with five required fields, so a model omitting
just spread lost the entire node — and every child line that named it as
a parent cascaded into 'Insert parent not found' (a measured 19-line,
whole-card silent loss). Effects are now normalized before the strict
parse: identity defaults for offsets/blur/spread, alias folding for the
common synonyms, a lone effect object wrapped into the array, numeric
strings coerced, and glow/drop-shadow spellings canonicalized. Truly
unknown effect kinds still fail the node — inventing an effect the model
did not ask for would be worse than dropping one. The modify path's
parser reuses the same normalizer so the two lanes cannot drift.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
Models keep authoring a progress ring's track and arc as flex siblings,
so the layout engine lays the two circles out side by side with the
percentage label floating off the edge. radial_repair already converts
a parent that IS the ring's own wrapper, and correctly declines padded
general-purpose containers — which was exactly the hole the defect kept
returning through. This pass closes it from the other side: the arcs are
extracted into a fixed-size layout:none wrapper that takes the first
arc's slot, the parent keeps its layout and other children, and a lone
percent-content text sibling is adopted as the centred label. The lane
predicate is shared with radial_repair so exactly one pass owns any
given ring, and the same detector feeds geometry diagnostics so the loop
sees the violation it can no longer ship.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
Bump jian for the single-cell stack compilation of layout:none frames.
The loader's repair_inferred_horizontal_container previously rearranged
explicit layout:none children into a row to paper over the engine gap;
with the engine fixed that bandaid would shove correctly stacked layers
out of the frame, so it now only fires for documents that omit the
layout field entirely. Corpus-wide differential over 184 documents:
60 of 240k node rects change, all overlay repairs (hero scrims and
avatars regaining their parent box), none collapsing to zero.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
Two independent defects in the pan bitmap cache showed as misregistered
bands while dragging at high zoom and photos stuck on their blur-up
placeholders. Strips repainted during an in-place scroll used the live
viewport pan while the layer stays anchored at the snapped cache pan, so
every threshold crossing baked a band at twice the residual; the restore
rebase also vacated a margin strip nothing ever repainted. And a decode
landing on the worker mutates no editor state, so a sharp layer kept
serving stale placeholder pixels forever. Strips now paint against the
cache anchor, vacated margins join the progressive restore, and a raster
generation stamp reopens the restore when new pixels install.
Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
The rebase port left a hand-wrapped import list rustfmt disagrees
with, and two restored-comment references to the current product
version trip the version-sync fixture rule — reflow the imports and
reword the comments without the literal.
Leftover from porting the color-variable popover onto the unified
scroll tier: the web host's popup interception references
scroll_by_max, which only default-feature builds resolved via an
unrelated re-export — import it directly so the canvaskit build
compiles too.
The catalog integrity gate requires every locale to carry exactly the
English key set — the eight keys added for batch frame export and the
image-ratio action existed only in en / zh-CN / zh-TW. Translate them
across the remaining twelve locales (placeholders preserved) and bump
the intentional catalog size.