Promote, move, or retire a document
Authority is not a folder. A document's tier and status say how much weight a reader gives it, so
a move is a claim, and check --base verifies the claim against the branch's history.
1. Nothing in reference/ may be implemented directly
Installed as a plugin, docs-notary's reference-read hook says so on every Read of a document
whose status is reference: not a commitment, never a build spec, and here is the mv that
promotes it. The hooks run the engine the host repository installed (node_modules/@puralex/docs-notary), or the plugin's own copy only in a clone where yaml resolves; a plugin install is a bare clone, so on the vendored route both hooks are silent. Promote it first, then rewrite the prose to describe this product:
docs-notary mv docs/reference/<name>.md docs/product/<name>.md
Run these as npx docs-notary … (npm install) or node scripts/<script>.mjs (vendored — the script names differ from the command names: check is check-docs.mjs, new is new-doc.mjs, mv is mv-doc.mjs, gen is gen-docs-index.mjs); a bare
docs-notary is on PATH only inside an npm script.
mv is git mv plus a restamp: it sets kind and module for the destination, and sets status
to the destination tier's forced status if it has one, else --status, else draft when leaving
reference, else the status the document already had. product/ forces nothing and no --status
is passed above, so this example lands on draft — the reference → draft edge. mv also sets
updated to today (a promotion is a substantive change and the rewrite is mandatory) and records
promoted_from. That field is what lets check --base tell a promotion from a copy. A bare
git mv across tiers records no promoted_from and fails promoted-verbatim under check --base.
Then rewrite. Promoting a captured document verbatim is how someone else's assumptions become your
requirements. check --base <ref> compares the promoted body with the origin's body before the
branch and fails promoted-verbatim when they are identical. Rewriting the prose is the half no
command can do.
2. Status transitions the gate allows
check --base <ref> compares each changed document's status with its status at the merge base and
allows only these edges. Any other edge is a transition error.
| From | To |
|---|---|
reference |
draft, superseded |
draft |
active, superseded |
active |
shipped, superseded, draft |
shipped |
superseded |
superseded |
nothing |
An unchanged status is always legal. A status the project added in its config is in no graph and
moves freely. reference/ forces reference; archive/ forces superseded.
draft→active: the work is agreed. Bumpupdated.active→shipped: convention, not enforcement — name the paths incode:and giveevidence:the gate can check anyway;shippedwithoutcode:only warns (shipped-code), and the gate requiresevidence:on no kind by default. Never ship on the strength of the plan's own "done" prose; if in doubt, docs-audit runsverifyfirst.active→draft: the plan was reopened. Say why in the body.
3. Supersede, then archive
When a newer document replaces an older one:
- Set
superseded_by: docs/<tier>/<new-name>.mdon the old file. Leavestatusalone —supersededoutsidearchive/is avocabularyerror. - Move it:
docs-notary mv docs/<tier>/<old-name>.md docs/archive/<old-name>.md. Thearchive/tier forcesstatus: superseded. The prose stays as it was — an archived document is a record, andcheck --baseowes it no rewrite. - Fix every link that pointed at it. The gate catches a link still naming the old path (
link: the target is gone) but not one you retarget at the archived copy —linknever reads a target's status, so a pointer at a superseded document is yours to notice.
A document whose own first line says SUPERSEDED belongs in archive/ whatever its frontmatter
says. A "closed" plan that still lists untaken steps is a live backlog and stays active.
4. Moves within a tier and hand-made moves
A rename inside one tier keeps status and needs no promoted_from; mv handles it, and sets
updated to today as it does on any move. After a move made by hand, docs-notary fix restamps
kind and module — the gate asserts they agree with the path. git mv renames for case alone in
one step. A file with no frontmatter at all is a stray, not a move: docs-sort.
5. Before you finish
docs-notary gen
docs-notary check --base <default-branch> # transition + promoted-verbatim run only here
docs-notary impact --base <default-branch> # documents whose claims cover the changed code
Update every link the move broke, then every document impact lists. A red gate is docs-gate.