On this page:
11.1 Required entries, defaults, and optional entries
11.1.1 Value kinds and unknown defaults
11.1.2 Reusing an interface for a field
11.1.3 Unknown defaults with named interfaces
11.1.4 Constraints on optional fields
11.2 Requirements on values
11.3 Declaration forms
11.4 Nested protocol parts
11.5 Conditional requirements
11.6 Requirements for every item in a list
11.7 Record interfaces
11.8 Extend and combine record interfaces
11.9 Workflow-part interfaces
9.3

11 Records and interfaces🔗ℹ

An interface describes the fields of a structured data object, called a record, or the named parts a workflow may provide. Both use must [...] to identify required entries. A record check treats the entries as fields; a workflow implementation declaration treats them as named workflow parts. The reader accepts must [...] in workflows, libraries, and separate interface files. Assessment support explains the reference structural checks.

11.1 Required entries, defaults, and optional entries🔗ℹ

Present required entries together inside must [...], including entries with defaults:

Compact

interface Timing [

  must [duration unit = "seconds"]

  notes

]

Verbose

interface Timing [

  must [duration set unit to "seconds"]

  notes

]

duration and unit must both be present. When constructing a record, supply duration; the interface supplies "seconds" for unit unless another value is provided. notes may be absent. The concrete default makes unit a text field; "minutes" is an allowed replacement. Required fields reject unknown by default, including overrides of a supplied default.

Entry

Meaning

must [duration unit]

Both fields are required; neither has a default

must [duration unit = "seconds"]

Both fields are required; unit has an overridable default

notes

Optional; may be absent

notes is text

Optional; checks supplied values as text

must [notes is text]

Required; checks the supplied value as text

11.1.1 Value kinds and unknown defaults🔗ℹ

An interface can require a number, text, boolean, list, or record. A record is an object with named fields, such as [period = 2 unit = "seconds"].

A concrete default also declares the field’s kind. Use these forms:

Declaration

Meaning

must [period is number]

Number required; no default

must [period = 2]

Number required; default 2

must [period = unknown number]

Number or explicit unknown; default unknown

must [timing = unknown Timing]

Object matching Timing or explicit unknown; default unknown

must [period = unknown]

No kind restriction; default unknown

The suffix after unknown can use any of the five kinds or a declared interface reference. For example, must [measurements = unknown list] permits a list or unknown. A concrete list or record default constrains the outer kind; requirements on its items or fields are declared separately. An attached u description does not change the underlying kind.

The field remains required. Construction fills an omitted default; checking an existing record leaves it unchanged and still reports an absent field. The permission follows the field through inheritance and library imports. Redeclaring a field replaces its default, kind, and permission. The runnable example shows a supplied period and a period explicitly allowed to be unknown. The value-kind example uses a numeric requirement for measured periods and an unknown numeric default for planned periods.

Kind checks apply during construction and interface checks. A later value update can be checked against the interface again. If a check cannot establish the default’s kind or the supplied value, it remains undetermined. Ordinary variables do not acquire permanent kind restrictions.

value is kind also works in expressions, such as if period is number [...]. On a known value it returns true or false; on unknown it remains unknown. A permitted unknown therefore leaves an additional period is number condition undetermined. The declaration period = unknown number directly allows that unknown field value.

A required list or record can contain unknown entries; requirements on those entries are checked separately. Optional fields can still be absent or contain unknown. A permitted unknown value does not establish an additional condition such as period > 0; that condition remains undetermined. A value the structural checker cannot resolve is also undetermined, rather than being treated as an explicitly supplied unknown. Equality can directly test the explicit marker: period == unknown is true when period contains unknown; period != unknown tests the opposite. These expressions also work in interface conditions. They do not replace the field’s declaration of permitted values.

must applies to every entry inside its brackets, whether they share a line or use separate lines. A field with a default is compulsory even if it is written outside must [...]; grouping it inside makes that meaning explicit and is the presentation used in this manual. Only an entry with neither must nor a default is optional. These rules are shared by data interfaces and interfaces describing workflow parts. The interface specification defines these declarations, constraints, and checks.

11.1.2 Reusing an interface for a field🔗ℹ

Use an interface name after is to check the fields of a nested object:

Compact

interface Timing [

  must [period is number unit = "seconds"]

]

 

interface Experiment [

  must [timing is Timing]

]

 

