ClusterMap

rendered, live
the wire — click a line to scrub
the contract — ClusterMap in catalog.json
{
  "type": "object",
  "properties": {
    "component": {
      "const": "ClusterMap"
    },
    "label": {
      "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString",
      "description": "Title and accessible name, e.g. 'Accounts at risk, by reason'. Required."
    },
    "clusters": {
      "oneOf": [
        {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "type": "string",
                "description": "Short name, e.g. 'Report accuracy'."
              },
              "size": {
                "type": "number",
                "description": "How many accounts share the reason. Raw count."
              },
              "intent": {
                "enum": [
                  "good",
                  "bad",
                  "warning",
                  "info",
                  "neutral"
                ]
              },
              "reason": {
                "type": "string",
                "description": "The shared risk reason, written for humans — the thing that makes the group actionable. Required."
              }
            },
            "required": [
              "id",
              "label",
              "size",
              "reason"
            ],
            "additionalProperties": false
          }
        },
        {
          "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DataBinding"
        }
      ],
      "description": "Groups of accounts that share a risk reason. The reason is the point — it is what makes the group actionable."
    },
    "clusterAction": {
      "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Action",
      "description": "Fired on cluster activation. subjectKind 'cluster', subjectId (the cluster's id), and reason are merged into its context automatically."
    }
  },
  "required": [
    "label",
    "clusters"
  ]
}
the prompt-pack — paste into your agent
### ClusterMap — accounts grouped by shared risk reason

Groups of at-risk accounts, grouped by _why_. The `reason` is the point — it is what makes the
group actionable.

| prop            | type                    | notes                                                       |
| --------------- | ----------------------- | ----------------------------------------------------------- |
| `label`         | string, required        | title and accessible name                                   |
| `clusters`      | cluster[] \| `{"path"}` | shape below                                                 |
| `clusterAction` | action                  | subject (`cluster`, the id) + `reason` merged automatically |

Cluster shape — `id`, `label`, `size` (raw count), `reason` required:

```
{"id":"cl-report-accuracy","label":"Report accuracy","size":12,"intent":"warning","reason":"Export totals don't match on-screen figures"}
```

```
{"id":"riskmap","component":"ClusterMap","label":"Accounts at risk, by reason","clusters":{"path":"/clusters"},"clusterAction":{"event":{"name":"cluster_drilled","context":{"view":"accounts"}}}}
```