Start

Glossary

Every term the documentation uses, defined once. Chapters link here on the first use of a term; the vocabulary itself is kept in CONTEXT.md in the repository.

Who is who#

Sanshain
The registry itself: the server that stores, splits and distributes API specifications. Where a longer name is needed, Sanshain Service.
Producer
A system that publishes an API spec to Sanshain. On the wire it is named by producername. A role, not an entity type: one system is usually a Producer and a Consumer at once.
Consumer
A system that requires endpoints from a Producer and is recorded as depending on them. Named by consumername.
System
A Producer or Consumer seen as one thing: the serviceName of a sanshain.yaml. The catalog push and the node panel speak of systems because they do not care which role the build plays.
Tooling (client)
Software that speaks HTTP to Sanshain on a Producer's or Consumer's behalf: the Maven plugin, the cargo subcommand, the Go, JavaScript and Conan clients, or plain curl. Tooling acts for a system; it is never a domain entity itself.
Actor
The authenticated caller behind a request, as the audit log records it. A version's "provided by" is the actor of its last provide, except that a byte-identical promotion keeps the snapshot's provider.
Role
A fixed, named bundle of permissions held instance-wide (admin, releaser, ...). The set of roles is part of the product.
Permission
One thing an actor may do; what every authorisation check tests. For example release_ga is the permission that publishing a GA version needs.
Releaser
The role that holds release_ga: publishing a GA version, retiring a protocol family and cutting a sanshain-branch need it. Admins and root hold it implicitly.
Maintainer
An actor responsible for a named set of Producers, with powers over those and no others: delete one of their versions, retire a family, manage the Producer's webhooks.
Root
An account whose authority comes from configuration rather than from stored grants, so it cannot be revoked from inside Sanshain. SANSHAIN_ROOT_USERS, when set, alone names the root accounts; otherwise the initial admin (INITIAL_ADMIN_USERNAME, default root) is root. Holds every permission.
Approval
A locally registered user cannot log in until an administrator approves the account, unless the administrator switched on auto-acknowledge on the admin page. Registration itself is a switch of Local mode, off by default.
Service account
An account an administrator creates for automation, such as jenkins. It has no password and never signs in; holders of manage_users issue, see and revoke its API tokens.

Versions#