timing = Timing.[period = 2]

experiment = Experiment.[timing = timing]

experiment implement Experiment

Verbose

interface Timing [

  must [period is a number set unit to "seconds"]

]

 

interface Experiment [

  must [timing is a Timing]

]

 

set timing to Timing with [set period to 2]

set experiment to Experiment with [set timing to timing]

experiment implements Experiment

The timing field is required and must satisfy Timing, including its required fields, value conditions, and any nested or inherited requirements. Extra fields are allowed. The nested object can have been created directly with named fields; it need not have been constructed from Timing.

The test supplies no default and does not change its operand. Timing.[period = 2] inserts the default unit during construction. By contrast, [period = 2] is Timing is false, because the required unit field is missing. [period = 2 unit = "minutes"] is Timing is true: "seconds" is an overridable default.

The same test works in expressions, such as if timing is Timing [...], and in conditional or per-item interface requirements. The target may be defined later, loaded through include, imported as timing-tools.Timing, or be a named nested group such as Protocol.documentation. A misspelled target is a reader error.

An unknown whole object gives unknown. A missing required field, a wrong value kind, or a false requirement gives false. If no failure is established but some checks remain unresolved, the answer is unknown. The target interface’s existing unknown permissions apply to its fields. Recursive interfaces can describe finite nested objects; a circular test with no independent answer remains undetermined.

The runnable example constructs a timing object and reuses its interface in an experiment.

11.1.3 Unknown defaults with named interfaces🔗ℹ

Use field = unknown Interface to supply and permit an unknown value while checking supplied objects against an interface:

Compact

interface Timing [

  must [period is number unit = "seconds"]

]

 

interface Experiment [

  must [timing = unknown Timing]

]

 

experiment = Experiment.[]

experiment.timing = Timing.[period = 2]

experiment implement Experiment

Verbose

interface Timing [

  must [period is a number set unit to "seconds"]

]

 

interface Experiment [

  must [set timing to unknown Timing]

]

 

set experiment to Experiment with []

set timing of experiment to Timing with [set period to 2]

experiment implements Experiment

The timing field is compulsory. Construction supplies unknown when it is omitted. An existing record must contain the field, and its value must be either unknown or an object satisfying Timing. The target interface’s own field and value rules apply to supplied objects. Checking an object does not insert its missing defaults: supplying [period = 2] fails this interface because unit is absent.

The target may be declared later, included, imported as timing-tools.Timing, or name a nested group such as Protocol.timing. Its name is unquoted. A following bare word is treated as a named suffix when it identifies a declared interface. Other names retain their ordinary field meaning. To declare a separate field with the same name as an interface after an unknown default, use a separate must [...] group or put that field earlier.

A further condition keeps its own meaning. For example, adding must [timing is Timing] leaves an explicitly unknown timing undetermined, even though its default declaration permits unknown. See the runnable example.

11.1.4 Constraints on optional fields🔗ℹ

Outside must [...], field is kind leaves the field optional:

Compact

interface Timing [

  must [period is number]

  notes is text

]

 

trial = Timing.[period = 2]

trial.notes = "Timed by hand"

trial implement Timing

Verbose

interface Timing [

  must [period is a number]

  notes is a text

]

 

set trial to Timing with [set period to 2]

set notes of trial to "Timed by hand"

trial implements Timing

The constructor leaves notes absent until it is supplied. Once present, its value is checked as text. A number in notes violates the constraint. An optional constraint supplies no default. Fields with defaults remain compulsory under the ordinary declaration rule.

The target can also be a named interface: review is Review checks a supplied review object against Review. Local, included, imported, and nested interface references use the same rules as required is tests. The optional form works in nested groups, conditional branches, and for each declarations, such as item.notes is text. Inheritance preserves the constraint; redeclaring the field replaces its declaration.

An absent field is skipped. A supplied unknown, or a value the checker cannot establish, leaves the constraint undetermined. A constructor reports that unresolved check. A plain record can retain the value for inspection. An unconstrained optional field, written simply notes, can still contain unknown without a kind check.

The runnable example uses an optional text field and an optional object constrained by an interface.

11.2 Requirements on values🔗ℹ

A must [...] group can mix conditions and required entries:

Compact

interface Timing-trial [

  must [swing-count > 10 swing-height unit == "seconds"]

]

Verbose

interface Timing-trial [

  must [swing-count is greater than 10 swing-height unit equals "seconds"]

]

This requires swing-count to be greater than 10, swing-height to be present, and unit to equal "seconds". The entries referenced by a condition must be present and reject unknown by default. swing-height = unknown therefore violates this interface. Declare must [swing-height = unknown] to permit that value and provide it as a default. A comparison using a permitted unknown can remain undetermined.

Use the existing arithmetic, comparison, and Boolean expressions:

Compact

must [swing-count > 10 and swing-count < 100 swing-height]

Verbose

must [swing-count is greater than 10 and swing-count is less than 100 swing-height]

The first expression is one condition; swing-height is the next entry. Names refer to entries of the surrounding interface part. Existing entries and defaults are reused; conditions do not require duplicate declarations. Dotted paths access nested values. Conditions can be nested under if, and inheritance preserves them.

Form

Meaning

must [unit = "seconds"]

Supplies an overridable default

must [unit == "seconds"]

Requires that exact value; supplies no default

== is the equality comparison throughout the language. Assignments, record entries, and defaults use =. Construction fills applicable defaults, then checks applicable requirements. A false requirement fails; an unresolved value requirement is reported as undetermined. The runnable value-requirement example constructs and checks a timing trial. Assessment support describes the reference structural checker.

Use in to require one of several allowed values:

Compact

interface Timing [

  must [method in ["manual" "video"]]

]

Verbose

interface Timing [

  must [is method in ["manual" "video"]]

]

This requires method to equal "manual" or "video"; it supplies no default. A named list is also possible. As with other interface expressions, its name refers to a field of the surrounding interface part:

Compact

must [methods = ["manual" "video"] method in methods]

Verbose

must [set methods to ["manual" "video"] is method in methods]

Construction supplies the methods default; checking an existing record requires that field to be present. Membership uses the same rules in conditional branches, nested parts, and for each requirements. Required fields still reject unknown unless explicitly permitted. The marker can match a list item: unknown in [unknown] is true, while unknown in ["manual" "video"] is false. An unknown list or values the checker cannot establish can leave membership undetermined.

The same in checks field presence when its right operand is a record:

Compact

interface Trial [

  details [notes]

  if notes in details [must [reviewer]]

]

Verbose

interface Trial [

  details [notes]

  if is notes in details then [must [reviewer]]

]

Here notes is an unquoted field name in details, not a separate entry in Trial. The optional field stays optional. If it is present, even with value unknown, the branch requires reviewer. must [notes in details] instead requires that field to be present; the presence test alone does not constrain its value. Values and expressions gives the expression rules.

11.3 Declaration forms🔗ℹ

Form

Purpose

interface Name [must [required-field defaulted-field = value] optional-field]

Declare required fields, their defaults, and optional fields

extends Parent

Inherit fields from a local or imported record interface

field is kind-or-interface

Outside must, check the field only when supplied

interface Name [version "..." must [name ...] optional-name affects source target ...]

Declare required and optional workflow parts in a separate file

An interface may have one nonempty version line or omit it. Local and imported interfaces may have extends lines. Interfaces describing workflow parts use the same required-entry brackets and bare optional names. An affects source target line links two required entries. Separate interface files cannot extend local interfaces.

11.4 Nested protocol parts🔗ℹ

A name followed by brackets declares a part containing its own requirements. The pendulum protocol example uses the same must [...] rule at each level:

interface Pendulum-protocol [

  version "1"

  must [

    measurement

    documentation [

      must [uncertainty]

      notes

    ]

  ]

  additional-measurements

]

measurement and documentation are required. Within documentation, uncertainty is required and notes is optional. additional-measurements is optional at the protocol level. A default on an entry makes that entry compulsory within its parent, as with other interface entries.

Dots reference the hierarchy: Pendulum-protocol.documentation.uncertainty identifies the uncertainty part. Names are unique within their parent; different parts can use the same child name. The interface version covers the full hierarchy.

A mapping to a parent also claims its required children. For example, "Report" identifies a stage declared in the workflow:

Compact

Report implement Pendulum-protocol.documentation

Verbose

Report implements Pendulum-protocol.documentation

This also claims documentation.uncertainty. The child can instead be referenced directly:

Compact

information.period.u implement Pendulum-protocol.documentation.uncertainty

Verbose

