Skip to content

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.

  • 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 , the shall ”, or as another EARS shape.

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 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 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 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 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.