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