information.period.u implements Pendulum-protocol.documentation.uncertainty

The second line belongs inside a state stage where information.period.u is available. It maps that uncertainty description to the specific requirement. Mapping one child does not claim its siblings. Optional nested parts remain optional when their parent is mapped. When an optional part is mapped, its own required children apply. These declarations identify work and data for inspection; they do not establish scientific conformity.

Use implement directly, without a must prefix. An unquoted stage name, a procedure name, or a value path can appear on its left. On its right, use the interface name and dotted path, including the existing library alias when imported, such as prot.Pendulum-protocol.documentation. A stage or procedure may reference the whole interface. Several workflow parts can map to one requirement, and one part can map to several requirements. See Assessment support for a complete example and the checks available.

Named blocks also describe nested data fields. A nested part can be used with the existing construction and record-check forms:

Compact

details = Pendulum-protocol.documentation.[uncertainty = [estimate = unknown]]

details implement Pendulum-protocol.documentation

Verbose

set details to Pendulum-protocol.documentation with [set uncertainty to [set estimate to unknown]]

details implements Pendulum-protocol.documentation

The reader preserves the dotted names, each entry’s requiredness, and parent links for tools inspecting the protocol. version and extends belong to the interface declaration; named parts contain entries and their must [...] groups. An affects link inside a part uses names relative to that part.

11.5 Conditional requirements🔗ℹ

Interfaces use the same if, else if, and else forms as ordinary statements. The conditional interface example declares different requirements for three timing methods:

Compact

interface Timing-protocol [

  version "1"

  must [method]

 

  if method == "automatic" [

    must [instrument unit = "seconds"]

  ] else if method == "video" [

    must [frame-rate]

  ] else [

    must [observer]

  ]

]

Verbose

interface Timing-protocol [

  version "1"

  must [method]

 

  if method equals "automatic" then [

    must [instrument set unit to "seconds"]

  ] else if method equals "video" then [

    must [frame-rate]

  ] else [

    must [observer]

  ]

]

Timing method

Required entries

"automatic"

method, instrument, and unit (default: seconds)

"video"

method and frame-rate

Any other known value

method and observer

Each condition uses the existing comparisons and Boolean operators. else if and else apply when all earlier conditions are false; either can be omitted. There is no separate elseif form. Within a named part, names refer to that part’s entries. Dotted paths keep their usual meaning. Conditions may refer to entries declared later or inherited from another interface.

The normal entry rules apply inside each branch. Defaults apply only in an active branch. Optional entries stay outside must [...], without a default. Entries in an inactive branch may still be supplied as additional fields. Entry names remain unique in their surrounding named part, including across conditional branches. Further conditionals can be nested; version and extends stay at interface level.

Construct records with the existing syntax:

Compact

automatic = Timing-protocol.[method = "automatic" instrument = "timer-1"]

video = Timing-protocol.[method = "video" frame-rate = 25]

manual = Timing-protocol.[method = "manual" observer = "researcher"]

Verbose

set automatic to Timing-protocol with [set method to "automatic" set instrument to "timer-1"]

set video to Timing-protocol with [set method to "video" set frame-rate to 25]

set manual to Timing-protocol with [set method to "manual" set observer to "researcher"]

automatic.unit is "seconds". The other records receive no unit default from the inactive branch. Construction checks the requirements of the applicable branch. To allow an unknown method, declare must [method = unknown]. If an omitted required field depends on an unknown condition, construction reports an undetermined conditional requirement. Plain records can retain unknown values for inspection; the structural check reports unresolved requirements as undetermined. An equality comparison with an explicit unknown is resolved: for example, method == "automatic" is false when method is unknown. Use if method == unknown [...] to state requirements for that case. The unknown-equality example requires an explanation when a period is unknown and a positive number otherwise.

For a workflow, the existing implement form connects a value to the interface entry used by a condition:

Compact

information.timing-method implement Timing-protocol.method

Verbose

information.timing-method implements Timing-protocol.method

The reader preserves the condition and mappings. The reference mapping checker resolves literal conditions; conditions depending on mapped workflow values remain undetermined when required mappings are absent. Other applications can inspect those values and conditions to assess conformity.

11.6 Requirements for every item in a list🔗ℹ

Use for each inside an interface to describe every item in a list:

interface Timing-series [

  must [measurements]

 

  for each measurement in measurements [

    must [measurement.period measurement.period.u]

  ]

]