Version
The Producer-declared identity of a spec: MAJOR.MINOR.PATCH, read from the spec file itself (info.version; for proto a mandatory // sanshain-version: comment). Sanshain never assigns one. v2 and 2.1 are accepted and stored as 2.0.0 and 2.1.0.
Version line
The ordered set of versions one Producer has published for one API type. Diffing, compatibility checks and cleanup happen within a single line; a Producer's OpenAPI and proto lines evolve independently.
Stability
Which of exactly two states a stored version is in, snapshot or GA. Declared by the caller on every provide; how the caller decides is the tooling's business (the ga switch), never Sanshain's.
Snapshot
A version in its mutable state: re-providing it overwrites it (the user who last provided it may change it, anyone else's different content is refused with the next free minor proposed, every overwrite audited), it is never compatibility-checked, and it expires once neither provided nor required for the snapshot window.
GA
A version in its immutable state. Re-providing identical content is a no-op; different content is rejected with a proposed next version. A GA permanently claims its number: no snapshot may ever exist for it again, and cleanup never removes it.
Promotion
The GA provide of a number that existed as a snapshot. The entry becomes GA in place and the snapshot content is gone. The response says "promoted": true.
Proposed version
The proposed_version field of a 409 that refused a provide: the next free number of the line, bumped by what actually changed (breaking: major, additive: minor, shape-identical: patch). Set it in the spec file and republish.
Breaking change
A change the compatibility classifier flags between two documents of one line: a removed endpoint, parameter, property, message or rpc, a type change, a new required field. A GA version that is breaking relative to the highest GA below it must bump the major.
Deprecation
A per-element marker in the spec (deprecated: true, option deprecated = true;, [deprecated = true]). Removing an element that was deprecated in the previous GA is not breaking.
Retire
A provide call with retired: true and no body: the Producer no longer provides that API family. It clears the family's capability tag, closes its trunk pins and releases its message contracts; versions and existing pins stay. Needs the releaser role or a maintainer grant.
Snapshot expiry
A snapshot that is neither provided nor required for snapshot_max_age_days (default 30, 0 disables) is cleaned up. Use keeps it alive. GA never expires.
Instance version
Sanshain's own build version, answered by GET /version. Always qualified, to keep it apart from spec versions.

Publishing and requiring#

Provide
A Producer's submission of a complete spec for one version of one API type, with a declared stability (POST /provide, /provide/asyncapi, /provide/grpc). Because it is complete, an endpoint absent from it is absent from that version's API.
Snippet
The part of a spec Sanshain cuts out for one endpoint: one OpenAPI operation with the schemas it references, one AsyncAPI channel with its messages, one proto service with one rpc and the messages it needs.
Require
A Consumer's request for specific endpoints at its pin (GET /require, /require/asyncapi, /require/grpc). A successful require also records the dependency; a failed one records nothing.
Bundle
POST /require-bundle: several endpoints of one Producer at one pin, answered as a single merged document with one copy of each shared schema. If any endpoint is absent the whole bundle fails and names the missing ones.
Pin
A Consumer's exact version choice for one dependency, written in its own configuration. No ranges, no latest, no default: what a Consumer builds against changes only when someone edits the pin.
Resolution
Answering "what is this endpoint at this pin?". The line holds one entry per version, snapshot or GA; that entry answers, and there is no fallback to any other version. Every resolution ends in exactly one of three states: served, absent or unknown.
Served
Resolution state: the pinned version exists and contains the endpoint. The X-Sanshain-Stability header says whether GA or snapshot answered.
Absent
Resolution state, 410 Gone: the pinned version exists and deliberately does not include this endpoint. A definitive no.
Unknown
Resolution state, 404 Not Found: the Producer, or the pinned version in either stability, does not exist. A configuration error on the Consumer's side, answered immediately.
Dry run
dry_run: true on a provide, require or bundle: the full validation runs and nothing is stored, not even the Producer. Made for pull-request pipelines.
Idempotent no-op
Re-providing byte-identical content (after line endings are normalised to LF and a leading BOM is removed) stores nothing and answers changes all zero. CI re-runs never fight.
ETag
Every require answer carries an ETag; sending it back as If-None-Match yields 304 Not Modified when the content is unchanged. A GA pin never changes; a snapshot pin can, and the ETag is what detects it.
Sanshain-Warning
A response header, one line per warning, on a call that succeeded but could not be recorded the way it was declared: an unknown tag, trunk and tag together, a catalog push that recorded nothing. Clients print it and fail on it only in strict mode.
Strict mode
A client setting (strict: true in sanshain.yaml or the client's flag): missing configuration and any Sanshain-Warning fail the build instead of printing a warning.
Message contract (AsyncAPI)
On a GA provide, every named publish message registers a contract keyed by channel and message name, owned by the first Producer to publish it. The owner may widen it; another Producer may co-publish only an identical payload schema.
Harvested subscription
An AsyncAPI subscribe (2.x) or receive (3.x) operation in a provided document becomes a version-less consumer edge in the graph, resolved against the channel's message contract. No hand-written require is needed for it.
Validator
POST /validate and the form on the landing page: the provide-side checks (version extraction, splitting) on any document, without authentication and without storing anything.

The graph#

Dependency graph
What Sanshain knows about who pins which version of which endpoint, drawn as a live SVG on /graph.html and answered as JSON by GET /report.
Outdated
A dependency whose pin is below the latest GA of its line. A display state only: being outdated changes nothing about what is served.
Snapshot-pinned
A dependency served from a snapshot because its pin has no GA. It flags building against overwritable content; such a pin may even be ahead of the latest GA.
Superseded
A snapshot below the latest GA of its line. The producers page marks it superseded by X ga, and a pin to it counts as outdated.
Stream
Where a build belongs: plain calls record dev activity, trunk: true marks the trunk stream, tag: "<branch>" marks a sanshain-branch. Streams never change version rules or what is served; they only decide which graph records the call.
Dev graph
The default view: everything ever provided or required, snapshots included, thinned by the dependency window (dependency_max_age_days, default 30).
Trunk
The stream of your default-branch CI. A trunk provide stamps the version as "trunk's current version"; a trunk require maintains the main graph's pin set, last write per endpoint wins.
Main graph
The trunk stream's view: every Producer at its trunk version, edges from trunk pins. What trunk is, deterministic after every trunk build.
Trunk TTL
Trunk entries not refreshed within trunk_max_age_days (default 90) leave the main graph; they are highlighted as stale once they pass half the window. History keeps them.
Sanshain-branch
A named copy of a graph at a chosen instant: the release cut. Created by a releaser from trunk or from another branch, updated by tagged builds, diffable against main or other branches. main, dev and trunk are reserved names.
Tag
The tag parameter of a provide, require or bundle: the call updates the named sanshain-branch instead of trunk. Branches are never auto-created; an unknown tag records the call in the dev graph only and answers a Sanshain-Warning.
Release cut
Creating a sanshain-branch: POST /admin/branches with a name, optionally a source branch and an as_of instant. A past instant repairs a forgotten cut.
Timeline
Trunk and branch writes are append-only, so the main graph and every branch can be rendered as they were at any past instant. The slider's markers are the instants the graph changed.
Peripheral resource
Something outside Sanshain a system depends on (a database, bucket, queue), known only by its Backstage ref resource:<namespace>/<name> from the system's own catalog-info.yaml. One node per ref, shared by every system that names it.
Catalog push
PUT /catalog/{systemname} with the system's Backstage catalog-info.yaml, once per build. Sanshain reads the Component named like the system and of it the periphery and the catalog context; everything else is ignored.
Missing component
A component: ref in a system's dependsOn that names no Producer and no Consumer: drawn as a dashed node with an edge from the depending system, so a dependency the graph cannot see is at least visible as a gap. It disappears the moment a system of that name provides or requires.
Origin
What the build that provided a version said about why: its build URL, the pull or merge request behind it (change_url), the ticket ids it closes and one line of intent. The latest provide that carries any of them wins; a no-op re-provide of identical bytes only fills an empty one. References, never content: the ticket itself stays in the tracker.
Catalog context
What the catalog push records besides the periphery: the system's owner, description, source location, links and tags. Shown on the graph's node panel and on the Producer and Consumer pages; a tag also focuses the graph (tag:<name>). One present-day fact per system, not tracked per stream.
Report scope
?scope=dev (default), main[@instant] or <branch>[@instant] on /report and its variants: which graph a report describes.
Audit timeline
The log of every provide, require and administrative action, with a diff viewer and filters by date, action, service and stream. For holders of the view_audit permission: the admin and viewer roles.

Credentials and integrations#

Session
What POST /auth/login answers and what the web UI sends: a token that expires with the session (7 days). Sessions can mint API tokens; API tokens cannot.
API token
A long-lived credential (san_ + 64 hex characters) owned by one user, minted on the account page or with POST /auth/tokens, shown once, with a mandatory expiry. What CI, scripts and AI clients send as Authorization: Bearer.
Token scope
Decided when a token is minted, immutable afterwards. full may do everything its owner may; read_only may read reports, versions, the update streams and the MCP endpoint, and is refused with 403 on every route that changes the catalog.
Webhook
A signed POST Sanshain sends to a registered URL for every fact it records and every provide it rejects: version.published, provide.rejected, version.deprecated, dependency.recorded, branch.cut, catalog.recorded. Registered globally by an administrator, or per Producer and Consumer on their pages.
MCP
The Model Context Protocol endpoint POST /mcp: eight read-only tools that let an AI assistant list and describe services, find an endpoint, read a spec, walk the graph, diff and blame versions. API tokens only, 60 calls per minute per token, 64 KiB per answer.
Developer mode
An auth mode for a laptop: provide, require, catalog and MCP work without a token, and only administrators sign in. It needs both the mode and the ALLOW_INSECURE_DEV_MODE=true safety gate, and fails closed otherwise.
Off (maintenance)
The auth mode for backups, restores and directory work: the API answers 503 and only administrators sign in. A fresh instance starts in it unless INITIAL_AUTH_MODE names another mode.

Checked against v2.10.0.