Expand description
CLEANLIB-178 — canonical customer-facing state taxonomy (Rust surfaces).
Single source of truth for the 8 customer states that the malicious-vs-
vulnerable cluster (CLEANLIB-176 wire-shape + 177 policy overlay + 178
aesthetic) surfaces. The design contract lives at
decisions/2026-06-12-cleanlib-178-state-aesthetic-mapping.md; this module
is its executable form for the Rust render surfaces — cleanlib-cli,
cleanlib-lsp (CLEANLIB-209), and any consumer of cleanlib-client. The
TS extension / Python MCP / JS+Go+Py SDKs mirror this table in their own
languages, each with a contract test asserting the same wire→state map
(anti-drift, sister of the silent-schema-drift discipline).
§Why this lives in cleanlib-client, not cleanlib-core
cleanlib-core is publish = false; the customer-state taxonomy is a
presentation concern consumed only by published render surfaces (the App
emits the wire source; it never renders a customer state). Keying on the
wire string (Verdict.source: String) — rather than cleanlib-core’s
VerdictSource enum — keeps this crate publishable to crates.io and avoids
a render-side dependency on the service-internal core crate.
§Design rules baked in (§0 of the spec — non-negotiable)
- Customer-language only — wire/engine codenames never appear in
label()/copy(). - Soft severity tokens (dark-theme-safe); brand cyan
#50C0E0is reserved for CLEAN. - Three derive tiers (block / warn / clean) → exit codes (1 / 2 / 0).
§Derive-once + fail-closed
Derive the state ONCE from the wire source (CustomerState::from_wire).
The App applies severity precedence server-side when it picks the single
source, so this map is 1:1 — no precedence is re-implemented here. An
unrecognized / future source fails CLOSED to NotYetAssessed (warn,
needs-review) — never silently Clean.
Enums§
- Customer
State - The 9 canonical customer-facing states, severity order (highest first) per the BD-ratified ordering in §1: Blocked-by-policy, Compromised, Malicious, Ransomware-linked, Actively-exploited, Vulnerable, Range-not-resolved, Not-yet-assessed, Clean. CLEANLIB-518(§3) added Range-not-resolved (8→9).
- Tier
- The three derive tiers — drive exit codes (block=1, warn=2, clean=0) and the colour family, and map onto the universal ALLOW/WARN/DENY render bucket.
Functions§
- is_
curated_ supply_ chain_ compromise - CLEANLIB-855:
trueiffmatched_rule_idnames a curated supply-chain-compromise-bridge policy rule (the App-side prefix convention for the CLEANLIB-177 curated compromise list), rather than an ordinary customer policy rule. This is the one place that prefix convention is checked on the render side — callers should go through this function (orCustomerState::from_wire_with_source_state_and_origindirectly) rather than re-implementing thestarts_withcheck, so the convention only needs to change in one place if it ever does.