Check catalog
This page lists each check that Speccy runs with the built-in PRD and SDD profiles. A finding in Speccy links to the entry of its check.
A check has a slug, a level and a stage. A MUST finding makes the verdict Not Build Ready. A SHOULD finding counts in the score. An INFO finding is a hint. A profile can change the level of a check. The review pipeline explains the stages.
Lint checks run without a model, on every save. They check the writing and the structure.
frontmatter.readable
- Level: MUST
- Profiles: every profile
Speccy reads the doc’s frontmatter. The block parses, it sits where Speccy looks, and it holds links in the form Speccy reads.
To fix a finding: Correct the YAML or JSON of the block, move it to the top of the doc, and write each link as a kind and a target.
lint.asset-nudge
- Level: SHOULD
- Profiles: every profile
No code block and no table is longer than the profile’s limits for the doc body.
To fix a finding: Move the code or the table into an asset in the bundle, and link to it.
lint.broken-link
- Level: MUST
- Profiles: every profile
Each relative link and image points at a file in the bundle.
To fix a finding: Correct the path, or add the file to the bundle.
lint.dangling-ref
- Level: SHOULD
- Profiles: every profile
Each referenced trace ID has a definition in this doc or in a doc it implements or refines.
To fix a finding: Define the ID, correct the reference, or link the doc that defines it.
lint.duplicate-id
- Level: MUST
- Profiles: every profile
No trace ID has two definitions in the doc.
To fix a finding: Give the second item a new ID.
lint.passive-voice
- Level: INFO
- Profiles: every profile
A sentence names who acts. Speccy marks passive voice, such as “the request is retried”.
To fix a finding: Name the actor, such as “the service retries the request”.
lint.placeholder
- Level: MUST
- Profiles: every profile
The prose has no placeholder, such as TBD, TODO, XXX, FIXME, a {{…}} or <…> marker, or lorem ipsum.
To fix a finding: Write the text that the placeholder holds a place for, or delete the placeholder.
lint.prose-limit
- Level: SHOULD
- Profiles: every profile
The doc and each section’s own text stay under the profile’s word limits.
To fix a finding: Move detail into an asset or a linked doc, or split the section.
lint.required-headings
- Level: MUST
- Profiles: every profile
The doc has each heading that the profile template requires for the doc’s size.
To fix a finding: Add the missing heading and its text. A heading with a section number, such as “5. Decisions”, counts.
lint.requirement-grammar
- Level: SHOULD
- Profiles: every profile
A requirement definition parses into a trigger and a response, in one of the EARS shapes. The check is off until a profile gives it a level.
To fix a finding: Write the requirement as “When
lint.rfc2119-case
- Level: SHOULD
- Profiles: every profile
A requirement item writes MUST, SHOULD and MAY in upper case.
To fix a finding: Write the keyword in upper case, so that a reader sees the requirement level.
lint.sentence-length
- Level: SHOULD
- Profiles: every profile
No sentence is longer than the profile’s sentence word limit. Headings and table cells do not count.
To fix a finding: Split the sentence. Put one statement in each sentence.
lint.slop-phrase
- Level: SHOULD
- Profiles: every profile
The prose has no filler phrase from Speccy’s list, such as “it is important to note that”.
To fix a finding: Delete the phrase, and state the fact.
lint.undefined-acronym
- Level: SHOULD
- Profiles: every profile
Each acronym has a definition at its first use, as “Full name (ABC)” or “ABC (Full name)”.
To fix a finding: Write the full name next to the first use of the acronym.
lint.weasel
- Level: SHOULD
- Profiles: every profile
The prose has no vague word from Speccy’s list, such as “fast”, “several” or “as needed”.
To fix a finding: Replace the word with a number, a name or a condition that a builder can test.
trace.no-ids
- Level: INFO
- Profiles: every profile
A section that names requirements, decisions or non-functional requirements defines at least one trace ID. The finding is a hint, not a defect.
To fix a finding: Use Add IDs on the Traceability page, or write an ID at the start of each item.
trace.unknown-prefix
- Level: INFO
- Profiles: every profile
A token that looks like a trace ID, at the place of a definition, has a prefix that the profile reads.
To fix a finding: Use one of the profile’s prefixes, or add the prefix to the profile.
Rubric
Section titled “Rubric”Rubric checks ask a model one question about the doc. The profile writes the question and the condition that passes it.
prd.consistency
- Level: MUST
- Profiles: PRD
The check asks: Do any two statements in the doc contradict each other?
It passes when: No two statements in the doc contradict each other.
prd.dependencies
- Level: MUST
- Profiles: PRD
- Sizes: app, initiative
The check asks: Are dependencies on other teams or systems listed?
It passes when: Dependencies on other teams or systems are listed, or the doc says “none”.
prd.goals.baseline
- Level: SHOULD
- Profiles: PRD
- Sizes: app, initiative
The check asks: Does each metric have a baseline?
It passes when: Each metric has a current baseline value.
prd.goals.measurable
- Level: MUST
- Profiles: PRD
The check asks: Is each goal measurable?
It passes when: Each goal has a metric and a target value.
prd.nfr
- Level: SHOULD
- Profiles: PRD
- Sizes: app, initiative
The check asks: Are performance, security, accessibility, and privacy needs addressed?
It passes when: Performance, security, accessibility, and privacy needs are stated or marked not applicable.
prd.non-goals
- Level: MUST
- Profiles: PRD
The check asks: Does the doc list what the product will not do?
It passes when: A section lists at least one thing the product will not do.
prd.open-questions
- Level: MUST
- Profiles: PRD
- Sizes: app, initiative
The check asks: Are open questions listed with an owner?
It passes when: Open questions are listed with an owner each, or the doc says “none”.
prd.problem.evidence
- Level: MUST
- Profiles: PRD
The check asks: Does the problem statement have evidence?
It passes when: The problem has evidence, such as a metric, a ticket, or a user quote.
prd.problem.who
- Level: MUST
- Profiles: PRD
The check asks: Does the doc name who has the problem?
It passes when: The doc names the people or the role that has the problem.
prd.release-scope
- Level: SHOULD
- Profiles: PRD
- Sizes: app, initiative
The check asks: Does the doc state what ships first?
It passes when: The doc states what ships first.
prd.req.acceptance
- Level: MUST
- Profiles: PRD
The check asks: Does every requirement have an acceptance criterion?
It passes when: Every requirement has an acceptance criterion that a tester can check.
prd.req.ids
- Level: MUST
- Profiles: PRD
The check asks: Does every requirement have a trace ID?
It passes when: Every requirement has a trace ID.
prd.req.priority
- Level: SHOULD
- Profiles: PRD
The check asks: Does every requirement have a priority?
It passes when: Every requirement has a priority (MUST, SHOULD, or COULD).
prd.req.what-not-how
- Level: SHOULD
- Profiles: PRD
The check asks: Do the requirements state what users need, not a technical design?
It passes when: Requirements state what users need, not a technical design.
prd.risks
- Level: SHOULD
- Profiles: PRD
- Sizes: app, initiative
The check asks: Are risks listed with a mitigation or an owner?
It passes when: Risks are listed, each with a mitigation or an owner.
sdd.components
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Does each component have a stated responsibility?
It passes when: Each component has a stated responsibility.
sdd.consistency
- Level: MUST
- Profiles: SDD
The check asks: Do any two statements in the doc contradict each other?
It passes when: No two statements in the doc contradict each other.
sdd.data.model
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Is each stored entity described with fields, types, and constraints?
It passes when: Each stored entity has fields, types, and constraints, in the doc or a linked asset.
sdd.data.ownership
- Level: SHOULD
- Profiles: SDD
- Sizes: app, initiative
The check asks: Does each entity have one owning component?
It passes when: Each entity has exactly one owning component.
sdd.decisions.alternatives
- Level: SHOULD
- Profiles: SDD
The check asks: Does each decision list a rejected alternative?
It passes when: Each decision lists at least one rejected alternative with a reason.
sdd.decisions.ids
- Level: MUST
- Profiles: SDD
The check asks: Does every design decision have a trace ID?
It passes when: Every design decision has a trace ID.
sdd.delivery
- Level: SHOULD
- Profiles: SDD
- Sizes: app, initiative
The check asks: Are milestones ordered with exit criteria?
It passes when: Milestones are ordered and each has exit criteria.
sdd.failure-modes
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Does each external dependency have a stated failure behaviour?
It passes when: Each external dependency has a stated failure behaviour.
sdd.interfaces
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Does each interface have inputs, outputs, and errors?
It passes when: Each interface has inputs, outputs, and errors, in the doc or a linked asset.
sdd.limits
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Do sizes, rates, and timeouts have numbers?
It passes when: Sizes, rates, and timeouts have numbers.
sdd.migration
- Level: SHOULD
- Profiles: SDD
- Sizes: app, initiative
The check asks: Are data and rollout migration described?
It passes when: Data and rollout migration are described, or marked not applicable.
sdd.non-goals
- Level: MUST
- Profiles: SDD
The check asks: Does the doc list what the system will not do?
It passes when: A section lists at least one thing the system will not do.
sdd.observability
- Level: SHOULD
- Profiles: SDD
- Sizes: app, initiative
The check asks: Are logs, metrics, and alerts stated?
It passes when: Logs, metrics, and alerts are stated.
sdd.open-questions
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Are open questions listed?
It passes when: Open questions are listed, or the doc says “none”.
sdd.performance
- Level: SHOULD
- Profiles: SDD
- Sizes: app, initiative
The check asks: Do performance targets have numbers?
It passes when: Performance targets have numbers.
sdd.security
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Are authentication, authorisation, secrets, and untrusted input addressed?
It passes when: Authentication, authorisation, secrets, and untrusted input are addressed.
sdd.state
- Level: SHOULD
- Profiles: SDD
- Sizes: app, initiative
The check asks: Does each stateful entity have its states and transitions?
It passes when: Each stateful entity has its states and transitions.
sdd.testing
- Level: MUST
- Profiles: SDD
- Sizes: app, initiative
The check asks: Does the test strategy name what proves each MUST requirement?
It passes when: The test strategy names what proves each MUST requirement.
Grounding
Section titled “Grounding”Grounding checks compare the doc’s factual claims with the sources that the profile’s source policy accepts.
grounding.contradicted-claim
- Level: MUST
- Profiles: every profile
No factual claim in the doc conflicts with a source that the profile’s source policy accepts.
To fix a finding: Correct the claim, or cite a source that supports it.
grounding.unverified-claim
- Level: SHOULD
- Profiles: every profile
Each factual claim in the doc has a source that the profile’s source policy accepts.
To fix a finding: Cite a source for the claim, or state it as an assumption.
Divergence
Section titled “Divergence”Divergence checks give the doc to independent readers, who answer the build questions from the doc only.
divergence.ambiguous
- Level: the level of its build question
- Profiles: every profile
Independent readers give one meaning for each build question.
To fix a finding: Rewrite the text that the question cites, so that it has one meaning.
divergence.gap
- Level: the level of its build question
- Profiles: every profile
The doc answers each build question. All the readers answered that the doc does not say.
To fix a finding: Add the answer to the section that the question cites.
Coherence
Section titled “Coherence”Coherence checks read the doc together with the docs it links to.
coherence.contradiction
- Level: MUST
- Profiles: every profile
No statement in this doc conflicts with a statement in a doc it implements, refines or references.
To fix a finding: Change one of the two statements, so that the docs agree.
coherence.external
- Level: SHOULD
- Profiles: PRD, SDD
The check asks: Does this doc agree with the issues and pages it links to?
It passes when: No statement in this doc conflicts with a linked issue or page.
coherence.restatement
- Level: SHOULD
- Profiles: every profile
No paragraph repeats more than half of a paragraph in the upstream doc.
To fix a finding: Link to the upstream text, and do not repeat it.
links.code-drift
- Level: SHOULD
- Profiles: PRD, SDD
The check asks: Has the code this doc points at changed since this version?
It passes when: No implemented-by target has a commit newer than this version.
links.external-target
- Level: MUST
- Profiles: PRD, SDD
The check asks: Does every external link target parse?
It passes when: Every external link target is a github target, a scheme with a pattern, or a full URL.
links.has-children
- Level: MUST
- Profiles: every profile
A doc of the size the profile names links the docs it covers.
To fix a finding: Add a references or refines link for each doc that this doc covers.
links.has-upstream
- Level: MUST
- Profiles: SDD
The check asks: Does the doc link to the PRD it implements?
It passes when: An implements link to a PRD exists, or a standalone acknowledgement exists.
trace.coverage
- Level: MUST
- Profiles: SDD
The check asks: Is every upstream REQ and NFR referenced or acknowledged?
It passes when: Every upstream REQ and NFR is referenced or acknowledged.