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:
| Command | What it does | When 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,
dependsandunblocksas 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
verifiedordonewith 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.mdtrips 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.