assay  ·  status as a build artifact

statusgen

The Go tool that reads a repo's stream documents and registers, and generates the single STATUS.md board. It is the machinery that turns convention into enforcement: gates a script runs, not rules a team is asked to remember.


What it does

statusgen parses each stream directory's README.md frontmatter and brief-row table, cross-applies findings to the streams they affect (flagging affected briefs as stale-knowledge), reads the two registers (FINDINGS.md and INTAKE.md), and emits a single aggregated view: one STATUS.md file with a priority-and-staleness-ranked Next-up batch, a cross-stream board, and a findings-intersection table.

Three modes carry the everyday loop:

Table The three everyday modes
CommandWhat it doesWhen to use it
statusgen Generate STATUS.md from sources. Writes the file. Locally, to read the board and see Next-up. Never commit it on a branch.
statusgen --lint Run every source check and build the view internally, but never read or write STATUS.md. Pull-request CI. Blocks changes carrying malformed briefs, broken dependency graphs, or a hand-edited board.
statusgen --check Regenerate STATUS.md internally and compare byte-for-byte to the committed version. Drift check. Advisory — not a gate by default.

The surface is larger than those three. Alongside the board it carries an execution witness that runs a brief's Verify table and writes back a three-state result per row; a set of read-only instrument views (delivery metrics, a transition historian, a per-stage bottleneck report, register alarms, a launch-readiness rollup); and several narrow checks used by the desks. The three above are what an adopting team needs on day one; statusgen --help is the authority on the rest, and this page deliberately does not try to be a command reference that would go stale the first time a flag was added.


The single-writer model

Only one CI job — triggered on push to the default branch — ever commits STATUS.md. Every other context (PRs, local runs) only reads or lints. This eliminates the entire class of merge conflicts on a generated file and makes drift between sources and status immediately visible: if a PR's lint step passes but the merged main regen produces different output, something changed under the PR.


What it checks

In --lint mode, statusgen runs every source check:

  • Brief frontmatter validity: every required field present, typed IDs, wave consistency, gate derived from risk, sources non-empty.
  • Dependency graph integrity: typed IDs only, depends and unblocks as mutual inverses, no self-loops, no wave violations.
  • Register integrity: ID format (slug-form on new entries, numeric grandfathered), duplicate IDs, and a tombstone check against branch history for entries that have gone missing.
  • Status cell format: lifecycle tokens only, dated and attributed entries in the Verified and Reviewed columns, no bare checkmarks.
  • Attribution floors: a risk-flagged brief cannot reach verified or done with an economy-tier runner recorded against it.
  • Findings cross-application: every finding's affected IDs resolve to real briefs; affected briefs are flagged stale and excluded from the queue until resolved.
  • Link resolution: a document reference that no longer resolves is a failure, not a broken link somebody notices later.
  • Stream frontmatter: required fields present, valid values.
  • Board immutability on branches: any change whose diff touches STATUS.md trips lint.

Lint separates its output into problems, which fail the run, and notices, which do not. The split is deliberate: a notice is for something a human should look at but which no machine can adjudicate — a brief closed before a mechanism existed, a standing alarm aging past its threshold, a queue growing faster than it drains. Promoting those to failures would train people to route around the checker, which costs more than the thing being flagged.


Repo-agnostic

statusgen is a standalone Go module — the standard library plus a YAML parser, and nothing else. Its module path is github.com/medici-finance/assay/statusgen. It knows nothing about any particular product: it reads a directory of stream documents and registers, and it will read yours.

It was extracted from an internal product repository in July 2026, already written repo-agnostic — the register and brief conventions on this site are the ones that build actually runs on, not a specification drafted for publication.


Take the binary, not the source

The obvious way to adopt a small self-contained tool is to copy its directory into your repository. That recommendation has been retired, on evidence from our own repositories rather than on principle.

A vendored copy is a fork, and forks rot in silence. The concrete case: a copied statusgen gating another repository's pull requests, frozen at the commit where it landed and untouched for weeks afterwards — still passing, still green, and missing three checks that had since been added upstream. Nothing failed. That is the problem. A gate that has quietly stopped checking what it is believed to check is worse than no gate, because a team stops looking at what it has delegated. Several sibling cases followed the same shape.

So the supported path is a pinned release binary: a small file in your repository names the release tag and the expected hash for each platform, installation verifies the hash, and upgrading is a one-line change reviewed like any other. One binary, one pin, one place to bump — and drift becomes a diff instead of a silence.

This repository is the canonical home for the tool; consumers take pinned releases from it rather than maintaining their own copy.


Reading

Status as a build artifact

What changes when the status board stops being a dashboard and becomes a generated file with one writer.

Article — publication pending

Drafted and referenced from the toolkit. The link activates on publication.