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.
The popover's escape layer was applied to the web host but dropped
from the native ladder while porting across the unified
keyboard_escape split — close the popup (and reset its scroll) one
layer before the fill-type dropdown, matching web. Also rustfmt
normalization of the rebase port sites.
The stale 'Image — fill row' line made the crop/adjust feature read
as unimplemented; describe the actual popover. Record that
op-host-native tests need --features gl-host — the default run
compiles out widget_host entirely and covers none of it.
text-rules and cjk-typography co-load on every Chinese request with
contradictory lineHeight tiers and no cross-reference — the model
picks one silently, and a wrong pick renders cramped headings rather
than an error. Mark the tiers latin-only and route CJK text to the
cjk-typography values, keeping latin digits and labels inside a CJK
design on the latin tiers.
The inspector's font dropdown scrolled against the wheel: it added
delta to its offset while the settings-panel font picker — same
widget, same scroll field, same file — and a dozen other scroll
surfaces all subtract. Flip it on both hosts and pin the convention
with direction tests that drive the real wheel entry point and
require the rail popups to move the same way as the panel behind
them. Also gate agent_indicator_test_support behind the same cfg as
its only consumers inside gl-host'd widget_host, so a default-feature
clippy run is clean without blanket allows.
The variable-binding list was emitted by the section walker as plain
panel rows — no height cap, no viewport, no scroll — so forty
variables inflated the inspector past the window and the clipped tail
stayed unreachable (yet still clickable through the clip). Rebuild it
as an anchored overlay in the same family as the fill-type and font
pickers: 320px cap with its own wheel scroll, outside-click and
Escape to close, name column ellipsized against a right-aligned hex
column so long tokens never overlap their value. Bind/unbind emission
is unchanged, the stroke-section picker shares the implementation,
and a regression test compares every other panel rect open-vs-closed
so the inline-inflation shape cannot come back.
Every image-fill popover test built its fixture on a rectangle, but a
dropped screenshot lands on a frame — a different SectionCapabilities
branch. A regression there would present exactly as 'the dropped
image can't be adjusted' with no red test. Walk the real chain once
from apply_image_drop on a frame through the fill row, mode chips and
crop-editing gate.