Two defects found on device by phase 8's AC-5 walk, both the same trap phase 2
hit with card elevation: Material takes these values as DEFAULT ARGUMENTS, not
from the theme, so mapping the token is not enough on its own.
1. Every ShardCard drew in Material's grey, not the shard's panel color.
CardDefaults.cardColors() takes its container from surfaceContainerHighest -
FilledCardTokens.ContainerColor, checked in the material3 1.3.0 artifact's
bytecode - and shardColorScheme mapped surfaceContainer, High and Low but not
Highest. All 26 ShardCard sites across 20 files were affected. Themed
instances showed it worst: on Fantasy the page went brown and the cards
stayed grey.
This is NOT an M12 regression. The untouched app draws the same grey cards
and has since M5; M12 only made it obvious by theming everything around them.
Fixing it therefore changes the untouched app too - cards move from Material's
grey to --panel-flat - which is the milestone's second deliberate change to a
shard that has set nothing, alongside phase 2's card shadow. AC-1 is updated
to record that rather than absorb it: every other role is still asserted
byte-for-byte against the verbatim pre-M12 scheme, and the two that moved are
named, given their new values, and checked to have actually differed before.
surfaceContainerLowest is mapped alongside it for consistency with
surfaceContainerLow. It has no reader in this app - the phase 8 sweep checked
every Material component the app draws against the roles the mapping leaves at
Material defaults, and surfaceContainerHighest was the only live one. The
drawer scrim reads the unmapped `scrim`, which stays Material's black
deliberately.
2. The drawer's selected row ignored --radius-pill. NavigationDrawerItem takes
`shape` as a default argument (CircleShape); the three call sites set `colors`
but never `shape`, so on Fantasy every other radius went square while the
selected row stayed fully round.
Verified on device against a Fantasy-themed local instance: the three ShardCards
on the shard screen now paint --panel-flat, and the selected drawer row is the
4px rectangle the preset asks for.
477 unit tests green (476 + 1), lintDebug clean.
Co-Authored-By: Claude <noreply@anthropic.com>
sonar.coverage.exclusions carried a ui/theme/** directory glob from the M11
coverage push (COVERAGE_PLAN.md §2 phase 0). At the time that directory held
only Color.kt, Type.kt and the composables, so excluding all of it cost nothing.
M12 put three pure resolvers in it. ShardPalette, ShardStructure and
ShardTypeface are the milestone's core logic, they are the reason phases 1-3
could prove the no-op invariant as a JVM assertion, and JaCoCo on edge measures
them at 98%, 100% and 100%. The directory glob was dropping all of that out of
the denominator, so a future change that deleted those tests would not move the
coverage number at all.
The glob is now the one file it was really about: Theme.kt, the composable
(52%). The rest of ui/theme/ is measured, all of it 93% or better.
This does not rescue the gate - M12's already-measured code (data/appearance/
and ui/navigation/) covers at 93-100% and clears new_coverage >= 50 on its own.
It makes the number honest about which code the tests actually hold.
ui/components/ stays excluded as a directory: BrandAssets.kt is 11%, and the
9 tests it does have are on brandAssetUrl, the one part of it that is not a
composable body.
Co-Authored-By: Claude <noreply@anthropic.com>