Authoring · 03 of 17
Requirements
In this chapter: the requirement, the first secondary model kind , as a constraint bound to subject aspect paths: its anatomy, the bind vocabulary, the constraint/requirement distinction, tables as data, and the VerdictQuantity discipline that derives every acceptance quantity exactly once.
3.1 What a requirement is
A requirement is a constraint over primary aspect paths. It is the first kind of secondary model you author, and the anchoring rule governs every line of it: a requirement binds aspect paths, it never redefines them, never restates a subject fact, and never contains a number that belongs to the instrument (INV-3). The “shall” sentence is the human rendering; the model is the binding plus the limit.
Requirements live in data/<rec>/specification/requirements/, grouped in
scopes /req/<area>; a requirement’s full id is its scope plus its
identifier_fragment, /req/metrological/creep. Every requirement is
also the anchor for everything downstream: tests targets it, forms
reference it, and evaluation re-executes its limit against evidence to
produce a verdict. A requirement with no test is unverifiable; that is a
coverage finding the linter computes, not a review opinion.
3.2 Anatomy
Six parts, in authoring order, shown on the simplest metrological
requirement of R 60 (● data/r60/specification/requirements/metrological.yaml
, measuring-range-max):
- name: Maximum load of the measuring range
identifier_fragment: measuring-range-max
reference: "urn:oiml:pub:r:60-1:2021#clause-5.2"
statement: |
The value of the largest load applied to a load cell during test which
is expressed in units of mass shall not be greater than E_max.
binds_to:
- sample.test_context.d_max
- model.parameters.e_max
limit:
expression: "ocl{sample.test_context.d_max <= model.parameters.e_max}"
uses:
- sample.test_context.d_max
- model.parameters.e_max
verification:
method: definitional
- statement + reference, the normative “shall” sentence transcribed verbatim, and its clause-URN provenance. The statement is for humans; nothing downstream parses it.
- binds_to, the canonical aspect paths the requirement constrains (§3.3). This is the requirement’s anchor set and the machine’s answer to “what is this requirement about?”
- limit, the machine-checkable OCL
expression, withuseslisting every input the expression reads: attribute paths,observable:ids,formula:/table:/profile:references.usesis the closed-world declaration the linker checks the expression against. - applicability, the classification filter (§3.6).
- verification.method, how conformity is established (§3.6).
- acceptance_criteria, the legacy human-readable form (threshold
type, operator, unit), kept for provenance only.
binds_to+limitare canonical; never author one without the other, because an unbound requirement cannot be re-executed at evaluation and judges nothing.
A richer limit shows the pattern at full strength, the creep
requirement (● same file, creep):
limit:
expression: "ocl{abs(c_c) <= 0.7 * abs(lookupMPE(sample.test_context.d_max, group.classification.accuracy_class, 0.7)) and sample.test_context.d_max >= 0.9 * model.parameters.e_max and sample.test_context.d_max <= model.parameters.e_max}"
uses:
- observable:c_c
- group.parameters.mpe
- group.classification.accuracy_class
- model.parameters.e_max
- sample.test_context.d_max
- formula:lookupMPE
- table:mpe_tiers
Note what the expression does not contain: no tier breakpoints, no MPE numbers. Those live in a table (§3.5). The limit reads the subject through bound paths and reads data through named lookups, nothing else.
3.3 The bind vocabulary
binds_to and form bind: paths share one vocabulary of canonical
aspect paths into the primary tier:
| path shape | binds | R 60 example |
|---|---|---|
model.parameters.<attr> |
model-scope attributes | model.parameters.e_max |
group.parameters.<attr> |
group-scope attributes | group.parameters.mpe, group.parameters.n_lc |
family.parameters.<attr> |
family-scope attributes | family.parameters.p_lc, family.parameters.t_min |
*.classification.<dim> |
dimension membership at its scope | group.classification.accuracy_class, family.classification.humidity_class |
sample.test_context.<attr> |
sample-scope, test-dependent values | sample.test_context.d_max, sample.test_context.v |
model.identity.<slot> |
documentary identity slots (identity.yaml, §2.12) |
model.identity.manufacturer, model.identity.serial_number |
model.aspects.<aspect> |
qualitative aspects (aspects.yaml, §2.12) |
model.aspects.markings, model.aspects.sealing |
model.capabilities.<id> |
declared capabilities | model.capabilities.digital |
model.characteristics.<id> |
declared characteristics | model.characteristics.creep |
model.behaviors.<id> |
declared behaviors | model.behaviors.span-stability |
observable:<symbol> |
test-output quantities (in uses) |
observable:e_l, observable:c_c, observable:c_p |
formula:<id> / table:<id> / profile:<id> |
named calculations and data (in uses) |
formula:lookupMPE, table:mpe_tiers, profile:min_temperature_span |
Scope discipline is enforced: a path must resolve to an attribute
declared at that scope, sample.test_context.e_max is a linker error,
not a warning, because e_max is model-scope. The observable: ids are
the symbols of the characteristics tests compute (symbols.yaml);
binding an observable is how a requirement constrains a test output
without owning the test.
3.4 Constraint vs requirement
Two model kinds carry OCL Booleans in this system, and confusing them corrupts evaluation:
- A Constraint (Module C) is an intrinsic validity rule, an OCL
invover the subject or the test setup. A violation means the situation is malformed. - A Requirement (Module D1) is a regulatory limit. A violation means the instrument is non-conforming.
The classic constraint is test-setup geometry (● ontology-remix/OIML Recommendation Models/Ontology/R 60/oiml-r60-loadcell-profile.yaml ,
constr:r60:fig3-2b):
- id: constr:r60:fig3-2b
kind: test-setup
stereotype: inv
expression: "0.9 * self.E_max <= self.D_max and self.D_max <= self.E_max"
output: { type: Boolean, satisfiedWhen: true }
violationMeaning: "D_max below 90% of capacity or above capacity — test setup invalid."
The violationMeaning is the tell: a violated test-setup constraint
invalidates the run as a test, regardless of results, checked at run
time, not judged at evaluation. The same sentence structure (“D_max shall
not exceed E_max”) appears as both kinds in R 60: as requirement
measuring-range-max (§3.2), where a violation is instrument
non-conformity, and as constraint fig3-2b, where a violation is a void
run. The authoring rule: “the test was set up wrong” → constraint;
“the instrument must be this good” → requirement.
3.5 Tables and profiles: Recommendation data stays data
When the Recommendation hands you a table, model the table, never bake
its numbers into OCL. R 60-1 Table 4 (MPE tiers per accuracy class) is
data in two linked shapes (● data/r60/specification/tables.yaml):
tables:, column-indexed rows with typed columns, supporting the MMEL lookup syntax;profiles:, dimension-keyed bindings for runtime lookup:mpe_tiersbinds per accuracy class the tier list{ min, max?, factor };test_runsbinds 5/5/3/3;temperature_incrementbinds 2/5/5/5;n_LC_range,p_LC_range,min_temperature_spanlikewise.
Expressions reach this data through two declared formula functions
(● data/r60/specification/formulas.yaml): lookupMPE(load, accuracy_class, p_lc), key on class, variable on load, multiplier
p_LC, and the generic lookupProfile('<profile>', <dimension_value>).
Requirement limits call the functions; the functions read the tables; the
tables carry the clause provenance (source: r:60-1:2021, table-4).
Change a tier in a future edition and you edit one data file, no
expression in the package moves.
Two honest-data practices come with this:
- Annotate equivalences, don’t “fix” shapes silently.
mpe_tierstier-3 rows are unbounded above (null); R 60-1 Table 4 bounds them at exactly then_LCclass limits of Table 1, so the shapes are equivalent for any classifiable load cell. The file header says so and keeps the legacy shape. - Record source discrepancies as data. The legacy value model carried
analogue-passive
p_LC0.3–1.0 against R 60-1:2021 §5.3.2’s 0.3–0.8. Thep_LC_rangeprofile keeps the legacy binding with asource_discrepancyblock (summary, sources, resolution, rationale); the canonical limit in/req/metrological/mpeenforces 0.3–0.8. Preserve and annotate; fix at the canonical layer.
3.6 Applicability and verification methods
Applicability is a classification filter, declared per requirement
against the dimension enums: applicability: { humidity_class: [CH] }
on /req/metrological/humidity-ch, [SH] on humidity-sh. The
applicability engine expands these per subject at runtime, a CH-marked
cell gets the CH requirement and never the SH one. Values must exist on
the dimension; the linker rejects typos here because applicability is
where a wrong id silently becomes “requirement never applies”.
verification.method declares how conformity is established, from the
fixed vocabulary definitional | computational | testing | inspection | deferred (● all five in use across data/r60/specification/requirements/):
definitional, satisfied by definition and confirmed at report review (the measuring-range requirements);computational, verified by evaluating the limit over declared and derived values;testing, verified by a conformance test (chapter 4);inspection, verified by examination (markings, documentation);deferred, no single test; assessed through the overall type evaluation (durability: “Assessed through the overall type evaluation process; no single specific test”).
The method is not decoration: it tells the workflow what evidence a
verdict for this requirement may draw on, and it is what makes
“requirement with no test” a finding for testing methods but a
design for deferred ones.
3.7 Acceptance quantities: derived once, referenced everywhere
Some acceptance quantities are real derivations, composite, normalized, clause-specified, and the failure mode to avoid is each layer recomputing them its own way. R 60 lived that failure: the temperature effect on MDLO was computed three ways at three layers (requirement, form, evaluation), differing by normalization and by the v→v_min conversion (the audit’s F1 defect). The discipline that closes it:
- The quantity is declared once in the VerdictQuantity registry
(●
data/r60/specification/verdicts.yaml,mdlo_normalized, R 60-3 §2.1.4):
- id: mdlo_normalized
quantity: { kind: dimensionless }
derive: "ocl{abs(c_m * t_f / delta_t * (d_max - d_min) / (n * v_min))}"
inputs: [c_m, t_f, delta_t, d_max, d_min, "n", v_min]
source: { doc: urn:oiml:pub:r:60-3:2021, clause: "2.1.4" }
- Every consumer references it. The requirement’s limit uses the
acceptspattern instead of restating the derivation (●/req/metrological/temperature-effect-mdlo):
limit:
accepts:
verdict: mdlo_normalized
op: lte
limit: "ocl{p_lc}"
- The linker enforces the one-home rule: every
inputsentry resolves (verdict-inputs-resolve), no consumer re-derives a registered quantity (verdict-no-shadow), and no restated derivation diverges (verdict-restatement). Requirement-level verdict evaluation and form-level calculation evaluate the same parsed derivation, cached once per standard load.
The outcome limit has exactly one home, the requirement, or the registry when the derivation is shared. Everything else is a reference.
3.8 Grammar sketch (illustrative v3 syntax)
requirement /req/metrological/creep {
is {
statement "The difference between the reading taken upon the
application of a maximum load (D_max) and … shall not exceed
0.7 times the absolute value of MPE for the applied load."
source "urn:oiml:pub:r:60-1:2021#clause-5.5.1"
modality shall
}
has {
binds_to [ group.parameters.mpe, model.parameters.e_max,
sample.test_context.d_max ]
limit ocl{
abs(c_c) <= 0.7 * abs(lookupMPE(sample.test_context.d_max,
group.classification.accuracy_class, 0.7))
and sample.test_context.d_max >= 0.9 * model.parameters.e_max
and sample.test_context.d_max <= model.parameters.e_max }
uses [ observable:c_c, group.parameters.mpe,
group.classification.accuracy_class,
model.parameters.e_max, sample.test_context.d_max,
formula:lookupMPE, table:mpe_tiers ]
applicability { } # all classes
}
does {
verification { method testing } # → /conf/metrological-tests/creep
}
}
requirement /req/metrological/temperature-effect-mdlo {
has {
limit accepts { verdict mdlo_normalized op lte limit ocl{p_lc} }
uses [ observable:c_m, observable:delta_t, profile:temperature_increment,
family.parameters.p_lc, group.parameters.v_min, … ]
}
does { verification { method testing } }
}
constraint fig3_2b on LoadCell { # Module C — validity, not a limit
inv ocl{ 0.9 * self.E_max <= self.D_max and self.D_max <= self.E_max }
violationMeaning "D_max below 90 % of capacity or above capacity —
test setup invalid."
}
3.9 Validation rules
The linker and primmel check enforce:
- every requirement carries
statement, clausereference,binds_to, OCLlimit+uses,applicability, andverification.method;acceptance_criteriaalone never satisfies the binding requirement; - every
binds_to/usespath resolves to a declared attribute at a scope-appropriate level; everyobservable:id resolves insymbols.yaml; everyformula:/table:/profile:reference resolves informulas.yaml/tables.yaml; - every identifier read by a limit expression appears in
uses, and everyusesentry is read (closed-world both directions); - every
applicabilityvalue is a declared enum value of its dimension; - every
limit.accepts.verdictresolves inverdicts.yaml, and no consumer shadows or divergently restates a registered VerdictQuantity; - no tier breakpoint, MPE number, or profile value appears inside an OCL
expression, data lives in tables, expressions read data through named
lookups. Clause-fixed constants are exempt: they are part of the
limit, not table data (the creep clause’s own
0.7, R 60-1 §5.5.1, is authored in the expression, never inmpe_tiers).
3.10 Summary
- A requirement is a constraint over primary aspect paths: statement +
clause reference +
binds_to+ OCLlimitwith closed-worlduses+applicability+verification.method. It binds; it never restates. - The bind vocabulary is small and canonical:
*.parameters.<attr>,*.classification.<dim>,sample.test_context.<attr>, plusobservable:/formula:/table:/profile:references inuses. - Constraints say “the test was set up wrong” (OCL
inv,violationMeaning, void run); requirements say “the instrument must be this good” (limit, verdict). The same English sentence can be both , model it twice, once per kind. - Recommendation tables and profiles are data with clause provenance,
read through
lookupMPE/lookupProfile; OCL never contains their numbers. Discrepancies are preserved and annotated, fixed only at the canonical layer. - Acceptance quantities are derived once in the VerdictQuantity registry
and referenced via
limit.acceptseverywhere, one home, one parsed derivation, all consumers agreeing by construction.
Next: Chapter 4, Conformance Tests: the operations that put these requirements on trial, variables, steps, conditions, acceptance criteria, and class inheritance.