Metanorma: Aequitate Verum

Metanorma machine-readable requirements ("MRR") requirements model scheme

General

Metanorma machine-readable requirements ("MRR") is a generic requirements model scheme developed according to the needs of NIST and ITU with a focus on machine-readability.

This document describes the models provided by the MRR scheme and their usage.

Understanding MRR

The major benefit of MRR, in comparison with other requirements model schemes, is its focus on making requirements machine-readable and executable.

Many standards and specifications today are meant for encoding data and behavioral requirements intended for machines or software. Instead of needing human intervention or re-interpretation of these requirements for machines, it is possible to streamline the semantics between the specification of requirements and the machine usage of such requirements.

MRR was originally announced at the ISO/TMB/SAG_MRS ("Special Advisory Group for Machine-Readable Standards") in 2019, and placed into production the same year.

Note
The Multi-Modal Modelling Language ("MMEL"), a core component of the BSI SMART program supported by the Ministry of Defense, UK, is implemented as a superset of MRR.

Use cases supported by MRR include:

  • representation of a requirements collection or a requirements graph of a coherent set of compliance criteria;

  • automated validation of the consistency of a set of requirements;

  • automated execution of automated processing steps as specified by as requirements;

  • automated compliance checks against machine-readable verification tests.

The architecture of MRR is described in the MRR model diagram.

MRR provides:

  • Two core classes:

    • Provision

    • ProvisionPart

  • Three models that can be instantiated:

    • Requirement

    • Recommendation

    • Permission

The three instantiable models provide the basis for encoding machine-readable requirements. The only difference between these three models is the obligation, which binds the subject to a different strength in terms of compliance.

One aspect that MRR differs from other requirements model schemes is that it relies on "components" to differentiate roles of provisions. (see Components for details). Components may be targeted towards human- or machine-readability.

Instances

Instance syntax

The method of encoding an MRR model follows the general syntax described in requirements.

The encoding syntax is as follows, where the block definition describes the type of the model.

Example 1. Encoding an MRR permission
[permission]
====
This is the permission statement.
====
Note
Additional examples of MRR encodings are available at metanorma-mrr-samples.

When using MRR within other documents that, by default, uses another requirements model scheme, it is necessary specify the instance with the model attribute.

Example 2. Encoding an MRR instance within a document that uses another requirements model scheme
[requirement,model=mrr]
====
This is an MRR requirement
====

Instance attributes

An MRR model instance is encoded with one of these block types:

  • [requirement] for Requirement

  • [recommendation] for Recommendation

  • [permission] for Permission

All instantiable models in MRR share the same set of attributes.

The following attributes are supported:

model

(optional) The requirement model scheme that applies to the instance. (default: basic)

type

(optional) The model of the instance, typically not necessary given the type has been specified at the block level (e.g. permission).

identifier

