design.contrast
Every foreground the design puts on a ground, in both themes, measured against WCAG 2.1 AA: the pair, the palette entries behind it, the ratio and the threshold. The pairs are not a list — they are derived from the declaration, which files each status's text with its own ground, and from the primitives that consume it, where a rule that sets a colour and a background states a pair and a rule that sets only a colour states a foreground that lands on every ground a container sets. A pair below the threshold is a finding that names the role, the ground, the theme, the measured ratio and the required one.
Every foreground the design puts on a ground, in both themes, measured against WCAG 2.1 AA: the pair, the palette entries behind it, the ratio and the threshold. The pairs are not a list — they are derived from the declaration, which files each status's text with its own ground, and from the primitives that consume it, where a rule that sets a colour and a background states a pair and a rule that sets only a colour states a foreground that lands on every ground a container sets. A pair below the threshold is a finding that names the role, the ground, the theme, the measured ratio and the required one.
- query
- behaviorally_verified
- module design
- #design
- #ui
- #accessibility
- #introspection
Exposure
Where this one definition is reachable. Absence is explicit: a surface not listed does not carry it.
| surface | as |
|---|---|
| MCP | tool majordomus_design_contrast |
| HTTP | GET /api/v1/design/contrast operationId design.contrast |
| command line | — |
Schemas
The canonical input and output, from the Rust types; the MCP tool schema and the OpenAPI parameters and responses are derived from these.
input · Empty
No input.
No properties: the capability takes no input.
JSON Schema
{
"additionalProperties": false,
"description": "No input.",
"title": "Empty",
"type": "object"
}output · ContrastReport
Every pair the declaration and its consumers state, measured.
| property | type | required | description |
|---|---|---|---|
| composed | integer | yes | Declarations skipped because their value is composed at run time. |
| findings | array | yes | One line per enforced pair that falls short, naming role, ground, theme, measured ratio and required ratio. |
| fingerprint | string | yes | The fingerprint of the declaration measured. |
| measured | integer | yes | How many pairs were derived and measured. |
| minimum_non_text | number | yes | The ratio asked of a non-text element that carries meaning. |
| minimum_text | number | yes | The ratio asked of text. |
| pairs | array | yes | Every pair, in a stable order: theme, then what it carries, then the two tokens. |
| readable | boolean | yes | Whether every enforced pair reaches its threshold. |
| sources | array | yes | The stylesheets read, and whether each was found. |
| standard | string | yes | The standard the thresholds come from. |
JSON Schema
{
"$defs": {
"Carries": {
"description": "What a colour is doing where it was found.",
"oneOf": [
{
"const": "text",
"description": "Text: held to [`MINIMUM_TEXT`].",
"type": "string"
},
{
"const": "non_text",
"description": "A border or an outline: measured against [`MINIMUM_NON_TEXT`], reported, not enforced.",
"type": "string"
}
]
},
"Measured": {
"description": "One measured pair: a foreground on a ground, in one theme.",
"properties": {
"carries": {
"$ref": "#/$defs/Carries",
"description": "Text, or a border."
},
"enforced": {
"description": "Whether falling short is a finding. False for a border; see the module documentation.",
"type": "boolean"
},
"foreground": {
"description": "The foreground token, as the declaration names it (`muted`, `ok`).",
"type": "string"
},
"foreground_entry": {
"description": "The palette entry it resolves to in this theme.",
"type": "string"
},
"foreground_value": {
"description": "The literal that entry holds.",
"type": "string"
},
"ground": {
"description": "The ground token.",
"type": "string"
},
"ground_entry": {
"description": "The palette entry the ground resolves to in this theme.",
"type": "string"
},
"ground_value": {
"description": "The literal that entry holds.",
"type": "string"
},
"passes": {
"description": "Whether it reaches it.",
"type": "boolean"
},
"ratio": {
"description": "The measured ratio, to two decimal places.",
"format": "double",
"type": "number"
},
"required": {
"description": "What the standard asks of this pair.",
"format": "double",
"type": "number"
},
"seen": {
"description": "Where the pair was read: the stylesheet and the selector that states it.",
"type": "string"
},
"theme": {
"description": "`light` or `dark`.",
"type": "string"
}
},
"required": [
"foreground",
"foreground_entry",
"foreground_value",
"ground",
"ground_entry",
"ground_value",
"theme",
"carries",
"ratio",
"required",
"passes",
"enforced",
"seen"
],
"type": "object"
},
"Source": {
"description": "One stylesheet the pair set was derived from.",
"properties": {
"path": {
"description": "Where it was read from, as the caller named it.",
"type": "string"
},
"rules": {
"description": "How many rules of it state a colour.",
"format": "uint",
"minimum": 0,
"type": "integer"
}
},
"required": [
"path",
"rules"
],
"type": "object"
}
},
"description": "Every pair the declaration and its consumers state, measured.",
"properties": {
"composed": {
"description": "Declarations skipped because their value is composed at run time.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"findings": {
"description": "One line per enforced pair that falls short, naming role, ground, theme, measured\nratio and required ratio.",
"items": {
"type": "string"
},
"type": "array"
},
"fingerprint": {
"description": "The fingerprint of the declaration measured.",
"type": "string"
},
"measured": {
"description": "How many pairs were derived and measured.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"minimum_non_text": {
"description": "The ratio asked of a non-text element that carries meaning.",
"format": "double",
"type": "number"
},
"minimum_text": {
"description": "The ratio asked of text.",
"format": "double",
"type": "number"
},
"pairs": {
"description": "Every pair, in a stable order: theme, then what it carries, then the two tokens.",
"items": {
"$ref": "#/$defs/Measured"
},
"type": "array"
},
"readable": {
"description": "Whether every enforced pair reaches its threshold.",
"type": "boolean"
},
"sources": {
"description": "The stylesheets read, and whether each was found.",
"items": {
"$ref": "#/$defs/Source"
},
"type": "array"
},
"standard": {
"description": "The standard the thresholds come from.",
"type": "string"
}
},
"required": [
"fingerprint",
"standard",
"minimum_text",
"minimum_non_text",
"sources",
"measured",
"pairs",
"composed",
"findings",
"readable"
],
"title": "ContrastReport",
"type": "object"
}Policies
- benchmark
- required — a target on every transport the exposure declares; the cases are the input type's
- cache
- disabled — every call runs the handler
Benchmark targets
Derived from the registry for this repository: one requirement per transport, and the cases the input type provides. The whole matrix is on the benchmarks page.