Skip to content

release.changelog

Every release the layer records, newest first, with the work that has not been released leading. A section's decisions are the ADRs dated inside that release's window, its changes the conventional commits in its range, its artifacts the record's own evidence. Nothing in it is authored, and a section that could not be read says so rather than appearing empty.

Every release the layer records, newest first, with the work that has not been released leading. A section's decisions are the ADRs dated inside that release's window, its changes the conventional commits in its range, its artifacts the record's own evidence. Nothing in it is authored, and a section that could not be read says so rather than appearing empty.

Exposure

Where this one definition is reachable. Absence is explicit: a surface not listed does not carry it.

surfaceas
MCPtool majordomus_changelog
resource majordomus://changelog
HTTPGET /api/v1/changelog operationId release.changelog
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 · ReleaseChangelogInput

Which part of the changelog to answer with.

propertytyperequireddescription
version string | null no One version, or `unreleased`; every section when absent.
JSON Schema
{
  "additionalProperties": false,
  "description": "Which part of the changelog to answer with.",
  "properties": {
    "version": {
      "description": "One version, or `unreleased`; every section when absent.",
      "type": [
        "string",
        "null"
      ]
    }
  },
  "title": "ReleaseChangelogInput",
  "type": "object"
}

output · ReleaseChangelog

The whole changelog.

