Check rules
manni strategy check reads the records and the pages that name them, and
reports what does not line up. It reads metadata, never prose. Each rule id
is manni:strategy/<rule>. Each rule’s level can be moved or turned off under
strategy.severity, as the configuration
shows.
The rules
Section titled “The rules”| Rule | Default | Fires when |
|---|---|---|
undefined-reference | error | A page’s audiences:, personas: or journeys:, or a record’s audience: or personas:, names no record of that type. |
duplicate-id | error | Two records share an id, ignoring case. |
missing-parent | warning | A page names a journey but none of its personas in personas:, or a persona but not its audience in audiences:. |
orphan-record | warning | A persona names no audience, or a journey names no persona, while the set holds records of the parent type. |
unserved-journey | warning | No page names the journey in journeys:. Records do not count, and a draft or archived journey is exempt. |
unused-record | notice | No page and no record names an audience or a persona. |
broken-step | error | A step’s doc names no page, or a step says exists: true or partial and has no doc. A step with exists: false is exempt. |
stale-step | warning | A step says exists: false, and its doc names a page. |
missing-journey | warning | A step’s page does not name the journey in journeys:. |
unwritten-step | notice | A step says exists: false, or has no doc. |
Records and references
Section titled “Records and references”A record is a page that declares type: audience, type: persona or
type: journey, in any format manni meta reads. Its id is its id:, or
the file name without its extension when it has none. A persona names its
audience in audience:. A journey names the personas it serves in
personas:, as one string or a list.
A reference is a value of a page’s audiences:, personas: or journeys:,
as one string or a list. The pages are read the way manni meta validate
reads them. So a value that a {page}.meta.yaml sidecar holds counts, and a
finding about it sits at the sidecar’s line.
Every id compares ignoring case. A field is checked only when the set holds a
record of that field’s type. A docset with persona records and no audience
records keeps a free-form audiences:, and no rule reads it.
Borrowed records
Section titled “Borrowed records”A record or page read from outside the run’s directory is borrowed. The run’s
directory is the config file’s, or the working directory when no config file
governs the run. A file is outside it when its path from there starts with
.., or sits on another drive.
A path typed on the command line resolves from the working directory. So a
run over typed paths also owns the working directory, wherever -c puts the
config file.
A borrowed file resolves references like any other, and no rule files a
finding in it. A local page’s typo still fails against borrowed records, with
its did-you-mean. A borrowed journey no page names draws no
unserved-journey, and a borrowed persona no page names draws no
unused-record. A borrowed journey’s steps are each unchecked, so no step
rule fires. Share one strategy across repositories
sets it up.
A journey can carry steps:, its stages in order, each with the page that
carries it. Each item is a mapping of stage, doc, exists and note.
A field of another type reads as absent, and manni meta validate checks
the shape. Steps count from 1, in the order written.
A step’s doc names a page in one of two forms:
- A repo path, such as
docs/guide.md. It resolves from the config file’s directory, or from the working directory when no config file governs the run. It names the file exactly. - A site route, a path that starts with
/, such as/manni/meta/ci/. It resolves throughgraph.routes, as a link does formanni graph.manni strategyreadsgraph:only when a step names a route.
Anything after # or ? is dropped first, so an anchor is not checked. A
URL with a scheme, such as https://, is not checked. Neither is a route
that no graph.routes entry covers. A record is never a step’s page.
Each step gets one state. The tool detects what it can, and reads exists
only for what it cannot detect:
doc | exists | State |
|---|---|---|
names a page that names the journey in journeys: | absent, true or false | served |
| names a page that does not | absent, true or false | unclaimed |
| names a page | partial | partial |
| names no page | false | unwritten |
| absent | absent or false | unwritten |
| names no page | absent, true or partial | broken |
| absent | true or partial | broken |
| a scheme URL or an unmapped route | absent, true or partial | unchecked |
| a scheme URL or an unmapped route | false | unwritten |
A step that names a page claims it exists, unless it says exists: false.
That tells a planned page from a typo. Coverage is the served steps over all
steps, so partial, unclaimed and unchecked steps do not count. A step
of a draft or archived journey draws no finding, and get and list
still show its state.
Every rule in one run
Section titled “Every rule in one run”This set breaks each rule once. A finding sits on the line of the value that
caused it. A finding about a whole record sits on its id: line, or on its
first line when it declares no id:
$ manni strategy checkdocs/guide.md:5 warning manni:strategy/missing-parent personas: does not name "maya", the persona of journey "m1". Add it, or drop "m1" from journeys:. manni:strategy missing-parent: A page names a journey but none of its personas in personas:, or a persona but not its audience in audiences:. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#missing-parent error manni:strategy/undefined-reference journeys: "m9" names no journey. Did you mean "m1"? Correct the value, or add a record with type: journey and id: m9. manni:strategy undefined-reference: A page's audiences:, personas: or journeys:, or a record's audience: or personas:, names no record of that type. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#undefined-referencestrategy/audiences/ci-engineers.md:1 notice manni:strategy/unused-record no page and no record names this audience. manni:strategy unused-record: No page and no record names an audience or a persona. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#unused-recordstrategy/journeys/d1.md:3 warning manni:strategy/unserved-journey no page names this journey in journeys:. Name it on the pages that serve it. manni:strategy unserved-journey: No page names the journey in journeys:. Records do not count, and a draft or archived journey is exempt. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#unserved-journeystrategy/journeys/m1.md:3 error manni:strategy/duplicate-id id: "m1" is also the id of strategy/journeys/m2.md:3. Give each record its own id. manni:strategy duplicate-id: Two records share an id, ignoring case. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#duplicate-idstrategy/journeys/m2.md:3 error manni:strategy/duplicate-id id: "M1" is also the id of strategy/journeys/m1.md:3. Give each record its own id. manni:strategy duplicate-id: Two records share an id, ignoring case. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#duplicate-idstrategy/personas/devin.md:1 warning manni:strategy/orphan-record audience: missing, so this persona belongs to no audience. Name one with audience:. manni:strategy orphan-record: A persona names no audience, or a journey names no persona, while the set holds records of the parent type. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#orphan-record
3 errors, 3 warnings, 1 notice in 7 recordsThe step rules need a journey with steps. This journey’s nine steps break
each of them. A finding about a doc sits on the doc: line, one about
exists on the exists: line, and an unwritten-step on the step’s first
line:
$ manni strategy checkstrategy/journeys/m1.md:16 warning manni:strategy/missing-journey step 4: docs/reference.md does not name "m1" in journeys:. Add it to that page's journeys:, or point the step at a page that does. manni:strategy missing-journey: A step's page does not name the journey in journeys:. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#missing-journeystrategy/journeys/m1.md:18 error manni:strategy/broken-step step 5: doc "docs/gide.md" names no page. Correct doc, or set exists: false if the page does not exist. manni:strategy broken-step: A step's doc names no page, or a step says exists: true or partial and has no doc. A step with exists: false is exempt. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#broken-stepstrategy/journeys/m1.md:21 warning manni:strategy/stale-step step 6: exists: false, but doc "docs/ci/index.md" names a page. Set exists: true or partial, or drop exists:. manni:strategy stale-step: A step says exists: false, and its doc names a page. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#stale-stepstrategy/journeys/m1.md:22 notice manni:strategy/unwritten-step step 7: doc "/site/tutorial/" names a page that does not exist. manni:strategy unwritten-step: A step says exists: false, or has no doc. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#unwritten-stepstrategy/journeys/m1.md:25 notice manni:strategy/unwritten-step step 8: no page carries this stage. manni:strategy unwritten-step: A step says exists: false, or has no doc. Guide: https://hawkeyexl.github.io/manni/strategy/reference/rules/#unwritten-step
1 error, 2 warnings, 2 notices in 4 recordsWhat each rule means
Section titled “What each rule means”undefined-reference
Section titled “undefined-reference”A value names no record of the type its field holds. The finding sits on the value’s line. When an id of that type is a few edits away, the message suggests it:
journeys: "s-17" names no journey. Did you mean "s17"? Correct the value, or add a record with type: journey and id: s-17.When the value is the id of a record of another type, the message says so. It suggests the record’s own persona or audience when it has one:
personas: "s17" is a journey, not a persona. Did you mean its persona, "sara"?A persona named in journeys: has no journey above it, so the message names
the field it belongs in instead: Move it to personas:.
A record’s audience: or personas: is checked the same way. Each value of
a journey’s personas: gets its own finding, on that value’s line:
personas: "mya" names no persona. Did you mean "maya"?duplicate-id
Section titled “duplicate-id”Reported on every record that shares the id, each naming the others with
their file and line. Ids compare ignoring case, so M1 and m1 collide.
Two files with no id: and the same name in different folders collide too.
Give each record its own id.
A borrowed record draws no finding. When every other record with the id is borrowed, the fix on the owned record says to remove the copy:
id: "maya" is also the id of ../manni/docs/content-strategy/personas/maya.md:3. That record is borrowed from outside this repository. Remove this copy, or give it its own id.When another owned record shares the id too, each owned record keeps
Give each record its own id.
missing-parent
Section titled “missing-parent”A page that names a journey also names at least one of that journey’s personas. A page that names a persona also names its audience. The rule reads a page’s own values and not a record’s. It reports each missing parent once per page, on the line of the first value that implies it:
personas: does not name "maya", the persona of journey "m1". Add it, or drop "m1" from journeys:.audiences: does not name "schema-authors", the audience of persona "sara". Add it, or drop "sara" from personas:.A journey that serves several personas is satisfied by any one of them. When the page names none, the message lists them all:
personas: names none of "maya", "sara", the personas of journey "m5". Add one, or drop "m5" from journeys:.orphan-record
Section titled “orphan-record”A persona with no audience:, or a journey with no personas:. It fires only
while the set holds a record of the parent type, so a set with no audience
records has no orphan personas. Name the parent:
audience: missing, so this persona belongs to no audience. Name one with audience:.personas: missing, so this journey belongs to no persona. Name one with personas:.unserved-journey
Section titled “unserved-journey”No page names the journey in journeys:. A record’s own journeys: serves
no reader, so it does not count. A journey can carry lifecycle from the
manni:lifecycle:1.0.0
vocabulary. A draft journey is not live yet, and an archived one no
longer is, so the rule skips both.
There are two fixes. Name the journey on the pages that serve it. Or, while
those pages are still to be written, mark the journey lifecycle: draft:
---type: journeyid: m33title: Hold a new page to its journeypersonas: [maya]lifecycle: draft---Raise the rule to error once every journey is served. A new journey then
lands with a page that serves it, or as a draft.
unused-record
Section titled “unused-record”No page names the audience or persona, and no record names it as its parent.
It is a notice, so it never fails a run. A journey has unserved-journey
instead.
broken-step
Section titled “broken-step”A step’s doc names no page of the run, or a step claims a page with
exists: true or partial and names none. Both leave a dangling path in the
journey, so the rule is an error. The finding sits on the doc: line, or on
the exists: line when there is no doc:
step 5: doc "docs/gide.md" names no page. Correct doc, or set exists: false if the page does not exist.step 3: exists: true, but the step has no doc. Name its page in doc:, or set exists: false.Correct the path or the route. When the page is still to be written, say so
with exists: false, and the step becomes an unwritten-step notice. A run
given paths reads only those pages, so a step whose page is outside them is
broken there.
stale-step
Section titled “stale-step”A step says exists: false, and its doc names a page that is there. The
page was written after the step. The finding sits on the exists: line:
step 6: exists: false, but doc "docs/ci/index.md" names a page. Set exists: true or partial, or drop exists:.missing-journey
Section titled “missing-journey”A step’s page does not name the journey in its own journeys:. Other tools
read the page’s journeys:, so the step alone does not make the claim. The
finding names the page by its path from the working directory, and sits on
the doc: line:
step 4: docs/reference.md does not name "m1" in journeys:. Add it to that page's journeys:, or point the step at a page that does.Add the journey to the page’s journeys:, or point the step at the page that
carries the stage. A journey whose steps’ pages all leave it out also draws
unserved-journey, and each names its own fix.
unwritten-step
Section titled “unwritten-step”A step says exists: false, or has no doc at all. It gives a planned page
a file and a line. It is a notice, so it never fails a run. The finding sits
on the step’s first line:
step 7: doc "/site/tutorial/" names a page that does not exist.step 8: no page carries this stage.Write the page and drop exists: false, or turn the rule off under
strategy.severity.