Skip to main content
xspec gives you two lightweight annotation mechanisms at the node level: tags for open-ended classification, and the coverage attribute to opt specific nodes out of coverage measurement. Together they let you slice your requirement graph into meaningful subsets without changing the structure of the graph itself.

Tags

The tags prop accepts a whitespace-separated list of labels on any <S> section:
You can apply as many tags as you like, separated by spaces. Duplicate tag names collapse — tags="a a b" is equivalent to tags="a b".

Tag character rules

A tag follows the same character rules as an ID segment and may additionally contain .. For example, negative, temporal, p0, and edge.case are all valid tag names.

Tag scope

Tags are not inherited. Applying tags="negative" to a parent section does not automatically tag its children — each node is tagged only by its own tags prop. This is intentional: child requirements often have different classification needs than their parents. Tags are not rendered into compiled Markdown. They exist purely as graph metadata.

How tags are used

Tags surface in two places in xspec.config.ts:
  1. Coverage profile targetTags — restricts a coverage profile to only measure nodes that carry at least one of the listed tags:
  2. Policy rule tags selector — matches nodes by tag when defining allowed or forbidden dependency edges:

The coverage attribute

The coverage prop controls whether a node is included as a target in coverage measurement.

Accepted values

What coverage="none" does and does not do

Setting coverage="none" removes the node from coverage measurement — it won’t appear in coverage reports as something that needs to be covered. However:
  • The node can still be depended on via the d prop. Other requirements may declare edges to it normally.
  • The node still appears in impact reports — if it changes, xspec still traces which nodes are affected.
  • Descendants keep their own settings. If a parent has coverage="none", its children are not automatically excluded. Each child is governed by its own coverage prop (defaulting to required if omitted).
Use coverage="none" for contextual or framing sections that exist to orient readers rather than to specify behavior — for example, a top-level summary or a section that imports definitions from a glossary.

Practical tagging strategies

A consistent tagging convention makes coverage profiles and policy rules much easier to maintain. Here are a few patterns that work well: Test classification tags — tag requirements by the kind of testing they need:
Then create separate coverage profiles for negative and positive nodes to track them independently. Maturity tags — tag in-progress requirements so policy rules can prevent them being depended on by stable specs:
Priority tags — tag high-priority requirements and create a dedicated coverage profile to ensure they are covered before lower-priority ones:
Keep tag names lowercase and hyphenated for consistency (happy-path, not happyPath or HappyPath). Because tags are byte-wise and case-sensitive, mixing conventions silently creates separate tags.
Combining tags and coverage="none" — a node can carry both. Tags remain usable in policy selectors even when the node is excluded from coverage targets: