ears

package
v0.9.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package ears implements the semantic pillar: classification and linting of requirements written in EARS (Easy Approach to Requirements Syntax).

Every rule in a spectackle spec file must match exactly one of the six EARS patterns. Vague prose is rejected by the linter; keywords are case-sensitive and uppercase (WHEN, WHILE, IF, THEN, WHERE, SHALL) so that lowercase occurrences in code fragments (e.g. "if (i < n)") never trigger a pattern.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compose

func Compose(p Pattern, s Slots) (string, error)

Compose builds the canonical EARS sentence for pattern p from slots. Clause order for Complex follows the EARS convention: WHERE, WHILE, WHEN/IF, response.

func FrontMatter

func FrontMatter(s string) string

FrontMatter returns the raw YAML between the fences, or "".

func IsProseSection

func IsProseSection(name string) bool

IsProseSection reports whether a heading name is a whitelisted prose section.

func MissingSlots

func MissingSlots(p Pattern, s Slots) []string

MissingSlots returns the slot names still required to compose a rule of pattern p. An empty result means Compose will succeed.

func ParseRules

func ParseRules(text, file string, startLine int) ([]Rule, []Finding)

ParseRules extracts rules from spec-file markdown (front matter already stripped by the caller, or absent). startLine is the 1-based line number of the first line of text within the original file. It reports structural findings (E005) alongside the parsed rules.

func StripFrontMatter

func StripFrontMatter(s string) (body string, bodyStartLine int)

StripFrontMatter removes a leading "---\n...\n---\n" YAML block and returns the remaining body plus the 1-based line number the body starts at.

Types

type Finding

type Finding struct {
	Code     string
	Severity Severity
	File     string
	Line     int
	Msg      string
}

Finding is one lint result, renderable as "! <code> <sev> <file>:<line> <msg>".

func LintFile

func LintFile(path string) ([]Finding, error)

LintFile parses and lints one spec file from disk (including front matter stripping identical to the cascade loader).

func LintSentence

func LintSentence(sentence, file string, line int) []Finding

LintSentence checks a single rule sentence (codes E001-E004, W001-W002).

func (Finding) String

func (f Finding) String() string

type Pattern

type Pattern uint8

Pattern is one of the six EARS rule patterns.

const (
	PInvalid    Pattern = iota
	PUbiquitous         // The <system> SHALL <response>.
	PEvent              // WHEN <trigger>, the <system> SHALL <response>.
	PState              // WHILE <state>, the <system> SHALL <response>.
	PUnwanted           // IF <condition>, THEN the <system> SHALL <response>.
	POptional           // WHERE <feature>, the <system> SHALL <response>.
	PComplex            // combination, e.g. WHERE ..., WHEN ..., the <system> SHALL ...
)

func Classify

func Classify(sentence string) Pattern

Classify returns the EARS pattern of a normalized rule sentence, or PInvalid if it matches none.

func PatternFromString

func PatternFromString(s string) Pattern

PatternFromString maps the one-letter tool encoding to a Pattern.

func (Pattern) String

func (p Pattern) String() string

type Rule

type Rule struct {
	ID        string
	Pattern   Pattern
	Text      string   // the EARS sentence
	Rationale string   // optional "Rationale:" paragraph
	Applies   []string // optional node IDs from "{applies: id,id}" heading suffix
	File      string
	Line      int // line of the "## <ID>" heading
}

Rule is one parsed spec rule (heading + sentence) inside a spec file.

type Section

type Section struct {
	Name string
	Line int // 1-based heading line within the given text
	Text string
}

Section is one prose section of a spec file.

func ParseSections

func ParseSections(text string) []Section

ParseSections extracts the whitelisted prose sections from spec-file markdown (front matter already stripped).

type Severity

type Severity uint8

Severity of a lint finding.

const (
	Error Severity = iota
	Warn
)

func (Severity) String

func (s Severity) String() string

type Slots

type Slots struct {
	System    string // "the <system>" subject; leading "the " is stripped
	Response  string // what the system SHALL do (must name something verifiable)
	Trigger   string // WHEN … (Event-driven, Complex)
	State     string // WHILE … (State-driven, Complex)
	Condition string // IF … (Unwanted behaviour, Complex)
	Feature   string // WHERE … (Optional feature, Complex)
}

Slots are the structured inputs a rule is composed from. End users and agents never hand-write EARS sentences; they fill slots (via the add_rule MCP tool, elicitation-guided) and the server composes and lints the sentence deterministically.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL