A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
entity.kinds
Every kind, and whether every object of it is addressable
What it is
The kinds the layer holds, each with the route of its index and how many objects it carries, and every route collision there is. A collision is the only way an object of the index can fail to have an address of its own; the healthy answer is none.
Descriptor
- Canonical id
entity.kinds- Module
entity- Kind
- query
- Stability
- implemented
- Provenance
- declared
- Source
apps/majordomus-cli/src/capability/builtin/entity.rs- Cache
disabled- Benchmark
required- Tags
- objectsgovernance
Run
queryA query. It reads and changes nothing.
Projections
| Interface | As | Where |
|---|---|---|
| MCP tool | majordomus_kinds | - |
| MCP resource | not exposed | - |
| HTTP | GET /api/v1/entity/kinds | Swagger |
| Command line | majordomus entity kinds | - |
Schemas
Input · Empty
{
"type": "object",
"additionalProperties": false,
"description": "No input.",
"title": "Empty"
}Output · KindList
{
"type": "object",
"properties": {
"count": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "How many kinds."
},
"kinds": {
"type": "array",
"items": {
"$ref": "#/$defs/KindEntry"
},
"description": "The kinds, in the index's order."
},
"routable": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "How many objects have a route. Every object does, unless it is in `collisions`."
},
"collisions": {
"type": "array",
"items": {
"$ref": "#/$defs/RouteCollision"
},
"description": "Two objects of one kind whose identities reduce to one route, which is the only way\nan object can fail to be addressable. Empty is the healthy answer and the only one\n`scripts/ci/entity-check` accepts."
}
},
"required": [
"count",
"kinds",
"routable"
],
"description": "Every kind of the layer, each with its route, and every route collision there is.\n\nThe two numbers are what `scripts/ci/entity-check` compares: the objects the index holds\nagainst the objects that have an address. They are reported together, in one answer, so\nthat the gate asks one question instead of joining two lists and deciding for itself\nwhat the difference means.\n\n```\nuse majordomus_cli::capability::builtin::entity::KindList;\n\nlet healthy: KindList = serde_json::from_value(serde_json::json!({\n \"count\": 1,\n \"kinds\": [{ \"kind\": \"adr\", \"count\": 52, \"route\": \"/cockpit/objects/adr\" }],\n \"routable\": 52,\n}))\n.unwrap();\n\nlet held: usize = healthy.kinds.iter().map(|k| k.count).sum();\n// every object addressable, and no collision: the only state the gate accepts\nassert_eq!(held, healthy.routable);\nassert!(healthy.collisions.is_empty());\n```",
"title": "KindList",
"$defs": {
"KindEntry": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"description": "The kind."
},
"count": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "How many objects of it the index holds."
},
"route": {
"type": "string",
"description": "Where its index is served."
},
"example": {
"anyOf": [
{
"$ref": "#/$defs/ObjectSummary"
},
{
"type": "null"
}
],
"description": "One of its objects, so a reader has somewhere to go."
}
},
"required": [
"kind",
"count",
"route"
],
"description": "One kind of the layer, with its address and how many objects it holds.\n\n`example` carries one of the kind's objects so that a catalogue of kinds is somewhere a\nreader can go from rather than a list of words: a kind with a count and no way in is a\ndead row. It is `None` only for a kind the index holds no object of.\n\n```\nuse majordomus_cli::capability::builtin::entity::KindEntry;\n\nlet e: KindEntry = serde_json::from_value(serde_json::json!({\n \"kind\": \"adr\",\n \"count\": 52,\n \"route\": \"/cockpit/objects/adr\",\n}))\n.unwrap();\n\nassert_eq!(e.kind, \"adr\");\n// the route is the kind's, derived — never a per-kind entry in a table of routes\nassert_eq!(e.route, majordomus_cli::entity::kind_route(&e.kind));\nassert!(e.example.is_none());\n```"
},
"ObjectSummary": {
"type": "object",
"properties": {
"uri": {
"type": "string",
"description": "`majordomus://<kind>/<identity>`."
},
"id": {
"type": "string",
"description": "The capability id, `<kind>.<identity>`."
},
"kind": {
"type": "string",
"description": "The kind the object was read as."
},
"identity": {
"type": "string",
"description": "The identity within the kind."
},
"title": {
"type": [
"string",
"null"
],
"description": "The title, when the kind's title rule found one."
},
"description": {
"type": [
"string",
"null"
],
"description": "The one-line description, when the kind holds one."
},
"path": {
"type": "string",
"description": "Repository-relative source path."
}
},
"required": [
"uri",
"id",
"kind",
"identity",
"path"
],
"description": "One object, summarised for a listing."
},
"RouteCollision": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"description": "The kind they share."
},
"slug": {
"type": "string",
"description": "The slug they both reduce to; empty when an identity reduces to nothing."
},
"identities": {
"type": "array",
"items": {
"type": "string"
},
"description": "The identities that collide, in index order."
},
"paths": {
"type": "array",
"items": {
"type": "string"
},
"description": "The files that declared them."
},
"correction": {
"type": "string",
"description": "What to do about it."
}
},
"required": [
"kind",
"slug",
"identities",
"paths",
"correction"
],
"description": "Two objects of one kind whose identities reduce to the same route.\n\nCarries both identities and both files, because the reader who has to fix it needs to\nknow which two things collided and where they are written — a count would tell them\nonly that the tree is refused. `correction` is the sentence `collisions` wrote about\nthis particular pair.\n\n```\n# use majordomus_cli::{Object, Provenance};\n# fn object(kind: &str, identity: &str) -> Object {\n# Object { kind: kind.into(), identity: identity.into(),\n# uri: format!(\"majordomus://{kind}/{identity}\"), title: None, description: None,\n# metadata: serde_json::json!({}), body: String::new(), content: String::new(),\n# media_type: \"text/markdown\",\n# provenance: Provenance { path: format!(\"{identity}.md\"), directory: \"x\".into(),\n# source_class: kind.into(), section: None, bytes: 0, member: None } }\n# }\nuse majordomus_cli::entity::{collisions, Collision};\n\n// `a.b` and `a-b` are two identities and one slug\nlet objects = vec![object(\"rule\", \"a.b\"), object(\"rule\", \"a-b\")];\nlet found: Vec<Collision> = collisions(&objects);\n\nassert_eq!(found.len(), 1);\nassert_eq!(found[0].kind, \"rule\");\nassert_eq!(found[0].slug, \"a-b\");\nassert_eq!(found[0].identities, [\"a.b\", \"a-b\"]);\nassert!(!found[0].correction.is_empty());\n```"
}
}
}Examples
These are the capability's own benchmark cases: the same inputs the benchmark runs and the OpenAPI document shows.
default
{}