BoRoKnowledge baseGitHub

How a document gets promoted

The rule for moving a document out of staging and into this wiki, one-way, in a state nobody has to untangle later.

LivingUpdated 2026-08-24

Why there is a rule at all

Promotion is copying a file, and copying files is how the duplication started. A document sitting in boro-ops that only one person can read is a problem. The same document in two repositories, both editable, both looking authoritative, is a worse one — because now there is no way to tell which copy a reader should believe, and the answer changes depending on who edited last.

So the move is not finished when a document lands here. It is finished when the copy it came from has stopped being a place anyone edits.

A copy that exists is not a duplicate. A copy that can be edited is.

This page is the rule. Source inventory is the state — what has moved, what is next, what is still sitting where only one person can reach it.


The three questions, answered

1 · What makes a document ready to leave staging?

It carries a version and a status, and the status says it is current. The FSD carries “Controlling — confirmed current 2026-08-20”, which is the bar. A document with no version marker is not ready; promoting it produces a page nobody can date, and an undated page is one that quietly becomes wrong.

Being unfinished is not a bar. The design system has ten unapplied amendments and should still be promoted — an outstanding amendment is a fact about the document that the document itself records. Waiting for a clean one means waiting forever.

2 · Who says so?

The document is Who releases it
Canon — the FSD, the Terms of Service Jay. He owns the specification and the legal documents.
The design system, brand, standards CJ.
Lifecycle logic and the data model Brad.

The owner releases it; anyone can do the mechanical move. The distinction matters because the mechanical move is fifteen minutes and the release is a judgement about whether a document is ready to be treated as authority by people who were not in the room when it was written.

3 · What happens to the staged copy?

Not every origin is a staging copy. The FSD came out of boro-ops, a repository that exists to be left; the Terms of Service came out of Drive, where the executed instrument lives and belongs. There is nothing to stub there, and stubbing it would be vandalism. The test is whether the origin is a place anyone edits. A staging repository is; an executed document is not — it is a source of record, and the promoted copy is derived from it exactly the way the FSD’s is.

It becomes a stub, and the stub is the whole point. Not a deletion — a deletion loses the history and leaves anyone with the old path staring at a 404, wondering whether they have the wrong path or the wrong memory. Not a fork, obviously. A short file at the same path that says where the document went and that this is no longer the place to edit it.

A stub carries PROMOTED-OUT so a machine can recognise it, the destination, and the date.

A stub cannot drift. That is why it is preferred to any arrangement where both copies stay whole and something watches them. Watching is a check you have to keep passing; a stub is a state you can only leave deliberately.


Derived documents — the case the rule has to handle

Some documents do not have their source of record here, and never will. The FSD’s markdown is a conversion of a .docx that Jay holds. The simulator’s boro-tokens.css is a copy of a file the design system generates. In both cases this repository holds something derived, and the upstream keeps moving.

For those, promotion carries three extra obligations:

  1. Say so on the page. The Master FSD opens with a panel naming its source of record, who holds it, and what to do instead of editing. A derived document that does not announce itself is a trap.
  2. Never hand-edit. Re-convert. A hand-edit produces canon that nobody authored and that the source of record contradicts.
  3. Hash it, so a hand-edit is loud. The body hash goes in the manifest and is checked on every verification run.

What this does not do is detect a change made upstream. If Jay edits the .docx, nothing here goes red — the file is not reachable from this machine. That is a real gap and it is named rather than papered over: the check catches unauthorised edits here, not staleness there. Closing it means the .docx living beside its conversion, which is an ask, not a tool.

And it cannot tell you whether what was promoted was FAITHFUL. A hash proves a file has not changed since it was recorded; it says nothing about whether the conversion that produced it was any good. This is not hypothetical. The FSD’s first conversion silently collapsed three table cells — in each case a cell that duplicated the one beside it — shifting every later cell in those rows one column left. §6.2 read as though the Commitment Hold applied to Lane A alone; §8.2 read as though the borrower’s travel in a halfway meet was “$0.00 — nets out”. Both are load-bearing, both were wrong, and nothing in the file looked broken.

So when a fresh export of the source appears, compare against it:

python3 tools/promotion/compare-source.py "~/Downloads/BoRo Master FSD 07_30 V9.md"

It matches section by section on normalised text — the two exports differ in markdown dialect, escaping and image handling, and none of that is content. The FSD now reports 104 of 104 sections identical. Run it every time a new export arrives, and record the result in the manifest.


The mechanics

One promotion, one pull request. Not a batch. A batch of five means five documents in an ambiguous state if the review stalls, and each one needs untangling separately.

  1. Copy it byte-identically, or convert it repeatably. For markdown: cp, then shasum -a 256 both files and confirm they match. For an executed .docx: python3 tools/promotion/convert-docx.py <in.docx> <out.md>, which preserves heading level, paragraph order, table structure and emphasis and changes nothing else. The converter is the pointre-convert, never hand-edit is a fiction unless re-converting is a command somebody can run. The FSD’s first conversion was done by hand elsewhere, dropped three table cells, and could not be re-run.
  2. Render it. Frontmatter, titles and contents lists are added in the presentation layer, the same way the simulator derives everything it can rather than touching Brad’s master.
  3. Record it in the manifestsrc/data/sources.json: origin, destination, hash, date, source of record. The inventory page and the verifier both read that entry; neither keeps its own list.
  4. Stub the origin, in the origin’s own repository, with its own commit.
  5. Run the checks. ./tools/lifecycle/verify-all.sh — which now includes the promotion check.
  6. Report the baselines in the pull request, before and after, so a regression is attributable to a pass rather than to a month.
python3 tools/promotion/verify-promoted.py

What it checks: that every promoted file still hashes to what was promoted, and that the origin it came from is a stub rather than a document. What it cannot check is an origin in a repository the machine cannot see — boro-ops is not on Railway or in CI — so it says so on the line rather than reporting a pass it did not earn.


The stub

The file left behind at the origin path. Short on purpose — it exists to redirect a reader and to be recognisable to the verifier, not to restate anything.

# PROMOTED-OUT — BoRo Master Functional Specification

**This document has moved.** It now lives in the wiki, where Brad and Jay can read it:
`AstonVentureInc/boro-wiki``src/canon/BoRo_MasterFSD.md`, rendered at `/canon/master-fsd/`.

**Do not edit this file, and do not restore the content here.** It was promoted on
2026-08-24 so there would be exactly one copy anyone can change. Two editable copies is
the condition this move exists to end.

Source of record remains `BoRo_Master_FSD_07_30_V9.docx`, held by Jay. To change the
specification, re-convert from that document into the wiki copy.