# Facts and their status markers {#root}

@status:doc/work @audience:author

[p01] A spec is a list of promises, and each promise has a state: proposed, being built, done, abandoned. vibe reads that state from a small marker written next to the promise, in Markdown or in the XML form, and one command tells you when a marker is malformed or in the wrong place. This page is the grammar of those markers.

[p02]
```sh
vibe facts check
```

```output
progress check: clean (2 files, 0 warning(s))
```

## The marker {#the-marker}

[p03] A marker is one XML-shaped element, `<status stage="…" state="…"/>`, embedded in Markdown or native in the dialect. A point marker is self-closing; an unclosed one is not well-formed and is an error. The shorthand `@status:spec/done` means the same as the element, and `@status:impl` alone means `impl/work`, with one exception: `@status:unknown` means `unknown/hold`. The older spellings without `status:` are still read. Every vocabulary is closed: a value outside the tables is an error, with the nearest legal value as a hint.

> [p04] One XML-shaped element, embedded in Markdown (and, later, native in XML
> documents — the frontend duality of PROP-035 §5):
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#STATUS-ELEMENT>

> [p05] A **point marker** MUST be self-closing (`/>`). An unclosed `<status …>`
>   point form is not well-formed XML and is a `check` error.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#POINT-SELF-CLOSING>

> [p06] `@status:<stage>/<state>` and `@status:<stage>` are macro-equivalents of a
> point marker. The **legacy** spellings `@<stage>/<state>` and `@<stage>` mean
> exactly the same and are still read, so a document written before the
> qualified form keeps parsing.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#SHORTHAND-FORMS>

> [p07] `@status:impl` ⇒ `<status stage="impl" state="work"/>` — bare shorthand defaults to
>   `state="work"`, with exactly one exception: `@status:unknown` ⇒ `state="hold"`.
>   (`@status:freeze` ⇒ `freeze/work`: "freezing now".)
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#SHORTHAND-BARE>

> [p08] Vocabularies are **closed**. Any value outside the tables is a `check` error
>   with a nearest-legal-value hint (typos like `rewrok` die in CI, not in
>   review).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#VOCAB-CLOSED>

## Anchors {#anchors}

[p09] A marked unit must have an address. In Markdown the [anchor](../glossary/index.xml#anchor) is `@fact:ID` as the first token of a paragraph or a list item. The id starts with a letter and continues with letters, digits, underscore and hyphen, and it shares one address space with the heading anchors, so a duplicate across the two forms is an error. A marker on a unit without an anchor is an error. The scanner ignores fenced code, inline code and addresses, so a marker quoted inside them is text, not a marker.

> [p10] **Fact anchors — the anchored-when-marked law** *(owner, 2026-07-24;
>      spelling amended 2026-08-06)*. A stable fact address is written
>      `@fact:<ID>` as the **first token** of a paragraph or list item. The
>      **legacy** spelling `##<ID>` means the same and is still read.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#FACT-ANCHOR-SYNTAX>

> [p11] `<ID>` is
>      `[A-Za-z][A-Za-z0-9_-]*`; the unit is then addressable as
>      `spec://…/<doc>#<ID>`, sharing one address space with the heading
>      `{#anchor}`s — a duplicate across both forms is a `check` error. The
>      **address is unchanged by the spelling**: it names the id, never the
>      opener.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#FACT-ID-GRAMMAR>

> [p12] **Every unit that carries a status marker — paragraph or list item —
>      MUST also carry a `@fact:<ID>` anchor**; a marked, anchor-less unit is a
>      `check` error.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#ANCHORED-WHEN-MARKED>

> [p13] Inside fenced code blocks, inline code spans, and URLs the element and the
>   shorthand (§3.7) are **not recognized** — the scanner is fence-aware.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#FENCE-AWARE>

## Where a marker goes {#placement}

[p14] There are four places. A document marker stands in the preamble, or right after the first heading when the document opens with one. A section marker stands alone on the line after its heading; that is the only legal standalone position in a body. A paragraph marker sits inside the paragraph's own text, as its first or its last token. Every list item is a unit of its own, at every nesting level, and its marker sits inside the item's text. A marker standing alone between two paragraphs is an error; there is no nearest-paragraph guess. A unit carries at most one status marker and any number of action markers.

> [p15] **Document** — marker in the preamble, before the first heading.
>    *Pilot amendment (2026-07-24):* a document that **opens with its
>    heading** (the standard shape of this repo's specs) has no preamble;
>    there, the standalone marker immediately after that first heading is
>    the **document** marker, not a section marker.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#PLACE-DOCUMENT>

> [p16] **Section** — marker on its own line **immediately after the heading
>    line** (for any heading other than a preamble-less file's first one,
>    per the amendment above). This is the only legal standalone position
>    inside a body.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#PLACE-SECTION>

> [p17] **Paragraph** — marker **inside the paragraph's own text**: the first
>    token (right after the newlines, or right after the paragraph's `@fact:<ID>`
>    anchor) or the last token (right before them).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#PLACE-PARAGRAPH>

> [p18] **List item** *(fact amendment, 2026-07-24 — owner-directed)* — every
>    item of a bulleted or numbered list is a **unit of its own**, at every
>    nesting level. Its marker — shorthand or XML form alike — sits **inside
>    the item's own text**: the first or last token of the item (before any
>    nested sub-items, which carry their own markers).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#PLACE-LIST-ITEM>

> [p19] A standalone marker between two paragraphs is a **`check` error** — there is
>   no "nearest paragraph" heuristic.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#NO-ORPHAN-MARKER>

> [p20] Multiple markers on one node: at most **one** status marker (stage/state), any
> number of **action** markers — a unit may legitimately need
> `remove`+`actionstage="doc"` and `continue`+`actionstage="test"` at once.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#MULTI-MARKERS>

## How a status rolls up and down {#rollup}

[p21] A node's marker covers the descendants that carry none. An unmarked node's computed status is the worst of its children, and `unknown` wins the bottom.

> [p22] **Downward (defaulting):** a node's marker covers unmarked descendants.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#ROLLUP-DOWNWARD>

> [p23] **Upward (aggregation):** an unmarked node's computed status is the
>   worst-of its children per the §3.3 order (`unknown` wins the bottom).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#ROLLUP-UPWARD>

## Actions, stages and audiences {#actions}

[p24] Beside the status a marker may carry an action, what should happen next, and `actionstage` narrows it: `action="remove" actionstage="doc"` means the documentation of this is to be removed while `stage` still describes the unit itself. A `doc` action with an `audience` is an obligation of the documentation: a page written for that audience must cite the [fact](../glossary/index.xml#fact), and `vibe doc check --coverage` checks that one does.

> [p25] `actionstage` narrows the target: `action="remove" actionstage="doc"` = "the
> documentation of this is to be removed", while `stage` keeps describing the
> unit itself.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#ACTIONSTAGE-NARROWS>

> [p26] Primary use: `actionstage="doc"`
>   markers with an audience are the **obligations** of the documentation —
>   the promises a page for that audience must cite. `vibe progress report
>   --view doc --audience user|author|dev|agent` lists them; it is the source
>   of the coverage gate `vibe doc check --coverage`
>   ([PROP-057 §14](../../common/PROP-057-documentation-packages-and-site.xml),
>   the ratchet PROP-047 `##DOC-COVERAGE-RATCHET` names), never a table of
>   contents — navigation is derived from the page manifest (amended
>   2026-09-11; the earlier wording fed the two guides' tables of contents).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#AUDIENCE-DOC-USE>

## What closes a fact {#requires}

[p27] A fact may say what closes it: `@requires:implementation,verification` right before its final status in Markdown, or a `requires` attribute in the XML form. The kinds are a closed list, `specification`, `implementation`, `verification`, `documentation`, `decision`, `research`, `plan`, `disposition` and `external`. They name closure artifacts, not genres: a research note may require an implementation.

> [p28] The Markdown form is
>       exactly one qualified trailing annotation
>       `@requires:<kind>[,<kind>…]`, immediately before the fact's final
>       status shorthand admitted by §3.7 (qualified full/bare or legacy
>       full/bare), or final `<status …/>` point marker. `@requires` itself has
>       no legacy bare spelling. The XML-dialect equivalent
>       is a `requires="<kind>[,<kind>…]"` attribute on the named or generic
>       fact element, beside `status`; it is never an attribute of the standalone
>       document/section `<status>` element. Both forms lower to one fact-owned
>       semantic set.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#REQUIRES-GRAMMAR>

> [p29] The closed
>         vocabulary, in canonical order, is `specification`, `implementation`,
>         `verification`, `documentation`, `decision`, `research`, `plan`,
>         `disposition`, `external`. A new kind requires an amendment here before
>         parser, IR or wire support. These are closure artifacts, not document
>         genres: a research document may require an implementation, and a
>         contract fact may itself be a decision artifact.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#REQUIRED-ARTIFACT-KINDS>

## The tool {#the-tool}

[p30] `vibe facts check` is the lint, and `--exhaustive` demands a marker on every paragraph; `vibe progress check` is a transitional alias that prints the new spelling. The observed files are named by include globs in `facts.toml` at the package root: globs that say what is observed, never a list of exclusions.

> [p31] **The CLI follows the boundary.** The markup lint is a facts
> operation: `vibe facts check [--exhaustive]` becomes its durable home, with
> `vibe progress check` kept as a transitional alias (printing the new spelling);
> the gate panel switches to the facts spelling. Campaign verbs
> (`scan`/`mirror`/`seal`/`gate`/`baseline`/`rescan`/`resume`/`weave`/`report`)
> stay under `vibe progress`. The same wave repairs B-100: a bare `--campaign
> <id>` resolves against `campaigns/<id>` instead of silently minting a
> cwd-relative state zone. Landed: `vibe facts check` carries the lint
> byte-identically (one implementation, two entries), the alias prints its
> stderr note (suppressed under --json), the shared campaign resolver fails
> loud on an unknown bare id with the existing zones listed and writes
> nothing, and the gate panel's markup line runs the facts spelling —
> proven live on the original B-100 scenario.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#BOUNDARY-CLI>

> [p32] Optional dev-mode mechanics, configured by a `facts.toml` at the package
>   root (the `clippy.toml` pattern — tool config, not manifest pollution);
>   `progress.toml` is read as a silent legacy fallback for the transition
>   (owner correction 2026-08-22: the observed tree is a facts-layer concern).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#CONFIG-FILE>

> [p33] Include-style globs name what **is** observed (not gitignore-style excludes):
>
> <spec://org.vibevm.core/vibevm/modules/vibe-facts/PROP-043#INCLUDE-STYLE>

## Edge cases and rules {#edge-cases}

[p34] A document written before the qualified spelling keeps parsing: the legacy `@spec/done` and `##ID` forms mean what the new ones mean. Converting a file between Markdown and XML keeps every marker, because the marker is part of the model, not of the syntax.

