UX audit found that the icon glyph rendered inside every node’s circle disc was tinted with onSecondaryContainer while the circle fill was primaryContainer. The two tokens are visually close in ChirpyDarkColorScheme but are not on-color pairs, meaning a light-theme or future palette change would expose the mismatch. Similarly, the DataPoint chip’s numeric value text (“0.0”) rendered inside the same primaryContainer circle with no explicit color, relying on ambient LocalContentColor rather than its on-color pair.
IconManager.iconColorFilter was set to colorScheme.onSecondaryContainer — likely a carry-over from when the chip scaffold used secondaryContainer as its chip surface. When getNodeStateColor was tokenized (resting states → primaryContainer), the circle fill moved to primaryContainer but the icon tint was never updated to match. The DataPoint value Text was inside a Box, not a Surface, so no contentColor was automatically provided.
IconManager.kt line 150: changed iconColorFilter from colorScheme.onSecondaryContainer to colorScheme.onPrimaryContainer.IconManager.kt DataPoint DOUBLE branch: added color = colorScheme.onPrimaryContainer to the value Text so the numeric overlay always pairs with the circle fill.When tokenizing a container fill color, always update the companion tint/content color in the same commit. The correct invariant: onX token appears wherever content sits on an X-filled container — if the circle is primaryContainer, glyphs and text on it must use onPrimaryContainer, not an unrelated on* token. A Roborazzi screenshot diff across both dark and a future light scheme is the fastest way to catch these: the visual delta is zero in dark (both tokens are similar) but obvious in light.