The interface requires a measurements list. Each item must have a period field and an attached uncertainty description accessible through period.u. These are the requirements of this example protocol. The block describes the items; it does not perform measurements. The runnable example constructs and checks a series with three measurements, including a minimum count requirement.

The name measurement refers to one item and is local to the block. Use its dotted paths for entries and the existing expressions for conditions:

Compact

for each measurement in measurements [

  must [measurement.swing-count > 10 measurement.unit == "seconds"]

]

Verbose

for each measurement in measurements [

  must [swing-count of measurement is greater than 10 unit of measurement equals "seconds"]

]

Entry declarations begin with the item name. They use the same required, optional, and default rules as other interface entries. Conditions may also read entries declared in the surrounding interface part. if, else if, else, and further for each blocks can appear inside the block. Nested loops can refer to their enclosing item names. Scalar lists can use the item name directly, as in for each count in counts [must [count > 10]].

To require a minimum number of measurements as well as their individual fields, use the list’s reserved .count property:

Compact

interface Timing-series [

  must [measurements.count >= 3]

 

  for each measurement in measurements [

    must [measurement.period measurement.period.u]

  ]

]

Verbose

interface Timing-series [

  must [count of measurements is at least 3]

 

  for each measurement in measurements [

    must [measurement.period measurement.period.u]

  ]

]

This requires at least three items. must [measurements.count == 3] requires exactly three. The count is computed from the list; it is not a separate field the author supplies. An unknown item value still occupies one position. An explicitly unknown list is rejected by default. Declare must [measurements = unknown] to permit it; its count requirement then remains undetermined.

Written collection

Check

Known list

Checks every item; any known violation makes the requirement violated

[]

Per-item requirements are satisfied; a separate minimum count can still be violated

unknown

Rejected by default; unresolved checks are undetermined when the collection permits unknown

Missing collection or a known value that is not a list

Violated when the block applies

A missing item field identifies its position, such as measurements.[2].period.u. An unknown value can leave a condition undetermined when the field permits unknown. Required item fields otherwise reject it by default. The existence of period.u does not establish the adequacy of the uncertainty description.

Construction fills applicable defaults in referenced list items. For example, must [measurement.unit = "seconds"] supplies each item’s unit unless overridden. Checking an existing record leaves it unchanged. The interface specification describes collection locations and default completion. Inheritance and library imports preserve the whole declaration. The workflow model retains the collection, local name, conditions, nesting, and source locations for applications to inspect. A workflow mapping alone does not establish the values of its list items.

11.7 Record interfaces🔗ℹ

A data interface names fields. Required fields, including those with defaults, must be present in the completed record. Optional fields may be absent, and extra fields are allowed. The timing record example is a runnable workflow:

Compact

#lang sciencelogo

 

workflow "Check timing records"

interface Timing [must [duration unit = "seconds"]]

trial = Timing.[duration = 2]

trial implement Timing

revised = trial.[unit = "minutes"]

revised implement Timing

revised implement "interfaces/timing.rkt"

Verbose

#lang sciencelogo

 

workflow "Check timing records"

interface Timing [must [duration set unit to "seconds"]]

set trial to Timing with [set duration to 2]

trial implements Timing

set revised to trial with [set unit to "minutes"]

revised implements Timing

revised implements "interfaces/timing.rkt"

Timing.[duration = 2] creates a record with unit = "seconds". Construction fails if a required field remains absent after applying defaults. On the right side of an assignment, trial.[unit = "minutes"] produces a modified value for revised; trial retains its earlier value. The existing trial can also be updated:

Compact

trial += [unit = "minutes" note = "hand timed"]

trial.duration += 2

Verbose

update trial with [set unit to "minutes" set note to "hand timed"]

update duration of trial with 2

After construction, += can replace unit, add note, or add to the existing numeric duration. Extra fields remain allowed.

A literal record can satisfy the same interface even when it was not constructed from Timing:

Compact

direct = [duration = 2 unit = "seconds"]

direct implement Timing

Verbose

set direct to [set duration to 2 set unit to "seconds"]

direct implements Timing

duration = unknown would violate this interface. Declaring must [duration = unknown unit = "seconds"] explicitly permits an unknown duration and supplies it as a default. The permission does not establish a scientific value for it. The implement check is declarative: it examines the written record shape and does not run the workflow. A direct record assignment or a dotted update has a known shape. A record returned by a procedure, or one possibly changed by a conditional or loop, is reported as undetermined. The check itself is described in Assessment support.