propertytyperequireddescription
current string yes The version the tree currently declares.
diagnostics array yes What could not be read, said rather than hidden: a repository with no git history, a release record that names no commit, a tag that is not in this clone.
produced_by one of 2 no Which capability answered, and where else the same value can be had.
schema string yes The schema this document satisfies.
sections array yes Newest first, the unreleased section leading when there is one.
JSON Schema
{
  "$defs": {
    "ReleaseChange": {
      "description": "One change, from one commit.",
      "properties": {
        "breaking": {
          "description": "Whether the commit marked itself breaking, with `!` or a `BREAKING CHANGE:` trailer.",
          "type": "boolean"
        },
        "commit": {
          "description": "The abbreviated commit.",
          "type": "string"
        },
        "kind": {
          "$ref": "#/$defs/ReleaseChangeKind",
          "description": "What it did."
        },
        "references": {
          "description": "The records of the layer this commit names — issues, milestones — resolved against\nwhat the layer actually holds.",
          "items": {
            "$ref": "#/$defs/ReleaseReference"
          },
          "type": "array"
        },
        "scope": {
          "description": "The area it did it in, when the subject named one: `commands`, `ci`, `site`.",
          "type": [
            "string",
            "null"
          ]
        },
        "subject": {
          "description": "The subject, without the type and scope that prefixed it.",
          "type": "string"
        },
        "url": {
          "description": "Where that commit can be read, when the repository's own URL is known. Derived from\n`about::REPOSITORY`, never written beside each entry.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "kind",
        "subject",
        "breaking",
        "commit"
      ],
      "type": "object"
    },
    "ReleaseChangeGroup": {
      "description": "The changes of one kind, with the heading and the rank that decide where they are shown.\n\nThe grouping is in the document rather than in each renderer. It was in the Markdown\nrenderer alone, and the site — which cannot see a Rust function — grouped alphabetically\ninstead, so the same changelog read in two orders depending on which surface showed it.\nA presentation order stated once and carried is the only kind that survives a projection.",
      "properties": {
        "changes": {
          "description": "The changes, in the order the commits were read.",
          "items": {
            "$ref": "#/$defs/ReleaseChange"
          },
          "type": "array"
        },
        "heading": {
          "description": "The heading it is shown under.",
          "type": "string"
        },
        "kind": {
          "$ref": "#/$defs/ReleaseChangeKind",
          "description": "What the changes in it did."
        },
        "rank": {
          "description": "Where it sorts among the other groups; ascending.",
          "format": "uint8",
          "maximum": 255,
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "kind",
        "heading",
        "rank",
        "changes"
      ],
      "type": "object"
    },
    "ReleaseChangeKind": {
      "description": "What a conventional commit says it did.\n\nThe set is the one the repository's own commit convention uses; a commit whose subject\ndoes not parse is [`ChangeKind::Other`] and still appears, because a changelog that\nsilently drops what it cannot classify is a changelog that lies by omission.",
      "oneOf": [
        {
          "const": "feat",
          "description": "A capability a person did not have before.",
          "type": "string"
        },
        {
          "const": "fix",
          "description": "Behaviour that was wrong and is not any more.",
          "type": "string"
        },
        {
          "const": "perf",
          "description": "Performance, with the behaviour unchanged.",
          "type": "string"
        },
        {
          "const": "refactor",
          "description": "Structure, with the behaviour unchanged.",
          "type": "string"
        },
        {
          "const": "docs",
          "description": "Documentation.",
          "type": "string"
        },
        {
          "const": "test",
          "description": "Tests.",
          "type": "string"
        },
        {
          "const": "chore",
          "description": "The build, the pipeline, the tooling.",
          "type": "string"
        },
        {
          "const": "ci",
          "description": "Continuous integration.",
          "type": "string"
        },
        {
          "const": "style",
          "description": "Formatting, with the behaviour unchanged.",
          "type": "string"
        },
        {
          "const": "build",
          "description": "The build system or its dependencies.",
          "type": "string"
        },
        {
          "const": "revert",
          "description": "A change that undoes another.",
          "type": "string"
        },
        {
          "const": "other",
          "description": "A commit whose subject does not parse as a conventional commit.",
          "type": "string"
        }
      ]
    },
    "ReleaseChangelogArtifact": {
      "description": "One published artifact, from the release record's own evidence.",
      "properties": {
        "name": {
          "description": "The file name.",
          "type": "string"
        },
        "sha256": {
          "description": "Its SHA-256, as the record read it off the file.",
          "type": "string"
        },
        "target": {
          "description": "The platform triple the record names.",
          "type": "string"
        }
      },
      "required": [
        "target",
        "name",
        "sha256"
      ],
      "type": "object"
    },
    "ReleaseDecision": {
      "description": "One decision, as the layer's own ADR object states it.",
      "properties": {
        "added": {
          "description": "The commit that added the file, which is what decides the release it belongs to. The\nfront-matter date says when the decision was made; those are different questions.",
          "type": [
            "string",
            "null"
          ]
        },
        "date": {
          "description": "The date the record carries.",
          "type": "string"
        },
        "id": {
          "description": "`adr-0027`.",
          "type": "string"
        },
        "status": {
          "description": "`proposed`, `accepted`, `superseded`.",
          "type": "string"
        },
        "title": {
          "description": "The decision, in its own words.",
          "type": "string"
        },
        "url": {
          "description": "Where the decision itself can be read: the file in the repository. The site has no\nper-ADR page, so this is the honest destination rather than an invented route.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "id",
        "title",
        "status",
        "date"
      ],
      "type": "object"
    },
    "ReleaseProducedBy": {
      "description": "Which capability answered with this document, and where that capability is projected.\n\nThe document carries its own provenance so that a reader — a person on the site, a client\nover MCP — can find the same value elsewhere without anything having to enumerate the\nroutes. A page that listed them would be declaring them a second time, which is the\nfailure `site-check`'s `registry` and `cli` assertions exist to catch; it caught this one.\n\n```\nuse majordomus_cli::release::model::ProducedBy;\nlet by = ProducedBy {\n    capability: \"release.changelog\".into(),\n    cli: Some(\"majordomus release changelog\".into()),\n    http: Some(\"/api/v1/changelog\".into()),\n    mcp_tool: None,\n    mcp_resource: Some(\"majordomus://changelog\".into()),\n};\nlet json = serde_json::to_value(&by).unwrap();\nassert_eq!(json[\"capability\"], \"release.changelog\");\n// a surface the capability is not projected on is absent, not null\nassert!(json.get(\"mcp_tool\").is_none());\nassert_eq!(ProducedBy::default().capability, \"\");\n```",
      "properties": {
        "capability": {
          "description": "The capability id.",
          "type": "string"
        },
        "cli": {
          "description": "The command line that renders it.",
          "type": [
            "string",
            "null"
          ]
        },
        "http": {
          "description": "The HTTP route that answers with it.",
          "type": [
            "string",
            "null"
          ]
        },
        "mcp_resource": {
          "description": "The MCP resource URI.",
          "type": [
            "string",
            "null"
          ]
        },
        "mcp_tool": {
          "description": "The MCP tool.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "capability"
      ],
      "type": "object"
    },
    "ReleaseReference": {
      "description": "A record of the layer that a commit names in its own text.\n\nInferred, never declared beside the commit: an issue id or a milestone id appearing in a\nsubject or a body is a reference, and the layer already holds the object it refers to. A\nreference to something the layer does not have is not carried — a link to a record that\ndoes not exist is worse than no link, because the reader cannot tell until they follow it.\n\n```\nuse majordomus_cli::release::model::Reference;\nlet r = Reference {\n    kind: \"issue\".into(),\n    id: \"I1305\".into(),\n    title: \"An observed contract has a fingerprint\".into(),\n    route: Some(\"/plan/i1305/\".into()),\n};\nlet json = serde_json::to_value(&r).unwrap();\nassert_eq!(json[\"id\"], \"I1305\");\nassert_eq!(json[\"route\"], \"/plan/i1305/\");\n// a reference the site has no page for carries no route rather than an invented one\nlet bare = Reference { route: None, ..r };\nassert!(serde_json::to_value(&bare).unwrap().get(\"route\").is_none());\n```",
      "properties": {
        "id": {
          "description": "`I1305`, `M000`.",
          "type": "string"
        },
        "kind": {
          "description": "`issue` or `milestone`.",
          "type": "string"
        },
        "route": {
          "description": "Where it is published on this site, when it has a page.",
          "type": [
            "string",
            "null"
          ]
        },
        "title": {
          "description": "What it is, from the record itself.",
          "type": "string"
        }
      },
      "required": [
        "kind",
        "id",
        "title"
      ],
      "type": "object"
    },
    "ReleaseSection": {
      "description": "One version's worth of changelog.",
      "properties": {
        "artifacts": {
          "description": "What was published, when this section is a release.",
          "items": {
            "$ref": "#/$defs/ReleaseChangelogArtifact"
          },
          "type": "array"
        },
        "commit": {
          "description": "The commit it was published from.",
          "type": [
            "string",
            "null"
          ]
        },
        "compare_url": {
          "description": "Every commit between the previous release and this one, as the forge renders it.",
          "type": [
            "string",
            "null"
          ]
        },
        "date": {
          "description": "When it was published, from the record.",
          "type": [
            "string",
            "null"
          ]
        },
        "decisions": {
          "description": "The decisions dated inside this release's window.",
          "items": {
            "$ref": "#/$defs/ReleaseDecision"
          },
          "type": "array"
        },
        "groups": {
          "description": "The changes, from the commits in this release's range, grouped by what they did and\nordered by the rank each group carries. The flat list is the concatenation of the\ngroups' own; nothing holds it twice.",
          "items": {
            "$ref": "#/$defs/ReleaseChangeGroup"
          },
          "type": "array"
        },
        "notes_url": {
          "description": "The release notes the record names — the published release itself.",
          "type": [
            "string",
            "null"
          ]
        },
        "tag": {
          "description": "The tag, when one was published.",
          "type": [
            "string",
            "null"
          ]
        },
        "tree_url": {
          "description": "The tree at this release.",
          "type": [
            "string",
            "null"
          ]
        },
        "unreleased": {
          "description": "Whether this section is the work that has not been released.",
          "type": "boolean"
        },
        "version": {
          "description": "The version, or `unreleased`.",
          "type": "string"
        }
      },
      "required": [
        "version",
        "unreleased",
        "decisions",
        "groups",
        "artifacts"
      ],
      "type": "object"
    }
  },
  "description": "The whole changelog.",
  "properties": {
    "current": {
      "description": "The version the tree currently declares.",
      "type": "string"
    },
    "diagnostics": {
      "description": "What could not be read, said rather than hidden: a repository with no git history,\na release record that names no commit, a tag that is not in this clone.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "produced_by": {
      "anyOf": [
        {
          "$ref": "#/$defs/ReleaseProducedBy"
        },
        {
          "type": "null"
        }
      ],
      "description": "Which capability answered, and where else the same value can be had."
    },
    "schema": {
      "description": "The schema this document satisfies.",
      "type": "string"
    },
    "sections": {
      "description": "Newest first, the unreleased section leading when there is one.",
      "items": {
        "$ref": "#/$defs/ReleaseSection"
      },
      "type": "array"
    }
  },
  "required": [
    "schema",
    "current",
    "sections",
    "diagnostics"
  ],
  "title": "ReleaseChangelog",
  "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.

transportstatecasestargets
directcovered2all
one-version
mcpcovered2all
one-version
httpcovered2all
one-version