Files
amethyst/commonsUI
Claude bb239c51ed feat(cordn): render the §8 disclosure — exposure card, health row, badge, link screen
§8 of the interop plan ends with a requirement: the metadata-exposure analysis
"should be surfaced in the UI if we ship this, not buried. A Marmot group and a
cordn group have materially different metadata exposure and users cannot infer
that from either one looking like a group chat." GroupExposure existed so there
would be something to render; this renders it.

The disclosure sits where it can still change a decision — on a pasted cordn1…
link, before joining, rather than in a settings page nobody opens. The screen
reads the link, names the coordinator and its relays, and shows the exposure. It
deliberately does not join: joining needs a live coordinator and Tier B is
blocked on licensing (§7), so a join button would be half a feature whose other
half has never been run.

- commonsUI/.../cordn/ui/: CordnExposureCard, CoordinatorHealthRow,
  CordnGroupBadge. Material3 only, so Desktop gets them for free.
- commons/.../CordnLinkInspection: parse-and-disclose, headless and tested, so
  the screen only draws. A ref naming no coordinator is valid but not
  followable, and carries no exposure — inventing a threat model for a server
  we cannot identify would be worse than saying nothing.
- Settings → Cordn group link, with a route and search keywords.

Rendering it found two bugs compiling could not:

- The severity colours were not monotonic. `tertiary` for the middle level
  rendered pink against a dark `onSurface` for the worst one, so "under a
  throwaway key" read as more alarming than "tied to your real account".
  Emphasis for the worst case is now weight rather than another hue. Nothing
  uses `error`: everything on the card is how cordn works, not a fault, and
  painting normal operation red teaches people to ignore red.
- Note order is part of the disclosure. Cross-group linkage (§8.2), the item
  nobody predicts, sat below message padding, the least consequential one.
  notes() now returns most-surprising-first.

CordnExposureRenderTest rasterises the surface headlessly (ImageComposeScene,
software Skia, no display, no new dependency — the same Compose Desktop
artifact jvmMain already uses) and asserts on pixels. It catches what a compile
cannot: a missing string resource, which throws at render because the generated
Res.string.* accessors compile regardless, and a composable that draws nothing.
Mutation-checked — hardcoding the card background and disabling the §8.2
conditional each kill exactly one test. The first version of the theme test
sampled only the page background and let the hardcoded card through, so it now
samples inside the card as well.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BfD4txdnsaPRXmNXbup9n
2026-09-19 02:05:08 +00:00
..