Skip to content
rlsbl.tag_explanation
On this page

The one consultation over whether a tag is accounted for: by an archived version whose refs include it, by an archive's recorded shipped_as spelling, or by the transition record.

#rlsbl.tag_explanation

#rlsbl.tag_explanation

Is this tag explained? -- the one consultation, for every reader of a tag namespace.

A repository's tag namespace is writable by anything, and two rlsbl commands have to walk it and decide, per tag, whether this repository can account for it:

  • rlsbl release backfill lists every tag it cannot explain FIRST and refuses

to write anything while one remains;

  • rlsbl release reconcile fires its publication tripwire on a ref origin

holds that no record explains.

Both used to answer from their own reading. This module is the answer, and the consumers differ only in what they DO with it.

The three explanations ----------------------

archived-version The tag is one of the refs a version its release archives record OWNS. The caller supplies that mapping, and it comes from expected_refs -- the single authority for a version's ref set -- in both consumers: reconcile asks it per archived version, and the backfill asks it per scope. This module never derives a spelling of its own.

shipped-as An archive records shipped_as = "<tag>": the historical spelling that version ACTUALLY shipped under, from before a rename or a repository boundary moved. Without this, a renamed project's whole published tag history reads as unexplained.

non-version-tag The transition record carries a non-version-tag event naming it: a tag deliberately outside the version model, recorded by an operator so that everything walking the namespace can account for it instead of reporting it forever.

Anything else is unexplained, and what that costs is the consumer's own decision -- a hard refusal in the backfill, a tripwire in reconcile.

Reading archives tolerantly, on purpose ---------------------------------------

shipped_as is read with :mod:tomllib rather than through :func:rlsbl.release_file.read_release_file. The strict reader requires the strictspec format_version gate, and the archives the backfill exists to repair are exactly the ones written before that gate -- asking the strict reader would refuse to look at the file whose one field is being read. Only that field is taken; nothing here validates an archive or acts on one.

#TagExplanation

Why a tag is accounted for.

version names the version the tag belongs to for the two archive-backed sources, and is None for a non-version tag -- which belongs to no version by definition. reason carries the operator's own words from a non-version-tag event.

#describe

python
def describe(self) -> str

One line naming the explanation, for a plan or an error.

#TagExplanations

The explanations available in one repository, keyed by tag.

#explain

python
def explain(self, tag: str) -> TagExplanation | None

The explanation for tag, or None when nothing accounts for it.

#explains

python
def explains(self, tag: str) -> bool

#non_version_tags

python
def non_version_tags(self) -> tuple[str, ...]

Every tag the transition record puts outside the version model.

#shipped_as_index

python
def shipped_as_index(releases_dir: str) -> dict

tag -> version for every archive in releases_dir recording one.

An archive that does not parse, or that carries no shipped_as, contributes nothing: this is a lookup over a field, not a validation pass.

#non_version_tag_index

python
def non_version_tag_index(transition_record_paths) -> dict

tag -> reason for every recorded non-version-tag event.

:func:rlsbl.transition_record.read_events is the read-for-use site and raises on a malformed record, which is the intended behavior: a namespace judged against a record that cannot be read in full would be judged against part of one.

#build

python
def build(*, version_tags=None, releases_dirs=(), transition_record_paths=()) -> TagExplanations

Assemble the explanations available in one repository.

version_tags is the caller's own tag -> version mapping, every spelling the versions it knows about own. The two other sources are read here: every shipped_as across releases_dirs, and every non-version-tag event across transition_record_paths.

Precedence is the order of the sources above, which is the order of decreasing specificity about a RELEASE: a tag the current scheme names is that version's, a tag an archive claims historically is that version's, and only a tag no archive claims can be one an operator put outside the model.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • selfdoc Static Site Generator that builds a project's documentation site directly from its source code, so the docs can never drift from the code they describe, with SEO/AEO, first-class blog, search, and cross-project linking built in
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search