The same interface can be a separate #lang sciencelogo file. In this example, revised implement "interfaces/timing.rkt" checks against that file; the path is relative to the workflow file. The assessor records the source revision hash even when the optional version is omitted. The standalone form checks a record; local declarations supply a name usable in construction. A stage or procedure reference uses the same implement word to map workflow parts. A value mapped to an interface or nested group is checked for required fields; a value mapped to an individual requirement identifies the data addressing that requirement.

11.8 Extend and combine record interfaces🔗ℹ

extends Parent inherits a record interface. Repeating it combines several parents. The combined interface example runs and passes the assessor:

Compact

workflow "Describe a pendulum trial"

interface Timed-observation [

  extends Timing

  extends Location

  must [observation unit = "minutes"]

]

interface Timing [must [duration unit = "seconds"]]

interface Location [must [place]]

 

trial = Timed-observation.[

  duration = 2

  place = "lab"

  observation = "ten swings"

]

trial implement Timed-observation

trial implement Timing

trial implement Location

Verbose

workflow "Describe a pendulum trial"

interface Timed-observation [

  extends Timing

  extends Location

  must [observation set unit to "minutes"]

]

interface Timing [must [duration set unit to "seconds"]]

interface Location [must [place]]

 

set trial to Timed-observation with [

  set duration to 2

  set place to "lab"

  set observation to "ten swings"

]

trial implements Timed-observation

trial implements Timing

trial implements Location

The parent interfaces may be declared after the interface that extends them. Timed-observation requires duration, place, and observation; its own unit = "minutes" replaces the Timing default. A child may also replace an inherited default with a required field without a default, written inside must [...]. Identical field declarations from different parents merge. If parents define the same field differently, the child must declare that field explicitly to resolve the conflict. Unknown parents and extension cycles are reader errors. Construction checks all inherited required fields, and implement can check a resulting record against the combined interface or any of its parents by field presence. The same check follows nested groups. Unknown nested contents are reported as undetermined; an optional group that is absent remains optional. If every required field has a default, Combined.[] constructs a record using those defaults. An interface may also declare required nested fields, including defaults, as must [clock.time clock.unit = "seconds"]. These are paths through a record, with the same dot meaning used to read and update its values. An inherited interface may be declared later in the same workflow, in an included workflow file, or imported from a library. Importing a library as timing makes its Timing record interface available as timing.Timing; write extends timing.Timing in a local interface and trial implement timing.Timing to check a record against it. A library can itself extend an interface imported from another library. Its dependency alias remains internal, so a workflow imports that dependency directly if it needs to name the interface.

11.9 Workflow-part interfaces🔗ℹ

A workflow-part interface uses the same declaration in a workflow, library, or separate #lang sciencelogo file. Its must [...] group names parts that must be provided. Bare names outside that group name parts that may be provided. An omitted optional part is not a missing requirement. affects source target marks a possible downstream effect if a required part is missing. A version line can identify the interface, but the assessor does not compare versions.

The assessor interface is a separate #lang sciencelogo file. It has one version and five required parts:

Compact

#lang sciencelogo

 

interface Assessor-process [

  version "0.1"

  must [

    parse

    resolve-libraries

    check-interfaces

    trace-impacts

    report

  ]

 

  affects parse check-interfaces

  affects resolve-libraries check-interfaces

  affects check-interfaces trace-impacts

  affects trace-impacts report

]

Verbose

#lang sciencelogo

 

interface Assessor-process [

  version "0.1"

  must [

    parse

    resolve-libraries

    check-interfaces

    trace-impacts

    report

  ]

 

  parse affects check-interfaces

  resolve-libraries affects check-interfaces

  check-interfaces affects trace-impacts

  trace-impacts affects report

]

The example workflow that supplies these parts is explained in Assessment support. These five parts belong to the example interface; they are not built-in ScienceLogo parts.

For example, an interface can require measurement and allow supplementary notes:

interface Pendulum-recording [

  version "1"

  must [measurement]

  supplementary-notes

]

A workflow may map a part to supplementary-notes, but it does not have to. The same required-entry rule applies when an interface describes data fields: a bare name without a default is optional.