Help us shape the future of Go! Take the 2026 Go Developer Survey

nfr

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package nfr is the nonfunctional-requirement spec format (SPEC-ADDITIONS §10.5): a Planguage-quantified quality attribute named by an agreed taxonomy. It binds the four things adh otherwise scatters into one testable unit — category (Tag, FURPS+/ISO-25010), measurement (Meter → a §13 tool), gate (Fail → the Evaluation acceptance bar), and rationale (Ambition → a decision/ADR). The type and its validation are a pure core; Load is the thin I/O shell.

Index

Constants

View Source
const DefaultDir = ".adh/nfr"

DefaultDir is the conventional repo path NFR specs live under (§10.5).

Variables

This section is empty.

Functions

This section is empty.

Types

type Direction

type Direction string

Direction is whether a larger measured value means better or worse quality.

const (
	Higher Direction = "higher" // bigger is better (availability, throughput)
	Lower  Direction = "lower"  // smaller is better (latency, error rate)
)

Direction values: whether a larger measured value is better or worse, so the Fail/Goal/Stretch thresholds can be checked for a consistent quality order.

type Spec

type Spec struct {
	ID        string    `json:"id"`
	Tag       string    `json:"tag"`
	Gist      string    `json:"gist,omitempty"`
	Ambition  string    `json:"ambition,omitempty"`
	Scale     string    `json:"scale"`
	Meter     string    `json:"meter"`
	Direction Direction `json:"direction"`
	Baseline  float64   `json:"baseline,omitempty"`
	Fail      float64   `json:"fail"`
	Goal      float64   `json:"goal"`
	Stretch   float64   `json:"stretch,omitempty"`

	// Guard marks a spec the change must not breach, as opposed to one it is trying
	// to improve (§10.5, §19.2).
	//
	// An arc's acceptance bar names what the change is *for*. Nothing named what it
	// must not cost, and **an objective without guards is hill-climbed by trading
	// away everything unmeasured** — `ruflo`'s loop raised a harness score 40 → 55 by
	// adding files a presence-counting metric rewarded, with no capability change,
	// and doubled a promotion rate by relaxing the predicate from AND to OR.
	//
	// It is a property of the **repository**, not of an arc, and that is the point of
	// putting it here rather than on the arc. A per-arc guard list would be more
	// expressive and would let the author of a change choose which guards apply to
	// it, which is the configurability that invites exactly the failure above: both
	// of ruflo's were a loop editing its own criteria.
	//
	// False is an ordinary objective, so a spec nobody marked does not silently
	// become a blocker.
	Guard bool `json:"guard,omitempty"`
}

Spec is one Planguage-quantified nonfunctional requirement (§10.5). Tag names the quality attribute under an agreed taxonomy (its head is a FURPS+/ISO-25010 category, e.g. "Performance.Latency"); Scale is the unit; Meter is how it is measured (a §13 tool id or a method); Fail is the acceptance bar the Evaluation gate enforces, Goal the target, Stretch (optional) the point past which more investment stops paying; Ambition is the rationale a decision/ADR records.

func ByID

func ByID(specs []Spec, id string) (Spec, bool)

ByID returns the spec with the given id, so a caller that already knows an NFR by name (a critic finding's Ref, §19.2) can resolve it to its Planguage thresholds.

func Guards

func Guards(specs []Spec) []Spec

Guards returns the specs a change must not breach, in the order declared.

Requires: nothing. Ensures: empty rather than nil when none is marked, so a caller need not distinguish "no guards declared" from "did not look". Pure.

func Load

func Load(dir string) ([]Spec, error)

Load reads NFR specs from JSON files under dir. An absent directory yields no specs and no error, so a repo that declares no NFRs is not an error.

func (*Spec) Meets

func (s *Spec) Meets(value float64) bool

Meets reports whether a measured value satisfies the Fail acceptance bar — the gate threshold the Evaluation stage enforces (§SPEC 3.1). Higher-is-better needs value ≥ Fail; lower-is-better needs value ≤ Fail.

func (*Spec) Regressed

func (s *Spec) Regressed(value float64) bool

Regressed reports whether a measured value is worse than the spec's baseline.

Requires: nothing. Ensures: **false when Baseline is unset**, because a spec with no baseline has nothing to have regressed from — and reporting every unbaselined spec as regressed would make the signal noise on its first run. Direction-aware, and pure.

It is distinct from Meets, and the gap between them is the point: Meets asks whether the value clears the acceptance bar, and this asks whether it got worse. A change can pass every bar and still cost something, which is the case that used to advance an arc with nothing recorded.

func (*Spec) Valid

func (s *Spec) Valid() error

Valid reports whether the spec is a well-formed Planguage requirement: a non-empty id, a Tag led by a known taxonomy category, a Scale, a Meter, a valid Direction, and Fail/Goal/Stretch ordered so quality increases (§10.5). It returns EINVALID on the first defect. Baseline is informational (a failing baseline is legitimate), so it is not ordered-constrained.

Jump to

Keyboard shortcuts

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