Факты и маркеры статуса
01Любой нормативный документ — список обещаний, и у каждого обещания есть состояние: предложено, строится, сделано, отброшено. vibe читает это состояние из маленького маркера, написанного рядом с обещанием, в Markdown или в форме XML, и одна команда говорит вам, когда маркер испорчен или стоит не на месте. Эта страница — грамматика этих маркеров.
Маркер
03Маркер — один элемент в форме XML, <status stage="…" state="…"/>, встроенный в Markdown или родной для диалекта. Точечный маркер самозакрывающийся; незакрытый не well-formed и считается ошибкой. Сокращение @status:spec/done значит то же, что элемент, а @status:impl само по себе значит impl/work, с одним исключением: @status:unknown значит unknown/hold. Старые написания без status: по-прежнему читаются. Каждый словарь закрыт: значение вне таблиц — ошибка с подсказкой ближайшего законного значения.
04 One XML-shaped element, embedded in Markdown (and, later, native in XML documents — the frontend duality of PROP-035 §5):
05 A point marker MUST be self-closing (/>). An unclosed<status …>point form is not well-formed XML and is acheckerror.
06@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.
07@status:impl⇒<status stage="impl" state="work"/>— bare shorthand defaults tostate="work", with exactly one exception:@status:unknown⇒state="hold". (@status:freeze⇒freeze/work: "freezing now".)
08 Vocabularies are closed. Any value outside the tables is acheckerror with a nearest-legal-value hint (typos likerewrokdie in CI, not in review).
Якоря
09У помеченной единицы должен быть адрес. В Markdown якорь — это @fact:ID первым токеном абзаца или элемента списка. Идентификатор начинается с буквы и продолжается буквами, цифрами, подчёркиванием и дефисом, и он делит одно адресное пространство с якорями заголовков, так что дубликат между двумя формами — ошибка. Маркер на единице без якоря — ошибка. Сканер игнорирует блоки кода, встроенный код и адреса, так что маркер, процитированный внутри них, — текст, а не маркер.
10 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.
11<ID>is[A-Za-z][A-Za-z0-9_-]*; the unit is then addressable asspec://…/<doc>#<ID>, sharing one address space with the heading{#anchor}s — a duplicate across both forms is acheckerror. The address is unchanged by the spelling: it names the id, never the opener.
12 Every unit that carries a status marker — paragraph or list item — MUST also carry a@fact:<ID>anchor; a marked, anchor-less unit is acheckerror.
13 Inside fenced code blocks, inline code spans, and URLs the element and the shorthand (§3.7) are not recognized — the scanner is fence-aware.
Где стоит маркер
14Мест четыре. Маркер документа стоит в преамбуле или сразу после первого заголовка, когда документ им открывается. Маркер раздела стоит один на строке после своего заголовка; это единственная законная отдельная позиция в теле. Маркер абзаца сидит внутри текста самого абзаца, первым или последним токеном. Каждый элемент списка — собственная единица, на любом уровне вложенности, и его маркер сидит внутри текста элемента. Маркер, стоящий один между двумя абзацами, — ошибка; догадки о ближайшем абзаце нет. Единица несёт не больше одного маркера статуса и сколько угодно маркеров действия.
15 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.
16 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.
17
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).
18 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).
19
A standalone marker between two paragraphs is a check error — there is
no "nearest paragraph" heuristic.
20 Multiple markers on one node: at most one status marker (stage/state), any number of action markers — a unit may legitimately needremove+actionstage="doc"andcontinue+actionstage="test"at once.
Как статус спускается и поднимается
21Маркер узла покрывает потомков, у которых своего нет. Вычисленный статус узла без маркера — худший из его детей, и unknown побеждает снизу.
22 Downward (defaulting): a node's marker covers unmarked descendants.
23
Upward (aggregation): an unmarked node's computed status is the
worst-of its children per the §3.3 order (unknown wins the bottom).
Действия, стадии и аудитории
24Рядом со статусом маркер может нести действие, что должно произойти дальше, а actionstage его сужает: action="remove" actionstage="doc" значит, что удалить надо документацию об этом, тогда как stage по-прежнему описывает саму единицу. Действие doc с audience — обязательство документации: страница, написанная для этой аудитории, должна процитировать факт, и vibe doc check --coverage проверяет, что такая есть.
25actionstagenarrows the target:action="remove" actionstage="doc"= "the documentation of this is to be removed", whilestagekeeps describing the unit itself.
26 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|agentlists them; it is the source of the coverage gatevibe doc check --coverage(PROP-057 §14, the ratchet PROP-047##DOC-COVERAGE-RATCHETnames), 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).
Что закрывает факт
27Факт может сказать, что его закрывает: @requires:implementation,verification прямо перед его финальным статусом в Markdown или атрибут requires в форме XML. Виды — закрытый список: specification, implementation, verification, documentation, decision, research, plan, disposition и external. Они называют артефакты закрытия, а не жанры: исследовательская заметка может требовать реализации.
28 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.@requiresitself has no legacy bare spelling. The XML-dialect equivalent is arequires="<kind>[,<kind>…]"attribute on the named or generic fact element, besidestatus; it is never an attribute of the standalone document/section<status>element. Both forms lower to one fact-owned semantic set.
29 The closed vocabulary, in canonical order, isspecification,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.
Инструмент
30vibe facts check — это линт, а --exhaustive требует маркер на каждом абзаце; vibe progress check — переходный псевдоним, который печатает новое написание. Наблюдаемые файлы названы включающими глобами в facts.toml в корне пакета: глобы, которые говорят, что наблюдается, и никогда не список исключений.
31 The CLI follows the boundary. The markup lint is a facts operation:vibe facts check [--exhaustive]becomes its durable home, withvibe progress checkkept 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 undervibe progress. The same wave repairs B-100: a bare--campaign <id>resolves againstcampaigns/<id>instead of silently minting a cwd-relative state zone. Landed:vibe facts checkcarries 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.
32 Optional dev-mode mechanics, configured by afacts.tomlat the package root (theclippy.tomlpattern — tool config, not manifest pollution);progress.tomlis read as a silent legacy fallback for the transition (owner correction 2026-08-22: the observed tree is a facts-layer concern).
33 Include-style globs name what is observed (not gitignore-style excludes):
Особые случаи и правила
34Документ, написанный до квалифицированного написания, продолжает разбираться: старые формы @spec/done и ##ID значат то же, что новые. Конвертация файла между Markdown и XML сохраняет каждый маркер, потому что маркер — часть модели, а не синтаксиса.