The identifier assigned to an instance. Identifiers can be simple strings, and are often entered as URIs or URNs. If present, it will be rendered in final output. [added in https://github.com/metanorma/metanorma-standoc/releases/tag/v2.2.0]

Note
identifier was previously called label.
classification

May be used to give an arbitrary number of key-value pairs of tags describing the instance. Key and value are separated by a colon, multiple values are delimited by comma, and key-value pairs are delimited by semicolon. Both key and value are expected to be tokens containing no punctuation.

obligation

(optional) Modality of the instance, as in the strength to which it pertains to compliance. Can contain one or more of requirement, permission, recommendation, comma-delimited. Using this attribute will override the obligation of the requirement.

inherit

May be used to reference the label of a requirement or definition that is imported or presupposed by this requirement. Can contain multiple semicolon-delimited identifiers. [added in https://github.com/metanorma/metanorma-standoc/releases/tag/v1.3.14].

Multiple instances of inherit can also be expressed with the inherit command, which can contain markup including cross-references [added in https://github.com/metanorma/metanorma-standoc/releases/tag/v1.3.21].

inherit:[<<ref1>>]
class

Declares a custom category of provisions labelled and numbered separately to "requirements", "recommendations" and "permissions" [added in https://github.com/metanorma/mn-requirements/releases/tag/v0.4.1].

Example 3. Rendering of a custom category called "Provision"
[requirement]
--
[%metadata]
class:: Provision
--

[requirement]
--
--

[requirement]
--
[%metadata]
class:: Provision
--

Rendered as:

Provision 1

Requirement 1

Provision 2

Any attributes that are not included in the list of requirement attributes above are treated as "classification tags". [added in https://github.com/metanorma/metanorma-standoc/releases/tag/v2.2.0]

Components

Component types

Components are a core part of how to represent content within MRR instances.

The recognized component types are:

  • Specification: specification

  • Measurement target: measurement-target (for quantitative requirements)

  • Verification steps: verification (verification steps for the requirement)

  • Behavioral interfaces (code stubs): import

  • Undifferentiated components: component [added in https://github.com/metanorma/metanorma-standoc/releases/tag/v1.10.4]

Components of a requirement can be encoded in order to make it machine-readable in Metanorma normative outputs, although this is not expected to be reflected in renderings.

Component syntax

Components are encoded within an MRR instance using named blocks. Each block needs to be named with the kind of component it contains as a role attribute.

A component block is encoded using the following mechanisms:

Any text not wrapped in a named block is considered to be part of the description of the outermost MRR instance (e.g. a requirement).

Example 4. An example of an instance with four components
[requirement]
====
[specification]
--
This is a formal specification
--

[measurement-target]
=====
This is a measurement target
=====

[verification]
--
This is a verification step
--

[import]
--
This is a code stub
--

====

Component types

Specification

A specification is a formal statement that describes the object of the requirement.

The specification component is identified by the specification type.

Example 5. An MRR requirement containing a specification statement
[requirement]
====

[specification]
--
An identifier shall be unique.
--
====

Specifications can be described with machine-readable content. These components can be specified with the classification of type:{specification-type}.

In the following example, an OpenAPI specification is used directly to specify requirements on the subject.

Example 6. An MRR requirement containing a machine-readable specification (OGC OpenAPI)
[requirement]
====
[%metadata]
identifier:: /openapi/3.0/
classification:: type:openapi

[specification]
--
[source,yaml]
----
 include::openapi.yaml[]
----
--
====
Measurement target

A measurement target indicates the target that a measurement is to be taken from, in order to express quantitative requirements.

The measurement target component is identified by the measurement-target type.

Example 7. An MRR requirement containing a measurement target
[requirement]
====

[measurement-target]
--
The value for stem:[alpha] shall be within 0.1 and 0.3.
--
====
Verification steps

A verification component provides verification steps for the MRR instance. This is typically a set of sequential steps that verifies compliance towards the instance.

The measurement target component is identified by the verification type, with contents encoded as an ordered list.

Example 8. An MRR requirement containing verification steps (SS 584:2020)
[requirement]
====
[%metadata]
identifier:: /ss/584/2015/level/1
subject:: The Cloud Service Provider's management and board of directors
classification:: type:text

[specification]
--
. Managing information security risks related to people, process, technology and
  governance.
. Oversight of the effective implementation of the technology controls.
. Oversight of risk management practices.
--

[verification]
--
. Determine that the responsibilities of management and board of directors in
  managing and overseeing information security risks are documented and
  communicated.
. Inspect documents such as meeting minutes and committee charter to identify
  the participants involved in the meeting or committee, their respective job
  functions and the reporting relationship.
. Determine whether the management and board of directors meet regularly, at an
  appropriate and monitored frequency.
. Determine whether the information security function is headed by a Chief
  Information Security Officer (CISO) or similar function.
--
====
Behavioral interfaces

A behavioral interface specifies compliance conditions of the target subject, by specifying the desired behavior of the subject.

A behavioral interface can be specified with a mix of human-readable and machine-readable content.

The behavioral interface component is specified with the import type.

Depending on the language used within the import block, different attributes are available.

Note
The term "interface" originates from its meaning from programming languages, and can be considered a way of entering "acceptance tests".
Example 9. Example of specifying a behavioral interface with mixed human- and machine-readable content (NIST SP 800-90B)
.Generic Structure for Permutation Testing
[requirement]
====
[%metadata]
identifier:: /iid-testing/permutation-test/

[description]
--
Input:: stem:[S = (s_1, ... s_L)]
Output:: Decision on the IID assumption
--

[verification]
--
. For each test stem:[i]
.. Assign the counters stem:[C_(i, 0)] and stem:[C_(i, 1)] to zero.
.. Calculate the test statistic stem:[T_(i)] on stem:[S].

. For stem:[j = 1] to 10 000
.. Permute stem:[S] using the Fisher-Yates shuffle algorithm.
.. For each test stem:[i]
... Calculate the test statistic stem:[T] on the permuted data.
... If (stem:[T > T_(i)]), increment stem:[C_(i, 0)]. If (stem:[T = T_(i)]),
    increment stem:[C_(i, 1)].

. If ( (stem:[C_(i, 0) + C_(i, 1) <= 5]) or (stem:[C_(i, 0) >= 9995]) ) for any
  stem:[i], reject the IID assumption; else, assume that the noise source
  outputs are IID.
--

[import, type="pseudo-fortress", run="DecideIID"]
----
import FisherYatesShuffle, TestStatistic

DecideIID(S: ZZ[], L: RR) : Boolean =
  for i <- 1 : L do
    C[i, 0] <- 0, C[i, 1] <- 0
    T[i] <- TestStatistic(S)
  end

  for j <- 1 : 10000 do
    S' <- FisherYatesShuffle(S)
    for i <- 1: L do
      T <- TestStatistic(S')

      if T' > T'[i]
        C[i, 0] <- C[i, 0] + 1
      end

      if T' == T[i]
        C[i, 1] <- C[i, 1] + 1
      end
    end
  end

  for i <- 1 : L do
    if (C[i, 0] + C[i, 1] <= 5) or (C[i, 0] >= 9995)
      return false
    end
  end

  return true
----
====
Custom components

A custom component (not among the defined components allowed) can be encoded using the class attribute, to specify the particular kind of component. If no such attribute is given, the default value is the undifferentiated component (component) [added in https://github.com/metanorma/metanorma-standoc/releases/tag/v1.10.4].

Example 10. Example with an MRR instance containing a custom component
[requirement]
====

[component,class=conditions]
--
The following conditions need to be fulfilled in this requirement...
--
====

Machine-readable components

General

Any component may include or consist of machine-readable code.

Components can be specified with a "type" if they are intended to be machine-readable. The "type" refers to the conventions or computer frameworks that they follow.

They are given by setting the type attribute on the component block:

Example 11. An example of mixed descriptions with a machine-readable ABNF specification
[requirement]
====
[%metadata]
identifier:: requirement A

This is some descriptive text.

[specification,type=ABNF]
--
[source,abnf]
----
status        = ( "draft" / "cancelled" ) / stage
stage         = "stage-" stagecode ["." iteration]
stagecode     = DIGIT DIGIT "."  DIGIT DIGIT
iteration     = "v" DIGITS
----
--

This is some more descriptive text.

====
Source code as specification

Such content is to be provided within a [source] block, which is expected to contain an attribute giving the computer language the block is expressed in.

Note
The notion of "language" may be expanded to include a particular computer framework that the code is to be run under.

It is also possible specify “source code” that is meant to be human readable, by [source,text].

The language of a source code block is likely to be distinct from the type of named block it is contained in.

Example 12. An example of machine-readable code in a specification
[requirement]
====
[%metadata]
identifier:: Requirement A

This is some descriptive text.

[verification,type=heuristic]
--
[source,ruby]
----
instances.each do |i|
  warn "uh-oh" if i > 5
end
----
--

====
Machine-readable content as alternative representation

By default, all components and descriptions will be included in final output.

Often, though not always, components can contain machine-readable code which is not intended to be included in the output, but is supplemental to the human-readable description.

That is signalled through the options attribute exclude on the named block.

Example 13. An example of a recommendation with a component excluded from rendering
[recommendation]
====
[%metadata]
identifier:: /ogc/recommendation/wfs/2
subject:: user

I recommend _this_.

[specification,type="tabular"]
--
This is the object of the recommendation:
|===
|Object |Value
|Mission | Accomplished
|===
--

As for the measurement targets,
[measurement-target]
--
The measurement target shall be measured as:
[stem]
++++
r/1 = 0
++++
--

[verification,type="comprehensive"]
--
The following code will be run for verification:

[source,CoreRoot]
----
CoreRoot(success): HttpResponse
if (success)
  recommendation(label: success-response)
end
----
--

[import%exclude]
--
[source,CoreRoot]
----
success-response()
----
--
====

Nested requirements

Nested requirements can be encoded with a combination of internal blocks.

MRR requirements can be nested by adding one or more delimiter symbols than its containing block.

Example 14. Example of nested permissions
[permission]
====

The permission statement surrounded by 4 delimiter symbols.

[example]
=====
An example within the permission surrounded by 5 delimiter symbols.
=====

[permission]
=====
A sub-permission surrounded by 5 delimiter symbols.
=====

[requirement]
=====
A requirement if the permission is adopted.
=====

====
Note
Nested requirements are marked up just like nested examples.
Example 15. An example of nested requirements with identifiers and components
[requirement]
====
[%metadata]
identifier:: requirement A

[requirement]
=====
[%metadata]
identifier:: requirement A1

[specification]
--
This is a formal specification.
--

=====

[requirement]
=====
[%metadata]
identifier:: requirement A2

[measurement-target]
--
This is a measurement target.
--

=====

====