Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Prose analysis

MarkSpec performs quality analysis on the body prose of authored entries — the paragraphs and list items that describe what a requirement means, not just its identity. Prose analysis runs as a separate markspec lint pass after parsing and validation; it does not block markspec validate.

Scope

Only authored entries of Specification-family types are analysed. The scope predicate is:

shape = Authored  AND  core type ∈ { Requirement, Test, Contract, Record, Risk }
                        or a profile subtype of any of the above

Reference-shape entries are excluded — they point to external documents whose prose MarkSpec does not own. Core types outside the Specification family (e.g. SoftwareComponent, Definition, Annotation) are also excluded; structural descriptions and glossary entries follow different writing conventions.

Suppression-hygiene rules (MSL-Q9xx) run on all authored entries regardless of type.

Modal keywords signal the obligation level of a requirement. MarkSpec enforces the RFC 2119 / EARS convention that modals appear in lowercase:

KeywordObligation
shallMandatory
shall notProhibited
shouldRecommended
should notNot recommended
mayOptional
mustExternal constraint (use shall for internal)
must notProhibited (external constraint)

MSL-M060 — modal-keyword-uppercase (warning)

Fires when any of the above keywords appears in uppercase (SHALL, MUST, …) inside body prose. The formatter (markspec format) rewrites uppercase modals to lowercase automatically, so this diagnostic appears only on files that have not been formatted.

warning[MSL-M060]: requirements.md:12 modal keyword 'SHALL' in body prose is
uppercase (spec §3.4.1 canonical form is lowercase; 'markspec format' will
rewrite it)

Verbatim blocks (fenced code, math, feature snippets) are excluded — modal keywords inside code examples are not checked.

MSL-M061 — missing-modal-keyword (info)

Fires on Requirement entries (and profile subtypes) whose body contains no modal keyword at all. This is a style hint: a requirement without an obligation word is often a description masquerading as a requirement.

info[MSL-M061]: requirements.md:7 Requirement entry contains no modal keyword
(shall / should / may / must) — consider declaring one to make the obligation
explicit

EARS pattern recognition

EARS (Easy Approach to Requirements Syntax) defines five body forms for requirement entries. MarkSpec recognises the leading keyword of each form and uses it internally for normalization — capitalisation is preserved at sentence start and lowercased mid-sentence.

FormLeading keywordTemplate
Ubiquitous(none)The system shall
State-drivenWhileWhile state, system shall
Event-drivenWhenWhen event, system shall
UnwantedIfIf condition, system shall
OptionalWhereWhere feature, system shall

The EARS form is currently used for normalization only; no lint rule fires on an EARS keyword choice. Future rule group ears is reserved for form-specific checks (e.g. ensuring state-driven requirements name a concrete state).

GWT pattern

GWT (Given / When / Then) is the standard body form for Test entries. MarkSpec accepts GWT prose without enforcing structural rules in the current phase; the three clauses are plain prose paragraphs.

Recommended form:

- [SWT_BRK_0030] Debounce rejects short pulses

  Given the debounce threshold is 10 ms, When a pulse of 5 ms arrives, Then the
  output shall remain unchanged.

      Id: 01HGW3R9QNP4ABCDEFGHJKMNPQ
      Type: test
      Verifies: 01HGW2Q8MNP3RSTVWXYZABCDEF

GWT-specific lint rules (detecting missing clauses, mixed-form bodies) are planned for a future phase.

INCOSE lexicon rules

These rules flag vocabulary patterns that the INCOSE Guide to Writing Requirements (GtWR) identifies as common sources of ambiguity. All rules apply to prose-bearing blocks (paragraphs, notes, list items); tables, code, and math blocks are excluded.

CodeNameSeverityExamples of flagged text
MSL-Q302incose-r7-vague-termwarningsome, several, many, adequate, sufficient, reasonable, as needed
MSL-Q303incose-r8-escape-clausewarningas appropriate, where possible, if practicable, to the extent possible
MSL-Q304incose-r9-open-endedinfoincluding but not limited to, etc., and/or
MSL-Q305incose-r10-superfluous-infinitiveinfobe able to, be designed to, in order to
MSL-Q310incose-r26-absoluteinfo100%, always, never, complete, entirely
MSL-Q313incose-r16-notinfonot (whole-word; excludes note, notation)

Rules MSL-Q302 and MSL-Q303 are warning severity — they flag text that routinely causes requirement verification ambiguity. The remaining rules are info — informational hints that the author should consider but that do not necessarily indicate a defect.

Example

warning[MSL-Q302]: src/braking/requirements.md:14 vague term 'sufficient' in
body prose — specify a measurable threshold instead (INCOSE GtWR R7)

warning[MSL-Q303]: src/braking/requirements.md:19 escape clause 'as appropriate'
weakens verifiability (INCOSE GtWR R8)

Structural quality rules

Two rules check the shape of entries rather than their vocabulary.

MSL-Q400 — struct-title-length (info)

The entry title should be between 3 and 120 characters. A 1–2 character title is almost certainly incomplete; a title longer than 120 characters is usually a sentence that belongs in the body.

MSL-Q401 — struct-body-length (info)

The entry body should contain between 5 and 500 words. An entry with fewer than 5 words has no meaningful description; one exceeding 500 words is likely describing multiple concerns that should be split.

Both thresholds are hard-coded defaults in the current phase. Profile-level configuration (e.g. prose.struct.title.maxLength) is planned but not yet implemented.

Suppression

A rule can be silenced for a specific entry by adding two trailer attributes:

- [SRS_BRK_0108] Legacy inherited requirement

  The system shall operate as appropriate for the ambient conditions.

      Id: 01HGW2Q8MNP3RSTVWXYZABCDEF
      Markspec-disable: MSL-Q303
      Rationale: Verbatim from customer SRS version 1.2; cannot be rephrased
                 without an approved change request.

Both Markspec-disable and Rationale must be present; a suppression without a rationale fires MSL-Q900 (disable-without-rationale). Citing an unknown rule code fires MSL-Q901 (disable-unknown-rule). These two hygiene rules run on all authored entries regardless of type and cannot themselves be suppressed.

Running prose analysis

markspec lint <paths...>           # info, warning, error output to stderr
markspec lint --format json <paths...>  # structured JSON to stdout
markspec lint --strict <paths...>  # promote warnings to errors (exit 1)

The lint subcommand is separate from validate; the pre-commit hook (markspec hook) does not run lint — lint is a review-time quality gate, not a commit blocker.